@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
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Candidate routes for the post-build capture pass
|
|
3
|
+
* (server/prebuilt-builder.ts, design/44-render-at-build-time.md §Build
|
|
4
|
+
* Phase): which pages carry prebuilt components, and which param combos
|
|
5
|
+
* to capture them for.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { CoercedParams } from '../../shared/param-value.ts';
|
|
9
|
+
import type { ManifestFile, ManifestSegmentNode } from '../route-matcher.ts';
|
|
10
|
+
import { hasDynamicSegments } from '../sitemap-generator.ts';
|
|
11
|
+
|
|
12
|
+
// ─── Route collection ─────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
export interface CandidateRoute {
|
|
15
|
+
urlPath: string;
|
|
16
|
+
page: ManifestFile;
|
|
17
|
+
/** Layout files along the chain that declare prebuilt components. */
|
|
18
|
+
layoutsToLoad: ManifestFile[];
|
|
19
|
+
/** Component IDs attributed to this route's page + layout chain. */
|
|
20
|
+
componentIds: string[];
|
|
21
|
+
/** Component IDs from layout files (receive SlotOutlet as children). */
|
|
22
|
+
layoutComponentIds: Set<string>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Walk the manifest tree and collect pages whose file chain (page +
|
|
27
|
+
* layouts above it) has prebuilt components attributed to it. Slots and
|
|
28
|
+
* intercepting/private segments are not walked — slot-scoped prebuilt is
|
|
29
|
+
* already unkeyable at request time when slot params diverge (see
|
|
30
|
+
* resolveKeyParams in prebuilt-runtime.ts), so the build doesn't model
|
|
31
|
+
* slots either.
|
|
32
|
+
*/
|
|
33
|
+
export function collectCandidateRoutes(
|
|
34
|
+
root: ManifestSegmentNode,
|
|
35
|
+
fileComponentMap: Record<string, string[]>
|
|
36
|
+
): CandidateRoute[] {
|
|
37
|
+
const routes: CandidateRoute[] = [];
|
|
38
|
+
|
|
39
|
+
const walk = (node: ManifestSegmentNode, layoutChain: ManifestFile[]) => {
|
|
40
|
+
if (node.segmentType === 'intercepting' || node.segmentType === 'private') return;
|
|
41
|
+
const chain = node.layout ? [...layoutChain, node.layout] : layoutChain;
|
|
42
|
+
|
|
43
|
+
if (node.page) {
|
|
44
|
+
const componentIds = new Set<string>();
|
|
45
|
+
const layoutIds = new Set<string>();
|
|
46
|
+
for (const f of chain)
|
|
47
|
+
for (const id of fileComponentMap[f.filePath] ?? []) {
|
|
48
|
+
componentIds.add(id);
|
|
49
|
+
layoutIds.add(id);
|
|
50
|
+
}
|
|
51
|
+
for (const id of fileComponentMap[node.page.filePath] ?? []) componentIds.add(id);
|
|
52
|
+
if (componentIds.size > 0) {
|
|
53
|
+
routes.push({
|
|
54
|
+
urlPath: node.urlPath,
|
|
55
|
+
page: node.page,
|
|
56
|
+
layoutsToLoad: chain.filter((l) => (fileComponentMap[l.filePath] ?? []).length > 0),
|
|
57
|
+
componentIds: Array.from(componentIds),
|
|
58
|
+
layoutComponentIds: layoutIds,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const child of node.children) walk(child, chain);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
walk(root, []);
|
|
67
|
+
return routes;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ─── Param enumeration ────────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
export type ParamCombo = CoercedParams;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the param combos to capture for a route. Static routes have
|
|
76
|
+
* exactly one combo (the empty record) — `export const prerender`-style
|
|
77
|
+
* components on static pages need no enumerator. Dynamic routes require
|
|
78
|
+
* `generateStaticSegmentParams` (design/44 §generateStaticSegmentParams);
|
|
79
|
+
* without it every request renders live and the wrapper is a no-op.
|
|
80
|
+
*/
|
|
81
|
+
export async function enumerateCombos(
|
|
82
|
+
route: CandidateRoute,
|
|
83
|
+
pageModule: Record<string, unknown>,
|
|
84
|
+
log: (message: string) => void
|
|
85
|
+
): Promise<ParamCombo[] | null> {
|
|
86
|
+
if (!hasDynamicSegments(route.urlPath)) return [{}];
|
|
87
|
+
|
|
88
|
+
const generateFn = pageModule.generateStaticSegmentParams;
|
|
89
|
+
if (typeof generateFn !== 'function') {
|
|
90
|
+
log(
|
|
91
|
+
`[timber] cache.component: route ${route.urlPath} has prebuilt components but no ` +
|
|
92
|
+
`generateStaticSegmentParams export — all its entries will render dynamically ` +
|
|
93
|
+
`until the page declares its param combos`
|
|
94
|
+
);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const combos: unknown = await (generateFn as () => unknown)();
|
|
98
|
+
if (!Array.isArray(combos)) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`generateStaticSegmentParams must return an array of param records, got ${typeof combos}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return combos as ParamCombo[];
|
|
104
|
+
}
|
|
@@ -1,89 +1,196 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* (server/prebuilt-runtime.ts).
|
|
2
|
+
* Capture state — the channel between a payload capture and the
|
|
3
|
+
* `__prebuilt` wrappers that render inside it (server/prebuilt-runtime.ts).
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
* components. With no payload source registered (the capture pass runs
|
|
8
|
-
* before artifacts exist), those inner wrappers render live and their
|
|
9
|
-
* output is baked flat into the outer entry — the nesting clamp of
|
|
10
|
-
* design/45-cache-lifetimes.md §Nesting Semantics (TIM-1136). The capture
|
|
11
|
-
* pass is the designated detection point for that clamp, so the wrapper
|
|
12
|
-
* reports every render that happens while a capture is active:
|
|
5
|
+
* Two callers capture a wrapped component's flight payload:
|
|
13
6
|
*
|
|
14
|
-
* - **
|
|
15
|
-
*
|
|
16
|
-
*
|
|
7
|
+
* - **Build time**: the post-build capture pass (server/prebuilt-builder.ts)
|
|
8
|
+
* renders each registry entry in turn.
|
|
9
|
+
* - **Request time**: `captureComponentPayload()` in prebuilt-runtime.ts
|
|
10
|
+
* renders a component in isolation for an inline re-render (full miss,
|
|
11
|
+
* stale entry, tombstone) or an SWR background re-render. These run
|
|
12
|
+
* concurrently with other requests' renders — and with each other.
|
|
13
|
+
*
|
|
14
|
+
* During a capture, the component's subtree may render OTHER wrapped
|
|
15
|
+
* components. Those inner wrappers render live and their output is baked
|
|
16
|
+
* flat into the outer entry — the nesting clamp of
|
|
17
|
+
* design/45-cache-lifetimes.md §Nesting Semantics (TIM-1136). The wrapper
|
|
18
|
+
* reports every render that happens inside a capture:
|
|
19
|
+
*
|
|
20
|
+
* - **Cycle**: the inner render IS the entry being captured — same
|
|
21
|
+
* component id AND same props key (TIM-1547). Left alone this recurses
|
|
17
22
|
* until the render times out; instead the wrapper throws
|
|
18
23
|
* `PrebuiltCaptureCycleError`, failing that entry with an error naming
|
|
19
|
-
* the cycle
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
24
|
+
* the cycle (build continues per doc 44 skip-and-report policy; at
|
|
25
|
+
* request time the re-render fails and is not cached, and the wrapper
|
|
26
|
+
* falls back as for any failed re-render). A component that renders
|
|
27
|
+
* itself with different props (a comment thread, a tree) is legitimate
|
|
28
|
+
* recursion with a base case and bakes flat like any other nesting.
|
|
29
|
+
* - **Nesting**: any other wrapper render is recorded per inner component
|
|
30
|
+
* with the tags it resolved to. Both capture callers run the clamp rule
|
|
31
|
+
* over those records when the entry completes (prebuilt/lifetime.ts).
|
|
32
|
+
*
|
|
33
|
+
* Identity is the capture ROOT only. A wrapper cannot see the wrappers
|
|
34
|
+
* between it and the root: Flight renders a component's children after
|
|
35
|
+
* the wrapper has returned, in Flight's own async context, not in a frame
|
|
36
|
+
* the wrapper could enter. So a same-key cycle that closes below the root
|
|
37
|
+
* (`A(p1) → A(p2) → A(p2) → …`) is not detected here; it is also an
|
|
38
|
+
* infinite recursion without caching, and the capture's render timeout
|
|
39
|
+
* fails it.
|
|
23
40
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
41
|
+
* The props key is the props half of the cache key (data props only,
|
|
42
|
+
* framework children outlet stripped — the same inputs the cache key
|
|
43
|
+
* hashes). The params half is left out: every render inside one capture
|
|
44
|
+
* reads the same segment params, so props decide identity. Unkeyable props
|
|
45
|
+
* (live React elements, …) cannot be proven identical and are never a
|
|
46
|
+
* cycle.
|
|
47
|
+
*
|
|
48
|
+
* Each capture's state lives in an AsyncLocalStorage store entered by
|
|
49
|
+
* `CaptureScope.run()`, so it is visible only to renders started inside
|
|
50
|
+
* that capture — including work Flight resumes after an await, which runs
|
|
51
|
+
* in the context the awaited promise was created in. A concurrent request
|
|
52
|
+
* rendering the same component is not a cycle, and a concurrent request
|
|
53
|
+
* rendering a different cached component still revives it from cache
|
|
54
|
+
* instead of baking it live (TIM-1536). Outside any capture
|
|
55
|
+
* `noteWrapperRender` is a single store lookup.
|
|
28
56
|
*/
|
|
29
57
|
|
|
58
|
+
import {
|
|
59
|
+
prebuiltCaptureAls,
|
|
60
|
+
requestContextAls,
|
|
61
|
+
type PrebuiltCaptureStore,
|
|
62
|
+
} from '../als-registry.ts';
|
|
30
63
|
import type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';
|
|
64
|
+
import { computeComponentCacheKey, splitSlotProps } from './cache-key.ts';
|
|
65
|
+
import { resolveTags } from './lifetime.ts';
|
|
66
|
+
import { withoutChildrenOutlet } from './slots.ts';
|
|
31
67
|
|
|
32
68
|
/** A wrapped component that rendered inside an active capture. */
|
|
33
69
|
export interface NestedWrapperRender {
|
|
34
70
|
innerId: string;
|
|
35
71
|
options: PrebuiltComponentOptions;
|
|
72
|
+
/**
|
|
73
|
+
* Every tag the inner resolved to across its renders in this capture;
|
|
74
|
+
* null when its tags function threw (the tags are unknown).
|
|
75
|
+
*/
|
|
76
|
+
tags: string[] | null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Per-inner record kept while the capture runs. */
|
|
80
|
+
export interface NestedRecord {
|
|
81
|
+
options: PrebuiltComponentOptions;
|
|
82
|
+
tags: Set<string> | null;
|
|
36
83
|
}
|
|
37
84
|
|
|
38
|
-
/** Thrown by the wrapper when a capture renders its own
|
|
85
|
+
/** Thrown by the wrapper when a capture renders its own entry. */
|
|
39
86
|
export class PrebuiltCaptureCycleError extends Error {
|
|
40
87
|
constructor(componentId: string) {
|
|
41
88
|
super(
|
|
42
|
-
`[timber] cache.component "${componentId}" renders itself
|
|
43
|
-
`other components) —
|
|
44
|
-
`
|
|
89
|
+
`[timber] cache.component "${componentId}" renders itself with the same props ` +
|
|
90
|
+
`(directly or through other components) — capturing its payload would recurse ` +
|
|
91
|
+
`forever. Remove the cycle or stop caching this component with cache.component.`
|
|
45
92
|
);
|
|
46
93
|
this.name = 'PrebuiltCaptureCycleError';
|
|
47
94
|
}
|
|
48
95
|
}
|
|
49
96
|
|
|
50
|
-
|
|
97
|
+
/** One capture's state, entered for the duration of its render. */
|
|
98
|
+
export interface CaptureScope {
|
|
99
|
+
/**
|
|
100
|
+
* Run `fn` inside this capture. Flight renders in the async context it
|
|
101
|
+
* was started (and pinged) from, so the render must be CREATED inside
|
|
102
|
+
* `run`; every wrapper it renders then sees this capture.
|
|
103
|
+
*/
|
|
104
|
+
run<T>(fn: () => T): T;
|
|
105
|
+
/** Wrapped components that rendered inside this capture so far. */
|
|
106
|
+
nestedRenders(): NestedWrapperRender[];
|
|
107
|
+
}
|
|
51
108
|
|
|
52
109
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
110
|
+
* The props half of a render's cache key, or null when unkeyable. Same
|
|
111
|
+
* inputs `tryRevivePayload` hashes: data props only for slot components,
|
|
112
|
+
* the framework-injected children outlet stripped.
|
|
55
113
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
114
|
+
function propsKey(
|
|
115
|
+
options: PrebuiltComponentOptions,
|
|
116
|
+
props: Record<string, unknown>
|
|
117
|
+
): string | null {
|
|
118
|
+
let keyProps = props;
|
|
119
|
+
if (options.slots && options.slots.length > 0) {
|
|
120
|
+
const split = splitSlotProps(props, options.slots);
|
|
121
|
+
if (split === null) return null;
|
|
122
|
+
keyProps = split.dataProps;
|
|
123
|
+
}
|
|
124
|
+
return computeComponentCacheKey(withoutChildrenOutlet(keyProps), {});
|
|
58
125
|
}
|
|
59
126
|
|
|
60
127
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
128
|
+
* Open a capture of component `outerId` rendered with `props`. Its state
|
|
129
|
+
* ends with the scope object.
|
|
63
130
|
*/
|
|
64
|
-
export function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
131
|
+
export function createCaptureScope(
|
|
132
|
+
outerId: string,
|
|
133
|
+
options: PrebuiltComponentOptions,
|
|
134
|
+
props: Record<string, unknown>
|
|
135
|
+
): CaptureScope {
|
|
136
|
+
const store: PrebuiltCaptureStore = {
|
|
137
|
+
outerId,
|
|
138
|
+
outerPropsKey: propsKey(options, props),
|
|
139
|
+
nested: new Map(),
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
run: (fn) => prebuiltCaptureAls.run(store, fn),
|
|
143
|
+
nestedRenders: () =>
|
|
144
|
+
Array.from(store.nested, ([innerId, record]) => ({
|
|
145
|
+
innerId,
|
|
146
|
+
options: record.options,
|
|
147
|
+
tags: record.tags && Array.from(record.tags),
|
|
148
|
+
})),
|
|
149
|
+
};
|
|
69
150
|
}
|
|
70
151
|
|
|
71
|
-
/** Whether
|
|
152
|
+
/** Whether the current render is inside a capture. */
|
|
72
153
|
export function isCaptureActive(): boolean {
|
|
73
|
-
return
|
|
154
|
+
return prebuiltCaptureAls.getStore() !== undefined;
|
|
74
155
|
}
|
|
75
156
|
|
|
76
157
|
/**
|
|
77
|
-
* Called by the `__prebuilt` wrapper on every render. No-op
|
|
78
|
-
* capture
|
|
79
|
-
*
|
|
158
|
+
* Called by the `__prebuilt` wrapper on every render. No-op outside a
|
|
159
|
+
* capture. Throws `PrebuiltCaptureCycleError` when the render is the
|
|
160
|
+
* entry the enclosing capture is producing.
|
|
80
161
|
*/
|
|
81
|
-
export function noteWrapperRender(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
162
|
+
export function noteWrapperRender(
|
|
163
|
+
innerId: string,
|
|
164
|
+
options: PrebuiltComponentOptions,
|
|
165
|
+
props: Record<string, unknown>
|
|
166
|
+
): void {
|
|
167
|
+
const capture = prebuiltCaptureAls.getStore();
|
|
168
|
+
if (capture === undefined) return;
|
|
169
|
+
if (innerId === capture.outerId && capture.outerPropsKey !== null) {
|
|
170
|
+
if (propsKey(options, props) === capture.outerPropsKey) {
|
|
171
|
+
throw new PrebuiltCaptureCycleError(innerId);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
let record = capture.nested.get(innerId);
|
|
175
|
+
if (record === undefined) {
|
|
176
|
+
record = { options, tags: new Set() };
|
|
177
|
+
capture.nested.set(innerId, record);
|
|
85
178
|
}
|
|
86
|
-
if (
|
|
87
|
-
|
|
179
|
+
if (record.tags !== null && options.tags) {
|
|
180
|
+
// A diagnostic must not change the capture. The tags function is user
|
|
181
|
+
// code, so it runs with the request context exited: a read of
|
|
182
|
+
// segment params, headers, or cookies inside it must not be charged
|
|
183
|
+
// to the OUTER entry (a build-time context violation, a lost
|
|
184
|
+
// param-independence proof, a key-discipline report). A tags function
|
|
185
|
+
// that throws — including because it needed that context — leaves the
|
|
186
|
+
// inner's tags unknown, which the clamp rule treats as not covered by
|
|
187
|
+
// the outer; the warning says so. The throw itself is not reported
|
|
188
|
+
// here: it belongs to the inner, which may never be cached on its own.
|
|
189
|
+
const tags = record.tags;
|
|
190
|
+
try {
|
|
191
|
+
for (const tag of requestContextAls.exit(() => resolveTags(options, props))) tags.add(tag);
|
|
192
|
+
} catch {
|
|
193
|
+
record.tags = null;
|
|
194
|
+
}
|
|
88
195
|
}
|
|
89
196
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifetime declarations of a `cache.component` — `prerender`, `ttl`,
|
|
3
|
+
* `tags` (design/45-cache-lifetimes.md) — and the nesting clamp between
|
|
4
|
+
* two of them (§Nesting Semantics, TIM-1136).
|
|
5
|
+
*
|
|
6
|
+
* The clamp rule lives here once, for both places a capture can embed one
|
|
7
|
+
* wrapped component in another: the post-build capture pass
|
|
8
|
+
* (server/prebuilt-builder.ts) and request-time re-renders
|
|
9
|
+
* (`captureComponentPayload()` in server/prebuilt-runtime.ts, TIM-1545).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { splitSlotProps } from './cache-key.ts';
|
|
13
|
+
import type { NestedWrapperRender } from './capture-state.ts';
|
|
14
|
+
import type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';
|
|
15
|
+
|
|
16
|
+
/** Whether the component has a runtime lifetime (ttl or tags). */
|
|
17
|
+
export function hasRuntimeLifetime(options: PrebuiltComponentOptions): boolean {
|
|
18
|
+
return options.ttl !== undefined || options.tags != null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolve tags from options (may be static array or function of props).
|
|
23
|
+
* Function-form tags receive DATA props only — slot props are excluded so
|
|
24
|
+
* the tags fn never sees SlotOutlet placeholders (capture paths pass
|
|
25
|
+
* placeholder-substituted props) and tags stay deterministic per key.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveTags(
|
|
28
|
+
options: PrebuiltComponentOptions,
|
|
29
|
+
props: Record<string, unknown>
|
|
30
|
+
): string[] {
|
|
31
|
+
if (!options.tags) return [];
|
|
32
|
+
if (Array.isArray(options.tags)) return options.tags;
|
|
33
|
+
const slots = options.slots;
|
|
34
|
+
// The split cannot fail here — capture paths pass framework-built shell
|
|
35
|
+
// props — but stay total: fall back to the props as given.
|
|
36
|
+
const fnProps =
|
|
37
|
+
slots && slots.length > 0 ? (splitSlotProps(props, slots)?.dataProps ?? props) : props;
|
|
38
|
+
return options.tags(fnProps);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─── Nesting clamp (design/45 §Nesting Semantics) ────────────────────────
|
|
42
|
+
|
|
43
|
+
/** The entry a capture is producing: its declaration and resolved tags. */
|
|
44
|
+
export interface CapturedLifetime {
|
|
45
|
+
id: string;
|
|
46
|
+
options: PrebuiltComponentOptions;
|
|
47
|
+
tags: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Why an embedded copy of `inner` goes stale inside `outer`, or null when
|
|
52
|
+
* the outer's refreshes cover every refresh channel the inner declares:
|
|
53
|
+
*
|
|
54
|
+
* - `shorterTtl`: the inner's ttl is shorter than the outer's effective
|
|
55
|
+
* lifetime (its ttl, or deploy-long without one).
|
|
56
|
+
* - `missingTags`: tags the inner resolved to that the outer lacks —
|
|
57
|
+
* `revalidateTag` on them refreshes the inner's own entries, never the
|
|
58
|
+
* copy. `null` inner tags (a tags function threw) cannot be proven a
|
|
59
|
+
* subset, so they count as missing.
|
|
60
|
+
*
|
|
61
|
+
* Declaring the inner's tags on the outer is the documented fix, and it
|
|
62
|
+
* silences the tag half by construction.
|
|
63
|
+
*/
|
|
64
|
+
function clampReasons(
|
|
65
|
+
outer: CapturedLifetime,
|
|
66
|
+
inner: NestedWrapperRender
|
|
67
|
+
): { shorterTtl: boolean; missingTags: string[] | null } | null {
|
|
68
|
+
const outerTtl = outer.options.ttl ?? Infinity;
|
|
69
|
+
const shorterTtl = inner.options.ttl !== undefined && inner.options.ttl < outerTtl;
|
|
70
|
+
const missingTags =
|
|
71
|
+
inner.tags === null ? null : inner.tags.filter((t) => !outer.tags.includes(t));
|
|
72
|
+
if (!shorterTtl && missingTags !== null && missingTags.length === 0) return null;
|
|
73
|
+
return { shorterTtl, missingTags };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Render a lifetime declaration for the clamp warning. */
|
|
77
|
+
function describeLifetime(
|
|
78
|
+
options: PrebuiltComponentOptions,
|
|
79
|
+
tags: readonly string[] | null
|
|
80
|
+
): string {
|
|
81
|
+
const parts: string[] = [];
|
|
82
|
+
if (options.prerender) parts.push('prerender');
|
|
83
|
+
if (options.ttl !== undefined) parts.push(`ttl: ${options.ttl}`);
|
|
84
|
+
if (tags === null) parts.push('tags: fn');
|
|
85
|
+
else if (tags.length > 0) parts.push(`tags: ${JSON.stringify(tags)}`);
|
|
86
|
+
return parts.join(', ') || 'no lifetime';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** When the outer entry — and so every copy embedded in it — refreshes. */
|
|
90
|
+
function describeRefresh(outer: CapturedLifetime): string {
|
|
91
|
+
const parts: string[] = [];
|
|
92
|
+
if (outer.options.ttl !== undefined) parts.push(`every ${outer.options.ttl}s`);
|
|
93
|
+
if (outer.tags.length > 0) parts.push(`on revalidateTag of its own tags`);
|
|
94
|
+
// Component keys are per-deploy, so every entry refreshes on redeploy.
|
|
95
|
+
parts.push('on redeploy');
|
|
96
|
+
return parts.join(', or ');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Warn for each wrapped component embedded in `outer`'s captured payload
|
|
101
|
+
* whose refresh channels the outer cannot honor. Once per (outer, inner)
|
|
102
|
+
* pair for the lifetime of `warnedPairs` — the builder passes one per
|
|
103
|
+
* build, the runtime one per process, since re-renders repeat. The key is
|
|
104
|
+
* the pair alone, not the reason: resolved tags vary with props, and a key
|
|
105
|
+
* that included them would grow with the data. So the first clamp found
|
|
106
|
+
* for a pair is the one reported. Returns the number of warnings emitted.
|
|
107
|
+
*/
|
|
108
|
+
export function warnNestingClamps(
|
|
109
|
+
outer: CapturedLifetime,
|
|
110
|
+
nested: readonly NestedWrapperRender[],
|
|
111
|
+
warnedPairs: Set<string>,
|
|
112
|
+
log: (message: string) => void
|
|
113
|
+
): number {
|
|
114
|
+
let count = 0;
|
|
115
|
+
for (const inner of nested) {
|
|
116
|
+
const reasons = clampReasons(outer, inner);
|
|
117
|
+
if (reasons === null) continue;
|
|
118
|
+
const pairKey = `${outer.id}\0${inner.innerId}`;
|
|
119
|
+
if (warnedPairs.has(pairKey)) continue;
|
|
120
|
+
warnedPairs.add(pairKey);
|
|
121
|
+
count++;
|
|
122
|
+
const outerLifetime = describeLifetime(outer.options, outer.tags);
|
|
123
|
+
const innerLifetime = describeLifetime(inner.options, inner.tags);
|
|
124
|
+
const consequences: string[] = [];
|
|
125
|
+
if (reasons.missingTags === null) {
|
|
126
|
+
consequences.push(
|
|
127
|
+
`${inner.innerId}'s tags could not be resolved during the capture (its tags function ` +
|
|
128
|
+
`threw or needed request context), so revalidating them may NOT update the embedded copy.`
|
|
129
|
+
);
|
|
130
|
+
} else if (reasons.missingTags.length > 0) {
|
|
131
|
+
const calls = reasons.missingTags.map((t) => `revalidateTag(${JSON.stringify(t)})`);
|
|
132
|
+
consequences.push(
|
|
133
|
+
`${calls.join(', ')} will NOT update the embedded copy; tag ${outer.id} itself if you ` +
|
|
134
|
+
`need that.`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (reasons.shorterTtl) {
|
|
138
|
+
consequences.push(
|
|
139
|
+
`${inner.innerId}'s ttl: ${inner.options.ttl} does not apply to the embedded copy.`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
log(
|
|
143
|
+
`[timber] ${inner.innerId} (${innerLifetime}) is embedded in ` +
|
|
144
|
+
`${outer.options.prerender ? 'prerendered' : 'cached'} ${outer.id} — the embedded ` +
|
|
145
|
+
`copy refreshes only when ${outer.id} does (${describeRefresh(outer)}). ` +
|
|
146
|
+
`${consequences.join(' ')} Chain: ${outer.id} (${outerLifetime}) → ${inner.innerId} ` +
|
|
147
|
+
`(${innerLifetime})`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return count;
|
|
151
|
+
}
|
|
@@ -19,6 +19,7 @@ import type { SlotValues } from '../../client/slot-context.ts';
|
|
|
19
19
|
import { SlotOutlet } from '../../client/slot-outlet.tsx';
|
|
20
20
|
import { SlotsProvider } from '../../client/slot-provider.tsx';
|
|
21
21
|
import { splitSlotProps } from './cache-key.ts';
|
|
22
|
+
import { hasRuntimeLifetime } from './lifetime.ts';
|
|
22
23
|
import type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -65,6 +66,18 @@ export function isChildrenSlotOutletElement(value: unknown): boolean {
|
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* `props` without the framework-injected children outlet — the key props
|
|
71
|
+
* of a render. The outlet is the same client reference on every request,
|
|
72
|
+
* so it never varies the cache key; user-provided children stay (and
|
|
73
|
+
* leave the props unkeyable). See design/45 §Layout Propagation, TIM-1181.
|
|
74
|
+
*/
|
|
75
|
+
export function withoutChildrenOutlet(props: Record<string, unknown>): Record<string, unknown> {
|
|
76
|
+
if (!isChildrenSlotOutletElement(props.children)) return props;
|
|
77
|
+
const { children: _children, ...rest } = props;
|
|
78
|
+
return rest;
|
|
79
|
+
}
|
|
80
|
+
|
|
68
81
|
/**
|
|
69
82
|
* Outcome of validating a `slots` declaration at registration time.
|
|
70
83
|
*
|
|
@@ -122,8 +135,7 @@ export function resolveSlotNames(id: string, options: PrebuiltComponentOptions):
|
|
|
122
135
|
return { kind: 'disabled' };
|
|
123
136
|
}
|
|
124
137
|
if (slots.length === 0) return { kind: 'none' };
|
|
125
|
-
|
|
126
|
-
if (!hasRuntimeLifetime) {
|
|
138
|
+
if (!hasRuntimeLifetime(options)) {
|
|
127
139
|
console.warn(
|
|
128
140
|
`[timber] cache.component "${id}": slots require a runtime lifetime ` +
|
|
129
141
|
`(ttl and/or tags). Slot caching is disabled.`
|
|
@@ -89,6 +89,9 @@ export function createBuildTimeStore(
|
|
|
89
89
|
segmentParamsRead: false,
|
|
90
90
|
};
|
|
91
91
|
const store: RequestContextStore = {
|
|
92
|
+
// No request at build time, so a stale-while-revalidate failure during
|
|
93
|
+
// capture is logged and not reported against a made-up one.
|
|
94
|
+
request: null,
|
|
92
95
|
headers: new Headers(),
|
|
93
96
|
originalHeaders: new Headers(),
|
|
94
97
|
cookieHeader: '',
|