@timber-js/app 0.2.0-alpha.208 → 0.2.0-alpha.209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{primitives-DLAnvsrk.js → actions-BerlqoXA.js} +640 -410
- package/dist/_chunks/actions-BerlqoXA.js.map +1 -0
- package/dist/_chunks/{als-registry-C6kcfprT.js → als-registry-DaxkVjt5.js} +6 -2
- package/dist/_chunks/als-registry-DaxkVjt5.js.map +1 -0
- package/dist/_chunks/{build-manifest-DTmSGLRz.js → build-manifest-DWppEdLB.js} +2 -51
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/{build-output-helper-9dqCv1pZ.js → build-output-helper-RV_BRcF1.js} +50 -53
- package/dist/_chunks/build-output-helper-RV_BRcF1.js.map +1 -0
- package/dist/_chunks/{cache-api-CUD9Ezaq.js → cache-api-CR23J_NC.js} +64 -32
- package/dist/_chunks/cache-api-CR23J_NC.js.map +1 -0
- package/dist/_chunks/{chains-B4bgOl2g.js → chains-CpFg56UB.js} +2 -2
- package/dist/_chunks/{chains-B4bgOl2g.js.map → chains-CpFg56UB.js.map} +1 -1
- package/dist/_chunks/{cli-check-G8o30ldg.js → cli-check-C6Ev6wBO.js} +11 -52
- package/dist/_chunks/cli-check-C6Ev6wBO.js.map +1 -0
- package/dist/_chunks/cli-context-By7k2xVo.js +70 -0
- package/dist/_chunks/cli-context-By7k2xVo.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js → cli-schema-sync-CbT2AUUI.js} +3 -3
- package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js.map → cli-schema-sync-CbT2AUUI.js.map} +1 -1
- package/dist/_chunks/{cloudflare-BFb__LYG.js → cloudflare-Byxl8FWP.js} +96 -53
- package/dist/_chunks/{cloudflare-BFb__LYG.js.map → cloudflare-Byxl8FWP.js.map} +1 -1
- package/dist/_chunks/{convention-lint-5KzoMg_A.js → convention-lint-jKTwKwPe.js} +21 -6
- package/dist/_chunks/convention-lint-jKTwKwPe.js.map +1 -0
- package/dist/_chunks/{dev-server-BzBxgYAV.js → dev-server-C4WZdB7L.js} +15 -167
- package/dist/_chunks/dev-server-C4WZdB7L.js.map +1 -0
- package/dist/_chunks/{error-boundary-BrHmG-2X.js → error-boundary-tA7kVfs4.js} +84 -104
- package/dist/_chunks/error-boundary-tA7kVfs4.js.map +1 -0
- package/dist/_chunks/{fs-identity-D7vb6GdI.js → fs-identity-BRKuL215.js} +3 -4
- package/dist/_chunks/fs-identity-BRKuL215.js.map +1 -0
- package/dist/_chunks/{graph-cache-CP4GEmf9.js → graph-cache-CYiUS2aS.js} +4 -5
- package/dist/_chunks/graph-cache-CYiUS2aS.js.map +1 -0
- package/dist/_chunks/{json-lossy-check-ClNvBM_3.js → json-lossy-check-ip0Qi0MT.js} +6 -3
- package/dist/_chunks/json-lossy-check-ip0Qi0MT.js.map +1 -0
- package/dist/_chunks/{live-graph-Bm5WTvcr.js → live-graph-Dv-JJCZw.js} +3 -3
- package/dist/_chunks/{live-graph-Bm5WTvcr.js.map → live-graph-Dv-JJCZw.js.map} +1 -1
- package/dist/_chunks/{logger-k2DQ4EUf.js → logger-DiDt5ppH.js} +192 -51
- package/dist/_chunks/logger-DiDt5ppH.js.map +1 -0
- package/dist/_chunks/{navigation-root-mHSK9psY.js → navigation-root-BQfo1-kG.js} +2 -2
- package/dist/_chunks/{navigation-root-mHSK9psY.js.map → navigation-root-BQfo1-kG.js.map} +1 -1
- package/dist/_chunks/{plugin-context-8idfR3UZ.js → plugin-context-BPBPc3lL.js} +28 -4
- package/dist/_chunks/plugin-context-BPBPc3lL.js.map +1 -0
- package/dist/_chunks/{poison-scan-DG5eI2_z.js → poison-scan-CpeT6_OJ.js} +2 -2
- package/dist/_chunks/{poison-scan-DG5eI2_z.js.map → poison-scan-CpeT6_OJ.js.map} +1 -1
- package/dist/_chunks/render-timeout-DOf_BBcO.js +46 -0
- package/dist/_chunks/render-timeout-DOf_BBcO.js.map +1 -0
- package/dist/_chunks/{rsc-payload-path-B_LBodc2.js → rsc-payload-path-dffcs4jp.js} +9 -3
- package/dist/_chunks/{rsc-payload-path-B_LBodc2.js.map → rsc-payload-path-dffcs4jp.js.map} +1 -1
- package/dist/_chunks/{scanner-BQ5sPIJ7.js → scanner-Bw0oq1HB.js} +2 -2
- package/dist/_chunks/{scanner-BQ5sPIJ7.js.map → scanner-Bw0oq1HB.js.map} +1 -1
- package/dist/_chunks/{navigation-context-D0TU0Jog.js → segment-context-xtPUGfdq.js} +36 -34
- package/dist/_chunks/segment-context-xtPUGfdq.js.map +1 -0
- package/dist/_chunks/{singleflight-2lUWfcAk.js → singleflight-BeVMMKi0.js} +4 -3
- package/dist/_chunks/{singleflight-2lUWfcAk.js.map → singleflight-BeVMMKi0.js.map} +1 -1
- package/dist/_chunks/{sizeof-lXffQ1Vr.js → sizeof-UwzwB1uM.js} +3 -2
- package/dist/_chunks/sizeof-UwzwB1uM.js.map +1 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js +49 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js.map +1 -0
- package/dist/_chunks/{state-FippDgxN.js → state-BhNGPsdi.js} +6 -8
- package/dist/_chunks/state-BhNGPsdi.js.map +1 -0
- package/dist/_chunks/{status-page-marker-CNbpUOPB.js → status-page-marker-gaihi0KZ.js} +53 -20
- package/dist/_chunks/status-page-marker-gaihi0KZ.js.map +1 -0
- package/dist/_chunks/{walkers-CN2N_bA-.js → walkers-BXExhzzk.js} +2 -2
- package/dist/_chunks/{walkers-CN2N_bA-.js.map → walkers-BXExhzzk.js.map} +1 -1
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js +32 -0
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +7 -7
- package/dist/adapters/build-output-helper.d.ts.map +1 -1
- package/dist/adapters/canonicalize-module.d.ts +8 -0
- package/dist/adapters/canonicalize-module.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +2 -2
- package/dist/adapters/cloudflare.d.ts +30 -8
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -2
- package/dist/adapters/compress-module.d.ts +8 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +2 -3
- package/dist/adapters/fs-identity.d.ts.map +1 -1
- package/dist/adapters/nitro-presets.d.ts +0 -6
- package/dist/adapters/nitro-presets.d.ts.map +1 -1
- package/dist/adapters/nitro-preview.d.ts +43 -11
- package/dist/adapters/nitro-preview.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +1 -13
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +291 -176
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +7 -2
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +105 -21
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js +0 -0
- package/dist/analyze/crawl-entry.js +3 -3
- package/dist/analyze/graph-cache.d.ts.map +1 -1
- package/dist/analyze/graph-command.js +4 -4
- package/dist/cache/index.js +2 -2
- package/dist/cache/json-lossy-check.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts.map +1 -1
- package/dist/cache/stores/memory.js +1 -1
- package/dist/cache/tag-aware-handler.d.ts.map +1 -1
- package/dist/cdn/workers-cache-purge.js +1 -1
- package/dist/cli-check.d.ts +7 -37
- package/dist/cli-check.d.ts.map +1 -1
- package/dist/cli-context.d.ts +54 -0
- package/dist/cli-context.d.ts.map +1 -0
- package/dist/cli.d.ts +9 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -24
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/hydrate.d.ts +19 -29
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
- package/dist/client/browser-entry/index.d.ts +7 -7
- package/dist/client/browser-entry/post-hydration.d.ts +6 -9
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts +6 -11
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +4 -3
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/error-reconstituter.d.ts +3 -9
- package/dist/client/error-reconstituter.d.ts.map +1 -1
- package/dist/client/history.d.ts +12 -11
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +5 -6
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +3 -3
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +68 -104
- package/dist/client/internal.js.map +1 -1
- package/dist/client/navigation-commit.d.ts +16 -7
- package/dist/client/navigation-commit.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +3 -5
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/react-root.d.ts +3 -2
- package/dist/client/react-root.d.ts.map +1 -1
- package/dist/client/router-pipeline.d.ts +1 -6
- package/dist/client/router-pipeline.d.ts.map +1 -1
- package/dist/client/router-types.d.ts +45 -39
- package/dist/client/router-types.d.ts.map +1 -1
- package/dist/client/router-url.d.ts +24 -0
- package/dist/client/router-url.d.ts.map +1 -0
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +8 -4
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/ssr-data.d.ts +18 -64
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/state.d.ts +2 -5
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts +1 -1
- package/dist/config-types.d.ts +2 -1
- package/dist/config-types.d.ts.map +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/dev-tools/dev-page-shell.d.ts +17 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
- package/dist/dev-tools/index.d.ts +1 -1
- package/dist/dev-tools/index.d.ts.map +1 -1
- package/dist/dev-tools/instrumentation.d.ts +17 -2
- package/dist/dev-tools/instrumentation.d.ts.map +1 -1
- package/dist/dev-tools/overlay.d.ts +6 -27
- package/dist/dev-tools/overlay.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +531 -373
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +26 -40
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +15 -2
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +19 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/post-build.d.ts +110 -0
- package/dist/plugins/post-build.d.ts.map +1 -0
- package/dist/plugins/prebuilt-capture.d.ts +11 -4
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -1
- package/dist/plugins/prebuilt.d.ts +17 -1
- package/dist/plugins/prebuilt.d.ts.map +1 -1
- package/dist/plugins/prerender-sugar.d.ts.map +1 -1
- package/dist/plugins/rsc-assets-manifest.d.ts +33 -0
- package/dist/plugins/rsc-assets-manifest.d.ts.map +1 -0
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +32 -9
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-write.d.ts +0 -9
- package/dist/routing/codegen-write.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/routing/segment-codegen.d.ts.map +1 -1
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts +5 -4
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +46 -7
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +58 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/children-interception.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +2 -23
- package/dist/server/cookie-context.d.ts.map +1 -1
- package/dist/server/csp-nonce.d.ts +0 -9
- package/dist/server/csp-nonce.d.ts.map +1 -1
- package/dist/server/csrf.d.ts +27 -4
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/debug.d.ts +0 -1
- package/dist/server/debug.d.ts.map +1 -1
- package/dist/server/default-logger.d.ts +2 -1
- package/dist/server/default-logger.d.ts.map +1 -1
- package/dist/server/deny-boundary.d.ts +12 -6
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +2 -2
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -3
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +9 -2
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/head-response.d.ts +4 -4
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +10 -3
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/internal.d.ts +1 -4
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +961 -581
- package/dist/server/internal.js.map +1 -1
- package/dist/server/json-status-response.d.ts +34 -0
- package/dist/server/json-status-response.d.ts.map +1 -0
- package/dist/server/logger.d.ts +26 -0
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +11 -6
- package/dist/server/param-coercion.d.ts.map +1 -1
- package/dist/server/pipeline-helpers.d.ts +95 -7
- package/dist/server/pipeline-helpers.d.ts.map +1 -1
- package/dist/server/pipeline-interception.d.ts +11 -0
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +11 -1
- package/dist/server/pipeline-outcome.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts +2 -2
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +23 -35
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/prebuilt/capture-render.d.ts +25 -0
- package/dist/server/prebuilt/capture-render.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-routes.d.ts +37 -0
- package/dist/server/prebuilt/capture-routes.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +79 -35
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -1
- package/dist/server/prebuilt/lifetime.d.ts +38 -0
- package/dist/server/prebuilt/lifetime.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +7 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -1
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -1
- package/dist/server/prebuilt-builder.d.ts.map +1 -1
- package/dist/server/prebuilt-runtime.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +6 -81
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/react-cache-bridge.d.ts +59 -0
- package/dist/server/react-cache-bridge.d.ts.map +1 -0
- package/dist/server/react-cache-scope.d.ts +49 -0
- package/dist/server/react-cache-scope.d.ts.map +1 -0
- package/dist/server/render-timeout.d.ts +15 -0
- package/dist/server/render-timeout.d.ts.map +1 -1
- package/dist/server/render-utils.d.ts +9 -0
- package/dist/server/render-utils.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +26 -5
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +7 -0
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +22 -22
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +7 -0
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +32 -6
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +11 -18
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +0 -1
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +5 -15
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +5 -6
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-signals.d.ts +65 -0
- package/dist/server/rsc-entry/render-signals.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +6 -16
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +7 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +8 -53
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +2 -2
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +9 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -1
- package/dist/server/signal-identity.d.ts +43 -0
- package/dist/server/signal-identity.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +4 -3
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/slot-subtree-contain.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +91 -53
- package/dist/server/ssr-bridge-types.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +8 -5
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +26 -40
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +1 -1
- package/dist/server/static-generator.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +12 -0
- package/dist/server/stream-utils.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +12 -16
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -1
- package/dist/server/version-skew.d.ts +3 -3
- package/dist/shared/csrf-reject.d.ts +16 -0
- package/dist/shared/csrf-reject.d.ts.map +1 -0
- package/dist/shared/error-digest.d.ts +28 -0
- package/dist/shared/error-digest.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +11 -10
- package/dist/shared/payload-root.d.ts.map +1 -1
- package/dist/shared/rsc-payload-path.d.ts +6 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -1
- package/dist/utils/write-file-atomic.d.ts +17 -0
- package/dist/utils/write-file-atomic.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +17 -14
- package/docs/api/32-api-cache.mdx +51 -23
- package/docs/api/34-api-config.mdx +34 -6
- package/docs/api/36-cli.mdx +11 -1
- package/docs/learn/03-fetching-data.mdx +17 -1
- package/docs/learn/04-access-control.mdx +1 -1
- package/docs/learn/10-caching.mdx +29 -11
- package/docs/learn/11-middleware.mdx +8 -2
- package/docs/learn/12-error-handling.mdx +6 -1
- package/package.json +5 -1
- package/src/adapters/build-output-helper.ts +55 -53
- package/src/adapters/canonicalize-module.ts +29 -0
- package/src/adapters/cloudflare.ts +105 -63
- package/src/adapters/compress-module.ts +16 -5
- package/src/adapters/fs-identity.ts +2 -3
- package/src/adapters/nitro-presets.ts +0 -15
- package/src/adapters/nitro-preview.ts +272 -136
- package/src/adapters/nitro.ts +119 -82
- package/src/adapters/shared.ts +23 -14
- package/src/adapters/types.ts +110 -21
- package/src/analyze/graph-cache.ts +3 -4
- package/src/cache/json-lossy-check.ts +3 -9
- package/src/cache/singleflight.ts +5 -2
- package/src/cache/sizeof.ts +3 -1
- package/src/cache/tag-aware-handler.ts +43 -26
- package/src/cli-check.ts +8 -98
- package/src/cli-context.ts +119 -0
- package/src/cli.ts +19 -28
- package/src/client/browser-dev.ts +1 -1
- package/src/client/browser-entry/action-dispatch.ts +26 -4
- package/src/client/browser-entry/hydrate.ts +53 -58
- package/src/client/browser-entry/index.ts +16 -27
- package/src/client/browser-entry/post-hydration.ts +6 -40
- package/src/client/browser-entry/router-init.ts +66 -84
- package/src/client/error-boundary.tsx +9 -41
- package/src/client/error-reconstituter.tsx +10 -5
- package/src/client/history.ts +18 -21
- package/src/client/index.ts +0 -1
- package/src/client/internal.ts +2 -7
- package/src/client/navigation-commit.ts +35 -18
- package/src/client/navigation-context.ts +3 -39
- package/src/client/react-root.ts +3 -2
- package/src/client/router-pipeline.ts +65 -128
- package/src/client/router-types.ts +46 -44
- package/src/client/router-url.ts +32 -0
- package/src/client/router.ts +43 -22
- package/src/client/rsc-fetch.ts +117 -155
- package/src/client/ssr-data.ts +19 -80
- package/src/client/state.ts +2 -9
- package/src/client/use-pathname.ts +1 -1
- package/src/config-types.ts +2 -1
- package/src/config-validation.ts +2 -1
- package/src/dev-tools/dev-page-shell.ts +18 -0
- package/src/dev-tools/index.ts +0 -2
- package/src/dev-tools/instrumentation.ts +50 -2
- package/src/dev-tools/overlay.ts +8 -238
- package/src/index.ts +24 -14
- package/src/plugin-context.ts +39 -40
- package/src/plugins/build-manifest.ts +4 -11
- package/src/plugins/build-report.ts +70 -70
- package/src/plugins/dev-server.ts +24 -44
- package/src/plugins/entries.ts +2 -1
- package/src/plugins/fonts.ts +35 -7
- package/src/plugins/post-build.ts +327 -0
- package/src/plugins/prebuilt-capture.ts +28 -32
- package/src/plugins/prebuilt.ts +54 -39
- package/src/plugins/prerender-sugar.ts +0 -4
- package/src/plugins/{adapter-build.ts → rsc-assets-manifest.ts} +20 -109
- package/src/plugins/shims.ts +1 -0
- package/src/plugins/static-build.ts +42 -74
- package/src/routing/codegen-write.ts +25 -3
- package/src/routing/segment-codegen.ts +3 -2
- package/src/rsc-runtime/vendor-types.d.ts +8 -0
- package/src/server/access-gate.tsx +2 -1
- package/src/server/action-client.ts +1 -1
- package/src/server/action-handler.ts +253 -110
- package/src/server/actions.ts +73 -25
- package/src/server/als-registry.ts +73 -5
- package/src/server/chain-url-parts.ts +1 -1
- package/src/server/children-interception.ts +2 -1
- package/src/server/cookie-context.ts +18 -48
- package/src/server/csp-nonce.ts +0 -12
- package/src/server/csrf.ts +140 -8
- package/src/server/debug.ts +0 -1
- package/src/server/default-logger.ts +2 -1
- package/src/server/deny-boundary.ts +25 -13
- package/src/server/deny-renderer.ts +30 -97
- package/src/server/error-boundary-wrapper.ts +7 -3
- package/src/server/fallback-error.ts +26 -11
- package/src/server/flight-scripts.ts +1 -1
- package/src/server/head-response.ts +4 -4
- package/src/server/html-injector-core.ts +2 -2
- package/src/server/html-injectors.ts +2 -4
- package/src/server/index.ts +0 -4
- package/src/server/instrumentation.ts +10 -3
- package/src/server/internal.ts +1 -6
- package/src/server/json-status-response.ts +105 -0
- package/src/server/logger.ts +39 -3
- package/src/server/param-coercion.ts +15 -12
- package/src/server/pipeline-helpers.ts +257 -12
- package/src/server/pipeline-interception.ts +133 -0
- package/src/server/pipeline-outcome.ts +103 -31
- package/src/server/pipeline-phases.ts +127 -237
- package/src/server/pipeline.ts +204 -207
- package/src/server/prebuilt/capture-render.ts +118 -0
- package/src/server/prebuilt/capture-routes.ts +104 -0
- package/src/server/prebuilt/capture-state.ts +155 -48
- package/src/server/prebuilt/lifetime.ts +151 -0
- package/src/server/prebuilt/slots.ts +14 -2
- package/src/server/prebuilt/synthetic-store.ts +3 -0
- package/src/server/prebuilt-builder.ts +30 -320
- package/src/server/prebuilt-runtime.ts +125 -129
- package/src/server/primitives.ts +8 -168
- package/src/server/react-cache-bridge.ts +124 -0
- package/src/server/react-cache-scope.ts +104 -0
- package/src/server/render-timeout.ts +20 -0
- package/src/server/render-utils.ts +11 -1
- package/src/server/request-context.ts +36 -9
- package/src/server/route-element-builder.ts +11 -6
- package/src/server/route-handler.ts +36 -23
- package/src/server/route-matcher.ts +15 -1
- package/src/server/rsc-entry/action-middleware-runner.ts +79 -123
- package/src/server/rsc-entry/api-handler.ts +27 -103
- package/src/server/rsc-entry/deny-fallback.ts +93 -26
- package/src/server/rsc-entry/error-renderer.ts +39 -91
- package/src/server/rsc-entry/helpers.ts +2 -4
- package/src/server/rsc-entry/index.ts +64 -58
- package/src/server/rsc-entry/render-route.ts +15 -80
- package/src/server/rsc-entry/render-signals.ts +108 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +56 -57
- package/src/server/rsc-entry/rsc-payload.ts +28 -61
- package/src/server/rsc-entry/rsc-stream.ts +113 -213
- package/src/server/rsc-entry/ssr-bridge.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +182 -263
- package/src/server/rsc-entry/wrap-action-dispatch.ts +12 -14
- package/src/server/signal-identity.ts +112 -0
- package/src/server/slot-resolver.ts +18 -18
- package/src/server/slot-subtree-contain.ts +2 -1
- package/src/server/ssr-bridge-types.ts +92 -56
- package/src/server/ssr-entry.ts +87 -111
- package/src/server/ssr-render.ts +55 -64
- package/src/server/ssr-wrappers.tsx +2 -2
- package/src/server/static-generator.ts +7 -42
- package/src/server/static-not-found.ts +3 -3
- package/src/server/stream-utils.ts +51 -0
- package/src/server/tracing.ts +58 -75
- package/src/server/types.ts +1 -1
- package/src/server/version-skew.ts +5 -5
- package/src/shared/csrf-reject.ts +15 -0
- package/src/shared/error-digest.ts +46 -0
- package/src/shared/payload-root.ts +11 -10
- package/src/shared/rsc-payload-path.ts +8 -1
- package/src/utils/write-file-atomic.ts +32 -0
- package/dist/_chunks/actions-jNrXdzgs.js +0 -346
- package/dist/_chunks/actions-jNrXdzgs.js.map +0 -1
- package/dist/_chunks/als-registry-C6kcfprT.js.map +0 -1
- package/dist/_chunks/build-manifest-DTmSGLRz.js.map +0 -1
- package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +0 -1
- package/dist/_chunks/cache-api-CUD9Ezaq.js.map +0 -1
- package/dist/_chunks/cli-check-G8o30ldg.js.map +0 -1
- package/dist/_chunks/convention-lint-5KzoMg_A.js.map +0 -1
- package/dist/_chunks/dev-server-BzBxgYAV.js.map +0 -1
- package/dist/_chunks/error-boundary-BrHmG-2X.js.map +0 -1
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +0 -1
- package/dist/_chunks/graph-cache-CP4GEmf9.js.map +0 -1
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +0 -1
- package/dist/_chunks/logger-k2DQ4EUf.js.map +0 -1
- package/dist/_chunks/navigation-context-D0TU0Jog.js.map +0 -1
- package/dist/_chunks/plugin-context-8idfR3UZ.js.map +0 -1
- package/dist/_chunks/primitives-DLAnvsrk.js.map +0 -1
- package/dist/_chunks/segment-context-D9_89u34.js +0 -34
- package/dist/_chunks/segment-context-D9_89u34.js.map +0 -1
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +0 -1
- package/dist/_chunks/ssr-data-D6T6Y3ef.js +0 -60
- package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +0 -1
- package/dist/_chunks/state-FippDgxN.js.map +0 -1
- package/dist/_chunks/status-page-marker-CNbpUOPB.js.map +0 -1
- package/dist/client/types.d.ts +0 -14
- package/dist/client/types.d.ts.map +0 -1
- package/dist/plugins/adapter-build.d.ts +0 -38
- package/dist/plugins/adapter-build.d.ts.map +0 -1
- package/dist/server/asset-headers.d.ts +0 -32
- package/dist/server/asset-headers.d.ts.map +0 -1
- package/dist/server/dev-source-map.d.ts +0 -22
- package/dist/server/dev-source-map.d.ts.map +0 -1
- package/src/client/types.ts +0 -21
- package/src/server/asset-headers.ts +0 -59
- package/src/server/dev-source-map.ts +0 -31
|
@@ -26,7 +26,19 @@ const DATA_PREFIX = 'd:';
|
|
|
26
26
|
const TAG_SET_PREFIX = 'ts:';
|
|
27
27
|
const TAG_VERSION_PREFIX = 'tv:';
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/** A store whose optional capability methods are known to be present. */
|
|
30
|
+
type StoreWith<K extends keyof CacheStore> = CacheStore & Required<Pick<CacheStore, K>>;
|
|
31
|
+
type NativeStore = StoreWith<'setWithTags' | 'invalidateTag'>;
|
|
32
|
+
type EagerStore = StoreWith<'sadd' | 'smembers' | 'srem' | 'sdel'>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The detected strategy carries the store narrowed to the capabilities that
|
|
36
|
+
* strategy relies on, so each branch calls those methods without assertions.
|
|
37
|
+
*/
|
|
38
|
+
type Strategy =
|
|
39
|
+
| { kind: 'native'; store: NativeStore }
|
|
40
|
+
| { kind: 'eager'; store: EagerStore }
|
|
41
|
+
| { kind: 'lazy' };
|
|
30
42
|
|
|
31
43
|
/** Stored entry format for eager strategy. */
|
|
32
44
|
interface EagerEntry {
|
|
@@ -43,10 +55,18 @@ interface LazyEntry {
|
|
|
43
55
|
tagVersions: Record<string, number>;
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
function isNativeStore(store: CacheStore): store is NativeStore {
|
|
59
|
+
return !!(store.setWithTags && store.invalidateTag);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isEagerStore(store: CacheStore): store is EagerStore {
|
|
63
|
+
return !!(store.sadd && store.smembers && store.srem && store.sdel);
|
|
64
|
+
}
|
|
65
|
+
|
|
46
66
|
function detectStrategy(store: CacheStore): Strategy {
|
|
47
|
-
if (store
|
|
48
|
-
if (store
|
|
49
|
-
return 'lazy';
|
|
67
|
+
if (isNativeStore(store)) return { kind: 'native', store };
|
|
68
|
+
if (isEagerStore(store)) return { kind: 'eager', store };
|
|
69
|
+
return { kind: 'lazy' };
|
|
50
70
|
}
|
|
51
71
|
|
|
52
72
|
export class TagAwareCacheHandler implements CacheHandler {
|
|
@@ -85,7 +105,7 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
85
105
|
const raw = await this.store.get(this.dataKey(key));
|
|
86
106
|
if (raw === null) return null;
|
|
87
107
|
|
|
88
|
-
if (this.strategy
|
|
108
|
+
if (this.strategy.kind !== 'lazy') {
|
|
89
109
|
const entry = JSON.parse(raw) as EagerEntry;
|
|
90
110
|
const stale = Date.now() > entry.expiresAt;
|
|
91
111
|
return { value: entry.value, stale };
|
|
@@ -111,8 +131,9 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
111
131
|
opts: { ttl: number; tags: string[]; generation?: number }
|
|
112
132
|
): Promise<void> {
|
|
113
133
|
const physicalTtl = Math.max(opts.ttl * 2 + 60, 120);
|
|
134
|
+
const strategy = this.strategy;
|
|
114
135
|
|
|
115
|
-
if (
|
|
136
|
+
if (strategy.kind === 'native') {
|
|
116
137
|
const entry: EagerEntry = {
|
|
117
138
|
value,
|
|
118
139
|
expiresAt: Date.now() + opts.ttl * 1000,
|
|
@@ -120,7 +141,7 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
120
141
|
};
|
|
121
142
|
const payload = JSON.stringify(entry);
|
|
122
143
|
if (opts.tags.length > 0) {
|
|
123
|
-
await
|
|
144
|
+
await strategy.store.setWithTags(
|
|
124
145
|
this.dataKey(key),
|
|
125
146
|
payload,
|
|
126
147
|
physicalTtl,
|
|
@@ -132,7 +153,7 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
132
153
|
return;
|
|
133
154
|
}
|
|
134
155
|
|
|
135
|
-
if (
|
|
156
|
+
if (strategy.kind === 'eager') {
|
|
136
157
|
const entry: EagerEntry = {
|
|
137
158
|
value,
|
|
138
159
|
expiresAt: Date.now() + opts.ttl * 1000,
|
|
@@ -141,7 +162,7 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
141
162
|
await this.store.set(this.dataKey(key), JSON.stringify(entry), physicalTtl);
|
|
142
163
|
if (opts.tags.length > 0) {
|
|
143
164
|
await Promise.all(
|
|
144
|
-
opts.tags.map((tag) =>
|
|
165
|
+
opts.tags.map((tag) => strategy.store.sadd(this.tagSetKey(tag), [key], physicalTtl))
|
|
145
166
|
);
|
|
146
167
|
}
|
|
147
168
|
return;
|
|
@@ -159,27 +180,30 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
159
180
|
}
|
|
160
181
|
|
|
161
182
|
async invalidate(opts: { key?: string; tag?: string }): Promise<void> {
|
|
183
|
+
const strategy = this.strategy;
|
|
184
|
+
|
|
162
185
|
if (opts.key) {
|
|
163
|
-
|
|
164
|
-
|
|
186
|
+
const key = opts.key;
|
|
187
|
+
if (strategy.kind === 'eager') {
|
|
188
|
+
const raw = await this.store.get(this.dataKey(key));
|
|
165
189
|
if (raw !== null) {
|
|
166
190
|
const entry = JSON.parse(raw) as EagerEntry;
|
|
167
191
|
if (entry.tags.length > 0) {
|
|
168
192
|
await Promise.all(
|
|
169
|
-
entry.tags.map((tag) =>
|
|
193
|
+
entry.tags.map((tag) => strategy.store.srem(this.tagSetKey(tag), [key]))
|
|
170
194
|
);
|
|
171
195
|
}
|
|
172
196
|
}
|
|
173
197
|
}
|
|
174
|
-
await this.store.del(this.dataKey(
|
|
198
|
+
await this.store.del(this.dataKey(key));
|
|
175
199
|
}
|
|
176
200
|
|
|
177
201
|
if (opts.tag) {
|
|
178
202
|
const tag = opts.tag;
|
|
179
|
-
if (
|
|
180
|
-
await
|
|
181
|
-
} else if (
|
|
182
|
-
const members = await
|
|
203
|
+
if (strategy.kind === 'native') {
|
|
204
|
+
await strategy.store.invalidateTag(`${this.prefix}${tag}`);
|
|
205
|
+
} else if (strategy.kind === 'eager') {
|
|
206
|
+
const members = await strategy.store.smembers(this.tagSetKey(tag));
|
|
183
207
|
// Verify each member still carries the tag before deleting — the set
|
|
184
208
|
// can contain stale memberships from overwritten entries or LRU eviction.
|
|
185
209
|
// Remove only the snapshot members (via srem, not sdel) so concurrent
|
|
@@ -187,17 +211,10 @@ export class TagAwareCacheHandler implements CacheHandler {
|
|
|
187
211
|
await Promise.all(
|
|
188
212
|
members.map(async (k) => {
|
|
189
213
|
const raw = await this.store.get(this.dataKey(k));
|
|
190
|
-
if (raw
|
|
191
|
-
await this.store.srem!(this.tagSetKey(tag), [k]);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
const entry = JSON.parse(raw) as EagerEntry;
|
|
195
|
-
if (entry.tags.includes(tag)) {
|
|
214
|
+
if (raw !== null && (JSON.parse(raw) as EagerEntry).tags.includes(tag)) {
|
|
196
215
|
await this.store.del(this.dataKey(k));
|
|
197
|
-
await this.store.srem!(this.tagSetKey(tag), [k]);
|
|
198
|
-
} else {
|
|
199
|
-
await this.store.srem!(this.tagSetKey(tag), [k]);
|
|
200
216
|
}
|
|
217
|
+
await strategy.store.srem(this.tagSetKey(tag), [k]);
|
|
201
218
|
})
|
|
202
219
|
);
|
|
203
220
|
} else {
|
package/src/cli-check.ts
CHANGED
|
@@ -36,10 +36,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
36
36
|
import { scanRoutes } from './routing/scanner.ts';
|
|
37
37
|
import { lintConventions, formatConventionWarnings } from './routing/convention-lint.ts';
|
|
38
38
|
import { writeRouteCodegen, CODEGEN_OUTPUT, ENV_DTS_FILENAME } from './routing/codegen-write.ts';
|
|
39
|
-
import {
|
|
40
|
-
|
|
41
|
-
/** The plugin that publishes timber's resolved context on its Vite `api`. */
|
|
42
|
-
const TIMBER_ROOT_SYNC_PLUGIN = 'timber-root-sync';
|
|
39
|
+
import { resolveTimberContext, type ResolveViteConfig } from './cli-context.ts';
|
|
43
40
|
|
|
44
41
|
/** The npm package that provides tsgo. Named in the missing-tool message. */
|
|
45
42
|
const TSGO_PACKAGE = '@typescript/native-preview';
|
|
@@ -68,23 +65,6 @@ export type RunTsgo = (command: string, args: string[], cwd: string) => Promise<
|
|
|
68
65
|
*/
|
|
69
66
|
export type ReadTsgoConfig = (command: string, args: string[], cwd: string) => Promise<string>;
|
|
70
67
|
|
|
71
|
-
/**
|
|
72
|
-
* Vite's own `resolveConfig`, narrowed to what this module passes and reads.
|
|
73
|
-
*
|
|
74
|
-
* The seam sits at `resolveConfig` rather than at "give me the plugins" so the
|
|
75
|
-
* *arguments* are the thing under test: which config file, which command, and
|
|
76
|
-
* which mode defaults. Those arguments have been wrong three separate times
|
|
77
|
-
* (TIM-1332 rounds 4-6), and a double that answered "here are the plugins"
|
|
78
|
-
* could not see any of it. The double returns what Vite returns — plugins with
|
|
79
|
-
* an opaque `api` — so the lookup and narrowing under test stay the real ones.
|
|
80
|
-
*/
|
|
81
|
-
export type ResolveViteConfig = (
|
|
82
|
-
inlineConfig: { configFile: string | undefined },
|
|
83
|
-
command: 'build',
|
|
84
|
-
defaultMode: string,
|
|
85
|
-
defaultNodeEnv: string
|
|
86
|
-
) => Promise<{ plugins: readonly PluginWithApi[] }>;
|
|
87
|
-
|
|
88
68
|
/** @internal Dependency injection for testing. */
|
|
89
69
|
export interface CheckDeps {
|
|
90
70
|
/**
|
|
@@ -164,89 +144,19 @@ export interface RouteInputs {
|
|
|
164
144
|
pageExtensions: string[] | undefined;
|
|
165
145
|
}
|
|
166
146
|
|
|
167
|
-
/** The subset of a resolved Vite plugin this module reads. */
|
|
168
|
-
export interface PluginWithApi {
|
|
169
|
-
name: string;
|
|
170
|
-
api?: unknown;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
147
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* `
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*/
|
|
181
|
-
const defaultResolveViteConfig: ResolveViteConfig = async (
|
|
182
|
-
inlineConfig,
|
|
183
|
-
command,
|
|
184
|
-
defaultMode,
|
|
185
|
-
defaultNodeEnv
|
|
186
|
-
) => {
|
|
187
|
-
const { resolveConfig } = await import('vite');
|
|
188
|
-
return resolveConfig(inlineConfig, command, defaultMode, defaultNodeEnv);
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* The mode defaults `timber build` resolves under.
|
|
193
|
-
*
|
|
194
|
-
* `resolveConfig`'s own defaults are `'development'` for both, but nothing
|
|
195
|
-
* reaches it with those on a build: `createBuilder` goes through Vite's
|
|
196
|
-
* internal `resolveConfigToBuild`, which calls
|
|
197
|
-
* `resolveConfig(inlineConfig, 'build', 'production', 'production')`. A config
|
|
198
|
-
* written as `defineConfig(({ mode }) => …)`, or one that loads `.env.production`,
|
|
199
|
-
* therefore resolves to a *different* app under the two. Passing the defaults
|
|
200
|
-
* explicitly is what makes "check validates what build builds" true rather than
|
|
201
|
-
* true-by-coincidence for configs that ignore mode (TIM-1332, round 6).
|
|
202
|
-
*/
|
|
203
|
-
const BUILD_MODE_DEFAULTS = ['production', 'production'] as const;
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Resolve root, appDir and pageExtensions the way `timber build` resolves them.
|
|
207
|
-
*
|
|
208
|
-
* Reading `timber.config.ts` directly is **not** equivalent, which is the whole
|
|
209
|
-
* reason this goes through Vite (TIM-1332, review round 3):
|
|
210
|
-
*
|
|
211
|
-
* - Config passed inline — `timber({ pageExtensions: [...] })` in
|
|
212
|
-
* `vite.config.ts` — lives only in the plugin's closure. Nothing that
|
|
213
|
-
* re-reads the config file can see it, so a scan built that way silently uses
|
|
214
|
-
* default page extensions and writes a route map missing the app's pages.
|
|
215
|
-
* `examples/next-playground-migration` is exactly this shape.
|
|
216
|
-
* - `root` is Vite's resolved root, not the caller's cwd, and the two differ in
|
|
217
|
-
* the monorepo layouts TIM-498 describes. `appDir` resolves against it.
|
|
218
|
-
*
|
|
219
|
-
* There is no fallback to a second, hand-rolled resolution. A project whose
|
|
220
|
-
* Vite config does not produce the timber plugin cannot be built either, so a
|
|
221
|
-
* check that quietly proceeded on a guessed tree would report a verdict about
|
|
222
|
-
* an app that does not exist.
|
|
148
|
+
* Resolve root, appDir and pageExtensions the way `timber build` resolves them
|
|
149
|
+
* — through Vite, never by re-reading `timber.config.ts` (see `cli-context.ts`).
|
|
150
|
+
* Inline `timber({ pageExtensions: [...] })` is the case that bites: a scan
|
|
151
|
+
* that re-read the file would silently use default page extensions and write a
|
|
152
|
+
* route map missing the app's pages. `examples/next-playground-migration` is
|
|
153
|
+
* exactly this shape.
|
|
223
154
|
*/
|
|
224
155
|
export async function resolveRouteInputs(
|
|
225
156
|
options: RouteOptions = {},
|
|
226
157
|
deps: CheckDeps = {}
|
|
227
158
|
): Promise<RouteInputs> {
|
|
228
|
-
const
|
|
229
|
-
// `configFile: undefined` is Vite's own "discover it" value, so the default
|
|
230
|
-
// path stays exactly what Vite does for `timber build` without `--config`.
|
|
231
|
-
const { plugins } = await resolveViteConfig(
|
|
232
|
-
{ configFile: options.viteConfigFile },
|
|
233
|
-
'build',
|
|
234
|
-
...BUILD_MODE_DEFAULTS
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
const rootSync = plugins.find((plugin) => plugin.name === TIMBER_ROOT_SYNC_PLUGIN);
|
|
238
|
-
if (!rootSync || !isTimberPluginApi(rootSync.api)) {
|
|
239
|
-
throw new Error(
|
|
240
|
-
`[timber] Could not read the resolved timber configuration from your Vite config.\n\n` +
|
|
241
|
-
` \`timber check\` resolves your project through Vite so it validates the same\n` +
|
|
242
|
-
` routes \`timber build\` builds — including config passed inline to timber().\n\n` +
|
|
243
|
-
` Check that vite.config.ts exists and lists the timber plugin:\n\n` +
|
|
244
|
-
` import { timber } from '@timber-js/app';\n` +
|
|
245
|
-
` export default { plugins: [timber()] };\n`
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const ctx = rootSync.api.getContext();
|
|
159
|
+
const ctx = await resolveTimberContext('check', options.viteConfigFile, deps.resolveViteConfig);
|
|
250
160
|
return { root: ctx.root, appDir: ctx.appDir, pageExtensions: ctx.config.pageExtensions };
|
|
251
161
|
}
|
|
252
162
|
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve timber's configuration the way `timber build` resolves it, for CLI
|
|
3
|
+
* commands that run outside the build: `timber check` and `timber preview`.
|
|
4
|
+
*
|
|
5
|
+
* Reading `timber.config.ts` directly is **not** equivalent, which is the whole
|
|
6
|
+
* reason this goes through Vite (TIM-1332, review round 3; TIM-1531):
|
|
7
|
+
*
|
|
8
|
+
* - Config passed inline — `timber({ pageExtensions, adapter, output })` in
|
|
9
|
+
* `vite.config.ts` — lives only in the plugin's closure. Nothing that
|
|
10
|
+
* re-reads the config file can see it.
|
|
11
|
+
* - `root` is Vite's resolved root, not the caller's cwd, and the two differ in
|
|
12
|
+
* the monorepo layouts TIM-498 describes.
|
|
13
|
+
* - The build directory can come from Vite's `build.outDir`, which only a
|
|
14
|
+
* resolved Vite config knows.
|
|
15
|
+
* - `--config` names a Vite config file; only Vite can load it.
|
|
16
|
+
*
|
|
17
|
+
* There is no fallback to a second, hand-rolled resolution. A project whose
|
|
18
|
+
* Vite config does not produce the timber plugin cannot be built either, so a
|
|
19
|
+
* command that quietly proceeded on a guess would act on an app that does not
|
|
20
|
+
* exist.
|
|
21
|
+
*
|
|
22
|
+
* Design docs: 11-platform.md §CLI
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { isTimberPluginApi, type PluginContext } from './plugin-context.ts';
|
|
26
|
+
|
|
27
|
+
/** The plugin that publishes timber's resolved context on its Vite `api`. */
|
|
28
|
+
const TIMBER_ROOT_SYNC_PLUGIN = 'timber-root-sync';
|
|
29
|
+
|
|
30
|
+
/** The subset of a resolved Vite plugin this module reads. */
|
|
31
|
+
export interface PluginWithApi {
|
|
32
|
+
name: string;
|
|
33
|
+
api?: unknown;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Vite's own `resolveConfig`, narrowed to what this module passes and reads.
|
|
38
|
+
*
|
|
39
|
+
* The seam sits at `resolveConfig` rather than at "give me the plugins" so the
|
|
40
|
+
* *arguments* are the thing under test: which config file, which command, and
|
|
41
|
+
* which mode defaults. Those arguments have been wrong three separate times
|
|
42
|
+
* (TIM-1332 rounds 4-6), and a double that answered "here are the plugins"
|
|
43
|
+
* could not see any of it. The double returns what Vite returns — plugins with
|
|
44
|
+
* an opaque `api` — so the lookup and narrowing under test stay the real ones.
|
|
45
|
+
*/
|
|
46
|
+
export type ResolveViteConfig = (
|
|
47
|
+
inlineConfig: { configFile: string | undefined },
|
|
48
|
+
command: 'build',
|
|
49
|
+
defaultMode: string,
|
|
50
|
+
defaultNodeEnv: string
|
|
51
|
+
) => Promise<{ plugins: readonly PluginWithApi[] }>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Ask Vite for the resolved config, which is what carries timber's context.
|
|
55
|
+
*
|
|
56
|
+
* `resolveConfig` runs the whole config pipeline — config file discovery,
|
|
57
|
+
* `config` and `configResolved` hooks — so the context it produces is the one
|
|
58
|
+
* `timber build` would use. Measured at ~300-400ms on a real app.
|
|
59
|
+
*/
|
|
60
|
+
const defaultResolveViteConfig: ResolveViteConfig = async (
|
|
61
|
+
inlineConfig,
|
|
62
|
+
command,
|
|
63
|
+
defaultMode,
|
|
64
|
+
defaultNodeEnv
|
|
65
|
+
) => {
|
|
66
|
+
const { resolveConfig } = await import('vite');
|
|
67
|
+
return resolveConfig(inlineConfig, command, defaultMode, defaultNodeEnv);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The mode defaults `timber build` resolves under.
|
|
72
|
+
*
|
|
73
|
+
* `resolveConfig`'s own defaults are `'development'` for both, but nothing
|
|
74
|
+
* reaches it with those on a build: `createBuilder` goes through Vite's
|
|
75
|
+
* internal `resolveConfigToBuild`, which calls
|
|
76
|
+
* `resolveConfig(inlineConfig, 'build', 'production', 'production')`. A config
|
|
77
|
+
* written as `defineConfig(({ mode }) => …)`, or one that loads `.env.production`,
|
|
78
|
+
* therefore resolves to a *different* app under the two. Passing the defaults
|
|
79
|
+
* explicitly is what makes "check validates what build builds" — and "preview
|
|
80
|
+
* serves what build wrote" — true rather than true-by-coincidence for configs
|
|
81
|
+
* that ignore mode (TIM-1332, round 6).
|
|
82
|
+
*/
|
|
83
|
+
const BUILD_MODE_DEFAULTS = ['production', 'production'] as const;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolve the project through Vite and return timber's context as
|
|
87
|
+
* `timber build` would see it.
|
|
88
|
+
*
|
|
89
|
+
* @param command The CLI command asking, named in the error message.
|
|
90
|
+
* @param viteConfigFile `--config`. Undefined means Vite's own discovery, the
|
|
91
|
+
* same as `timber build` without the flag.
|
|
92
|
+
*/
|
|
93
|
+
export async function resolveTimberContext(
|
|
94
|
+
command: string,
|
|
95
|
+
viteConfigFile: string | undefined,
|
|
96
|
+
resolveViteConfig: ResolveViteConfig = defaultResolveViteConfig
|
|
97
|
+
): Promise<PluginContext> {
|
|
98
|
+
// `configFile: undefined` is Vite's own "discover it" value, so the default
|
|
99
|
+
// path stays exactly what Vite does for `timber build` without `--config`.
|
|
100
|
+
const { plugins } = await resolveViteConfig(
|
|
101
|
+
{ configFile: viteConfigFile },
|
|
102
|
+
'build',
|
|
103
|
+
...BUILD_MODE_DEFAULTS
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const rootSync = plugins.find((plugin) => plugin.name === TIMBER_ROOT_SYNC_PLUGIN);
|
|
107
|
+
if (!rootSync || !isTimberPluginApi(rootSync.api)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`[timber] Could not read the resolved timber configuration from your Vite config.\n\n` +
|
|
110
|
+
` \`timber ${command}\` resolves your project through Vite so it sees the same\n` +
|
|
111
|
+
` configuration \`timber build\` uses — including config passed inline to timber().\n\n` +
|
|
112
|
+
` Check that vite.config.ts exists and lists the timber plugin:\n\n` +
|
|
113
|
+
` import { timber } from '@timber-js/app';\n` +
|
|
114
|
+
` export default { plugins: [timber()] };\n`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return rootSync.api.getContext();
|
|
119
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// Type-only — the implementation is imported dynamically inside runCheck so the
|
|
16
16
|
// CLI's other commands never load the route scanner.
|
|
17
17
|
import type { CheckDeps } from './cli-check.ts';
|
|
18
|
+
import type { ResolveViteConfig } from './cli-context.ts';
|
|
18
19
|
|
|
19
20
|
export type { CheckDeps };
|
|
20
21
|
|
|
@@ -140,6 +141,7 @@ export interface ViteDeps {
|
|
|
140
141
|
createServer?: typeof import('vite').createServer;
|
|
141
142
|
createBuilder?: typeof import('vite').createBuilder;
|
|
142
143
|
preview?: typeof import('vite').preview;
|
|
144
|
+
resolveViteConfig?: ResolveViteConfig;
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
/**
|
|
@@ -227,42 +229,31 @@ export async function runBuild(options: CommandOptions, _deps?: ViteDeps): Promi
|
|
|
227
229
|
await builder.buildApp();
|
|
228
230
|
}
|
|
229
231
|
|
|
230
|
-
/**
|
|
231
|
-
* Determine whether to use the adapter's preview or Vite's built-in preview.
|
|
232
|
-
* Exported for testing — the actual runPreview function uses this internally.
|
|
233
|
-
*/
|
|
234
|
-
export function resolvePreviewStrategy(
|
|
235
|
-
adapter: import('./adapters/types.ts').TimberPlatformAdapter | undefined
|
|
236
|
-
): 'adapter' | 'vite' {
|
|
237
|
-
if (adapter && typeof adapter.preview === 'function') {
|
|
238
|
-
return 'adapter';
|
|
239
|
-
}
|
|
240
|
-
return 'vite';
|
|
241
|
-
}
|
|
242
|
-
|
|
243
232
|
/**
|
|
244
233
|
* Serve the production build for local testing.
|
|
245
234
|
* If the adapter provides a preview() method, it takes priority.
|
|
246
235
|
* Otherwise falls back to Vite's built-in preview server.
|
|
247
236
|
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
* Vite
|
|
237
|
+
* The project is resolved through Vite, as `timber check` resolves it
|
|
238
|
+
* (`cli-context.ts`), so the adapter, the output mode, and the build
|
|
239
|
+
* directory are the ones `timber build` used — including `--config`, inline
|
|
240
|
+
* `timber({ ... })` options, Vite's `root`, and `build.outDir`, none of which
|
|
241
|
+
* a re-read of `timber.config.ts` can see (TIM-1531). A config file that
|
|
242
|
+
* exists but fails to load throws (naming the file) instead of silently
|
|
243
|
+
* degrading to plain Vite preview (TIM-1066).
|
|
252
244
|
*/
|
|
253
245
|
export async function runPreview(options: CommandOptions, _deps?: ViteDeps): Promise<void> {
|
|
254
|
-
const {
|
|
246
|
+
const { resolveTimberContext } = await import('./cli-context.ts');
|
|
247
|
+
const { adapterConfig, contextAdapter } = await import('./plugin-context.ts');
|
|
255
248
|
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const timberConfig = { output: (config?.output ?? 'server') as 'server' | 'static' };
|
|
265
|
-
await adapter!.preview!(timberConfig, buildDir);
|
|
249
|
+
const ctx = await resolveTimberContext('preview', options.config, _deps?.resolveViteConfig);
|
|
250
|
+
const adapter = contextAdapter(ctx);
|
|
251
|
+
|
|
252
|
+
if (typeof adapter?.preview === 'function') {
|
|
253
|
+
await adapter.preview(adapterConfig(ctx), {
|
|
254
|
+
output: ctx.config.output ?? 'server',
|
|
255
|
+
outputDir: ctx.buildDir,
|
|
256
|
+
});
|
|
266
257
|
return;
|
|
267
258
|
}
|
|
268
259
|
|
|
@@ -312,7 +312,7 @@ export function setupClientErrorForwarding(hot: HotInterface): void {
|
|
|
312
312
|
* they are expected during navigation and are handled by the error boundary
|
|
313
313
|
* and router. Exported for tests.
|
|
314
314
|
*
|
|
315
|
-
* See also: isControlFlowSignal() in server/
|
|
315
|
+
* See also: isControlFlowSignal() in server/signal-identity.ts (server-side,
|
|
316
316
|
* handles both instanceof and digest detection).
|
|
317
317
|
*/
|
|
318
318
|
export function isFrameworkSignalError(error: unknown): boolean {
|
|
@@ -22,11 +22,12 @@ import { setHardNavigating } from '../navigation-root.tsx';
|
|
|
22
22
|
import { getClientDeploymentId, DEPLOYMENT_ID_HEADER, RELOAD_HEADER } from '../rsc-fetch.ts';
|
|
23
23
|
import { markClientStale } from '../stale-client.ts';
|
|
24
24
|
import { RSC_CONTENT_TYPE } from '../../shared/rsc-media-type.ts';
|
|
25
|
+
import { CSRF_REJECT_HEADER, CSRF_REJECT_VALUE } from '../../shared/csrf-reject.ts';
|
|
25
26
|
import { createActionQueue } from './action-queue.ts';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Wait for a navigation or refresh to both settle (promise resolved) AND
|
|
29
|
-
* commit (pushState /
|
|
30
|
+
* commit (pushState / the navigation's commit thunk ran). The queue must
|
|
30
31
|
* not release the next action until the URL is correct in the address bar
|
|
31
32
|
* — same rule `<Link>` uses for `isPending` (design/19 §Per-Link Pending
|
|
32
33
|
* State). `onCommit` fires exactly once: on commit, supersession, or
|
|
@@ -93,6 +94,13 @@ export function setupServerActions(): void {
|
|
|
93
94
|
markClientStale();
|
|
94
95
|
throw new Error('Version skew detected — this client is out of date');
|
|
95
96
|
}
|
|
97
|
+
// A CSRF 403 has a plain-text body; handing it to createFromFetch
|
|
98
|
+
// would surface as an opaque Flight decode error (TIM-1459).
|
|
99
|
+
if (res.headers.get(CSRF_REJECT_HEADER) === CSRF_REJECT_VALUE) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
'Server action rejected: CSRF origin check failed (403). ' + 'The server log says why.'
|
|
102
|
+
);
|
|
103
|
+
}
|
|
96
104
|
hasRevalidation = res.headers.get('X-Timber-Revalidation') === '1';
|
|
97
105
|
hasRedirect = res.headers.get('X-Timber-Redirect') != null;
|
|
98
106
|
reval.paths = res.headers.get('X-Timber-Revalidation-Path');
|
|
@@ -170,7 +178,8 @@ export function setupServerActions(): void {
|
|
|
170
178
|
.then(
|
|
171
179
|
(applied) => {
|
|
172
180
|
if (!applied) {
|
|
173
|
-
|
|
181
|
+
// Synchronous eviction already ran at line 121 — only
|
|
182
|
+
// the refresh flag needs deferral (TIM-1518).
|
|
174
183
|
queue.markNeedsRefresh();
|
|
175
184
|
}
|
|
176
185
|
},
|
|
@@ -184,8 +193,17 @@ export function setupServerActions(): void {
|
|
|
184
193
|
}
|
|
185
194
|
|
|
186
195
|
// revalidatePath was called but only for non-current paths —
|
|
187
|
-
// caches were already invalidated above, no refresh needed
|
|
196
|
+
// caches were already invalidated above, so no refresh is needed
|
|
197
|
+
// unless a navigation ran while this action was in flight. That
|
|
198
|
+
// navigation may have consumed a pre-mutation prefetch before the
|
|
199
|
+
// eviction above, or fetched before the mutation landed, and it is
|
|
200
|
+
// now on screen. The other branches catch this through
|
|
201
|
+
// applyActionResult's epoch check; this one must check itself
|
|
202
|
+
// (TIM-1483).
|
|
188
203
|
if (reval.paths) {
|
|
204
|
+
if (router && epoch && !router.isEpochCurrent(epoch)) {
|
|
205
|
+
queue.markNeedsRefresh();
|
|
206
|
+
}
|
|
189
207
|
return decoded;
|
|
190
208
|
}
|
|
191
209
|
|
|
@@ -194,11 +212,15 @@ export function setupServerActions(): void {
|
|
|
194
212
|
// the queue until the refresh commits so the next action captures a
|
|
195
213
|
// current epoch (codex on #1125).
|
|
196
214
|
if (router && epoch) {
|
|
215
|
+
// TIM-1518: Evict synchronously so a navigation that supersedes
|
|
216
|
+
// this action's refresh cannot consume a pre-mutation prefetch.
|
|
217
|
+
// The deferred eviction in .then() ran as a microtask — after the
|
|
218
|
+
// superseding navigation had already consumed a stale entry.
|
|
219
|
+
router.evictStaleCaches();
|
|
197
220
|
hold(
|
|
198
221
|
router.applyActionResult(epoch).then(
|
|
199
222
|
(applied) => {
|
|
200
223
|
if (!applied) {
|
|
201
|
-
router.evictStaleCaches();
|
|
202
224
|
queue.markNeedsRefresh();
|
|
203
225
|
}
|
|
204
226
|
},
|