@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 @@
|
|
|
1
|
+
{"version":3,"file":"status-page-marker-gaihi0KZ.js","names":[],"sources":["../../src/shared/rsc-error-envelope.ts","../../src/client/segment-cache.ts","../../src/client/router-url.ts","../../src/client/navigation-commit.ts","../../src/client/status-page-marker.tsx"],"sourcesContent":["/**\n * The hard-navigate error envelope shared by the server and the client router.\n *\n * A client-navigation (RSC) request cannot carry an error *page* — the response\n * body must be Flight data or the decoder crashes. Instead the server answers\n * with this envelope: an `X-Timber-Error: 1` header and a minimal JSON body.\n * The client treats it as \"give up on SPA navigation and hard-navigate\", and\n * the resulting document request renders the real error page as HTML.\n *\n * The header name lives here so the four server producers and the single\n * client consumer cannot drift apart. See design/10-error-handling.md\n * §\"Error Page Rendering for Client Navigation\".\n */\n\n/** Header the client checks to decide whether to hard-navigate. */\nexport const TIMBER_ERROR_HEADER = 'X-Timber-Error';\n","// Segment Cache — stores the mounted segment tree and prefetched payloads\n// See design/19-client-navigation.md for architecture details.\n\nimport type { PublishedParams } from '../shared/payload-root.ts';\nimport type { SegmentInfo, StateTree } from '../shared/segment-info.ts';\nimport { createSingleflight } from '../cache/singleflight.ts';\n\n// ─── Types ───────────────────────────────────────────────────────\n\n/** A prefetched RSC result with optional segment metadata. */\nexport interface PrefetchResult {\n payload: unknown;\n /**\n * Completion of the full Flight stream, when the prefetch is still decoding.\n * Carried through to the navigation that consumes the entry so a decode\n * failure reaches *that* navigation's recovery rather than dying with the\n * prefetch (TIM-1275).\n */\n decodePromise?: Promise<void> | null;\n /** Segment metadata from X-Timber-Segments header for populating the segment cache. */\n segmentInfo?: SegmentInfo[] | null;\n /**\n * The params published beside `payload`, split off the same payload root.\n * Carried so a consumed prefetch publishes the params of the tree it is\n * about to render, and not the ones already on screen.\n */\n params?: PublishedParams | Promise<PublishedParams>;\n /** Segment paths skipped by the server (for client-side merging). */\n skippedSegments?: string[] | null;\n}\n\n/**\n * A node in the client-side segment tree. Each node represents a mounted\n * layout or page segment with its RSC flight payload.\n */\nexport interface SegmentNode {\n /** The segment's URL pattern (e.g., \"/\", \"/dashboard\", \"/projects/[id]\") */\n segment: string;\n /**\n * The segment's `app/` directory path, groups included (e.g. `/(browse)/feed`).\n * Undefined for slot nodes and for servers that predate the field.\n */\n treePath?: string;\n /** The RSC flight payload for this segment (opaque to the cache) */\n payload: unknown;\n /**\n * Whether the segment/slot is request-dependent (calls getHeaders,\n * getSearchParams, cookies, etc.). Request-dependent segments always\n * re-render on navigation. For segments, this is still based on the\n * AsyncFunction heuristic (to be replaced separately). For slots,\n * this is taint-tracked via ALS.\n */\n isRequestDependent: boolean;\n /** Child segments keyed by segment path */\n children: Map<string, SegmentNode>;\n /** Parallel route slots keyed by slot path (e.g., \"/@sidebar\") */\n slots?: Map<string, SegmentNode>;\n /** Whether this slot's access.ts denied on its last render. */\n denied?: boolean;\n /**\n * Content key for slot nodes — opaque string the server computed from\n * owner parts, slot name, entry file, and slot params. Advertised back\n * to the server so it can decide skips by key membership (TIM-1370).\n */\n contentKey?: string;\n}\n\n// ─── Segment Cache ───────────────────────────────────────────────\n\n/**\n * Maintains the client-side segment tree representing currently mounted\n * layouts and pages. Used for navigation reconciliation — the router diffs\n * new routes against this tree to determine which segments to re-fetch.\n */\nexport class SegmentCache {\n private root: SegmentNode | undefined;\n /**\n * Monotonic counter. Bumped by `invalidateReuse()` (TIM-1466).\n * `serializeStateTree` suppresses `segments` and `slots` when\n * `reuseInvalidatedAt > reuseRestoredAt`. Only `restoreReuse()`\n * advances `reuseRestoredAt` — `set()` does not, because a\n * pre-invalidation navigation's commit thunk would lift suppression\n * before a post-invalidation request has been sent (codex on #1167).\n */\n private reuseInvalidatedAt = 0;\n private reuseRestoredAt = 0;\n\n get(segment: string): SegmentNode | undefined {\n if (segment === '/' || segment === this.root?.segment) {\n return this.root;\n }\n return undefined;\n }\n\n set(segment: string, node: SegmentNode): void {\n if (segment === '/' || !this.root) {\n this.root = node;\n }\n }\n\n clear(): void {\n this.root = undefined;\n this.reuseRestoredAt = this.reuseInvalidatedAt;\n }\n\n /**\n * Suppress segment and slot reuse without destroying the tree\n * structure (TIM-1466). `serializeStateTree` sends empty\n * `segments`/`slots` (forcing a full render) while `treePaths`\n * still reflects the mounted tree for interception scoping.\n * Call `restoreReuse()` once post-invalidation data has been\n * fetched and committed.\n */\n invalidateReuse(): void {\n this.reuseInvalidatedAt++;\n }\n\n /**\n * Lift reuse suppression. Called after the segment cache has been\n * rebuilt from a response that was fetched with suppression active\n * (i.e. the server sent a full render). Safe to call idempotently.\n */\n restoreReuse(): void {\n this.reuseRestoredAt = this.reuseInvalidatedAt;\n }\n\n /** Whether segment/slot reuse is currently suppressed (TIM-1466). */\n isReuseSuppressed(): boolean {\n return this.reuseInvalidatedAt > this.reuseRestoredAt;\n }\n\n /**\n * Serialize the mounted segment tree for the X-Timber-State-Tree header.\n * Only includes sync segments — async segments are excluded because the\n * server must always re-render them (they may depend on request context).\n *\n * When mergeableFilter is provided, only segments whose paths are in the\n * set are included. This ensures the server only skips segments that the\n * client can actually merge (i.e., segments whose cached element tree\n * contains an inner SegmentProvider the merger can splice into).\n *\n * `treePaths` is collected UNFILTERED, unlike `segments` and `slots`. Those\n * two answer \"what may the server skip re-rendering?\", so every reason a\n * segment cannot be reused is a reason to leave it out. `treePaths` answers\n * \"what is mounted right now?\" for interception scoping — a request-dependent\n * layout is still on screen, and dropping it would silently narrow the scope\n * the server sees and cancel a modal that should open (TIM-1282).\n *\n * This is a performance optimization only, NOT a security boundary.\n * The server always runs all access.ts files regardless of the state tree.\n */\n serializeStateTree(mergeableFilter?: Set<string>): StateTree {\n const segments: string[] = [];\n const slots: string[] = [];\n const treePaths: string[] = [];\n const suppressed = this.reuseInvalidatedAt > this.reuseRestoredAt;\n if (this.root) {\n if (!suppressed) {\n collectSyncSegments(this.root, segments, mergeableFilter);\n collectSyncSlots(this.root, slots);\n }\n collectTreePaths(this.root, treePaths);\n }\n const tree: StateTree = { segments };\n if (slots.length > 0) {\n tree.slots = slots;\n }\n if (treePaths.length > 0) {\n tree.treePaths = treePaths;\n }\n return tree;\n }\n}\n\n/** Recursively collect sync segment paths from the tree */\nfunction collectSyncSegments(\n node: SegmentNode,\n out: string[],\n mergeableFilter?: Set<string>\n): void {\n if (!node.isRequestDependent && (!mergeableFilter || mergeableFilter.has(node.segment))) {\n out.push(node.segment);\n }\n for (const child of node.children.values()) {\n collectSyncSegments(child, out, mergeableFilter);\n }\n}\n\n/**\n * Recursively collect the `app/` directory path of every mounted segment.\n *\n * Slots are not walked: a slot's own sub-tree can never own an intercepting\n * slot's scope, because scopes are always ordinary segments (`interception.ts`\n * derives one from the slot owner's ancestor chain).\n */\nfunction collectTreePaths(node: SegmentNode, out: string[]): void {\n if (node.treePath) out.push(node.treePath);\n for (const child of node.children.values()) {\n collectTreePaths(child, out);\n }\n}\n\n/**\n * Recursively collect content keys from cacheable slots.\n *\n * The server advertises a content key per slot on every render (TIM-1370),\n * encoding the owner's URL parts, the slot name, the matched entry file,\n * and the slot's params. The client stores this key and sends it back on\n * the next navigation so the server can decide skips by key membership —\n * no departing URL reconstruction needed.\n */\nfunction collectSyncSlots(node: SegmentNode, out: string[]): void {\n if (node.slots) {\n for (const slot of node.slots.values()) {\n if (!slot.isRequestDependent && !slot.denied && slot.contentKey) {\n out.push(slot.contentKey);\n }\n }\n }\n for (const child of node.children.values()) {\n collectSyncSlots(child, out);\n }\n}\n\n// ─── Segment Tree Builder ────────────────────────────────────────\n\n/**\n * Build a SegmentNode tree from flat segment metadata.\n *\n * Takes an ordered list of segment descriptors (root → leaf) from the\n * server's X-Timber-Segments header and constructs the hierarchical\n * tree structure that SegmentCache expects.\n *\n * Each segment is nested as a child of the previous one, forming a\n * linear chain from root to leaf. The leaf segment (page) is excluded\n * from the tree — pages are never cached across navigations.\n */\nexport function buildSegmentTree(segments: SegmentInfo[]): SegmentNode | undefined {\n // Need at least a root segment to build a tree\n if (segments.length === 0) return undefined;\n\n // Separate slot entries from segment entries. Slots are attached to\n // their parent segment node after the main chain is built.\n const segmentEntries: SegmentInfo[] = [];\n const slotEntries: SegmentInfo[] = [];\n for (const info of segments) {\n if (info.slot) {\n slotEntries.push(info);\n } else {\n segmentEntries.push(info);\n }\n }\n\n // Build the main segment chain.\n let root: SegmentNode | undefined;\n let parent: SegmentNode | undefined;\n const nodeById = new Map<string, SegmentNode>();\n\n for (const info of segmentEntries) {\n const id = info.segmentId ?? info.path;\n const node: SegmentNode = {\n segment: id,\n treePath: info.treePath,\n payload: null,\n isRequestDependent: info.isRequestDependent,\n children: new Map(),\n };\n\n nodeById.set(id, node);\n\n if (!root) {\n root = node;\n }\n\n if (parent) {\n parent.children.set(id, node);\n }\n\n parent = node;\n }\n\n // Attach slot entries to their parent segment nodes.\n for (const slotInfo of slotEntries) {\n const parentId = slotInfo.parentSegment;\n const parentNode = parentId ? nodeById.get(parentId) : root;\n if (!parentNode) continue;\n\n const slotId = slotInfo.segmentId ?? slotInfo.path;\n const slotNode: SegmentNode = {\n segment: slotId,\n payload: null,\n isRequestDependent: slotInfo.isRequestDependent,\n children: new Map(),\n denied: slotInfo.denied,\n contentKey: slotInfo.contentKey,\n };\n\n if (!parentNode.slots) {\n parentNode.slots = new Map();\n }\n parentNode.slots.set(slotId, slotNode);\n }\n\n return root;\n}\n\n// ─── Prefetch Cache ──────────────────────────────────────────────\n\ninterface ReadyEntry {\n result: PrefetchResult;\n expiresAt: number;\n}\n\n/** Sentinel value for negative cache entries (URL is not a route). */\nconst NEGATIVE_ENTRY: PrefetchResult = Object.freeze({ payload: null });\n\n/**\n * Timeout for the in-flight singleflight (TIM-1438). Per CLAUDE.md's\n * singleflight rule: \"Never write a coalescing Map without a timeout.\"\n * A hung prefetch cannot block clicks or suppress hovers forever.\n */\nconst PREFETCH_SINGLEFLIGHT_TIMEOUT_MS = 5_000;\n\n/**\n * Identifies a prefetched payload. A payload is addressed by *every* input that\n * changes the server's answer, not by the destination alone.\n *\n * The server's answer for a destination depends on where the request came\n * from — that is the whole mechanism behind intercepting routes, and it also\n * drives slot-skip resolution. A prefetch issued from `/gallery` is a modal\n * payload; the same URL prefetched from `/` is the full page. Keying on the\n * destination alone let the first click after a hover be answered with\n * whichever variant happened to be fetched (TIM-1265).\n *\n * `from` alone stopped being enough in TIM-1282. It is a pathname, and once\n * interception scope comes from the rendered tree rather than the address, one\n * pathname no longer names one source tree: `/photo/1` is the address both for\n * a modal open over `(browse)` and for `(landing)`'s canonical page. A key\n * without the scope hands the modal payload to the canonical page's click,\n * which renders it without the server's scope check ever running.\n *\n * The two reads happen at different instants — `scope` is sampled at hover and\n * again at click — which is why a tree that changed in between produces a\n * *miss* and a refetch rather than a wrong hit.\n */\nexport interface PrefetchKey {\n /** Destination URL — hash-less `pathname + search`, as navigate() fetches it. */\n url: string;\n /** Departing pathname — the `X-Timber-URL` the prefetch was issued with. */\n from: string;\n /**\n * The rendered scope the prefetch was issued with — the `treePaths` half of\n * `X-Timber-State-Tree`, joined. Empty when none crossed.\n */\n scope: string;\n}\n\n/**\n * Compose the map key. Length-prefixed rather than delimiter-joined for the\n * same reason `shared/rsc-cache-key.ts` is: any delimiter is forgeable by a\n * value containing it, and a URL may contain any character a delimiter could.\n */\nfunction prefetchMapKey(key: PrefetchKey): string {\n return `${key.from.length}:${key.from}:${key.scope.length}:${key.scope}:${key.url}`;\n}\n\n/**\n * Extract the destination URL from a length-prefixed map key.\n * Key format: `${from.length}:${from}:${scope.length}:${scope}:${url}`\n */\nfunction extractUrlFromMapKey(mapKey: string): string | null {\n // Parse from-length prefix\n const firstColon = mapKey.indexOf(':');\n if (firstColon === -1) return null;\n const fromLen = parseInt(mapKey.slice(0, firstColon), 10);\n if (Number.isNaN(fromLen)) return null;\n // Skip past `from.length:from:`\n const scopeStart = firstColon + 1 + fromLen + 1;\n // Parse scope-length prefix\n const secondColon = mapKey.indexOf(':', scopeStart);\n if (secondColon === -1) return null;\n const scopeLen = parseInt(mapKey.slice(scopeStart, secondColon), 10);\n if (Number.isNaN(scopeLen)) return null;\n // Skip past `scope.length:scope:` — remainder is the URL\n return mapKey.slice(secondColon + 1 + scopeLen + 1);\n}\n\n/**\n * The `scope` half of a `PrefetchKey`, derived from the state tree that will\n * actually be sent. Taking it from the header value rather than re-walking the\n * cache is the point: the key varies by exactly what the request varies by.\n */\nexport function prefetchScopeOf(stateTree: StateTree | undefined): string {\n return stateTree?.treePaths?.join('\\u0000') ?? '';\n}\n\n/** Outcome of a prefetch flight — discriminated so NonRscResponse is a\n * success (stores a negative entry) rather than a rejection.\n * `startGen` is the eviction generation at flight start — joiners that\n * started after a gen bump must reject pre-invalidation results (TIM-1464). */\nexport type FlightOutcome =\n | { kind: 'ready'; result: PrefetchResult; startGen: number }\n | { kind: 'non-route'; startGen: number };\n\n/**\n * Short-lived cache for hover-triggered prefetches. Entries expire after\n * 30 seconds. When a link is clicked, the prefetched payload is consumed\n * (moved to the history stack) and removed from this cache.\n *\n * In-flight dedup (TIM-1438): concurrent fetches for the same key are\n * coalesced by a `createSingleflight` instance. A hover starts a flight;\n * a click for the same key joins it instead of issuing a duplicate. The\n * singleflight enforces a 5-second timeout and cleans up automatically\n * on settlement.\n *\n * timber.js does NOT prefetch on viewport intersection — only explicit\n * hover on <Link prefetch> triggers a prefetch.\n */\nexport class PrefetchCache {\n private static readonly TTL_MS = 30_000;\n private entries = new Map<string, ReadyEntry>();\n private flights = createSingleflight({ timeoutMs: PREFETCH_SINGLEFLIGHT_TIMEOUT_MS });\n private evictionGen = 0;\n\n set(key: PrefetchKey, result: PrefetchResult): void {\n this.entries.set(prefetchMapKey(key), {\n result,\n expiresAt: Date.now() + PrefetchCache.TTL_MS,\n });\n }\n\n get(key: PrefetchKey): PrefetchResult | undefined {\n const mapKey = prefetchMapKey(key);\n const entry = this.entries.get(mapKey);\n if (!entry) return undefined;\n if (Date.now() >= entry.expiresAt) {\n this.entries.delete(mapKey);\n return undefined;\n }\n return entry.result;\n }\n\n /** True if a ready or negative entry exists for this key. */\n has(key: PrefetchKey): boolean {\n return this.get(key) !== undefined;\n }\n\n /** Get and remove the entry (used when navigation consumes a prefetch) */\n consume(key: PrefetchKey): PrefetchResult | undefined {\n const result = this.get(key);\n if (result !== undefined) {\n this.entries.delete(prefetchMapKey(key));\n }\n return result;\n }\n\n /**\n * Fetch or coalesce with an in-flight fetch for this key (TIM-1438).\n *\n * Concurrent callers (hover + click, repeated hovers) get the same\n * promise. On success the result is stored as a ready entry. On\n * NonRscResponse a negative entry is stored and the outcome is\n * `{ kind: 'non-route' }`. Other errors (network, version skew)\n * reject — the singleflight cleans up the key and subsequent callers\n * retry.\n *\n * The singleflight signal is passed to `doFetch` so a timed-out flight\n * aborts the underlying fetch rather than leaving it running.\n */\n fetchOrCoalesce(\n key: PrefetchKey,\n doFetch: (signal: AbortSignal) => Promise<PrefetchResult>,\n isNonRoute: (error: unknown) => boolean\n ): Promise<FlightOutcome> {\n // Capture the eviction generation before the flight starts. If an\n // action evicts caches while this flight is in progress, the gen\n // will have bumped and the stale result is discarded (TIM-1476).\n // The starting gen is also included in the outcome so joiners\n // that started after a gen bump can detect pre-invalidation\n // results (TIM-1464).\n const genAtStart = this.evictionGen;\n return this.flights.do(prefetchMapKey(key), async (signal) => {\n try {\n const result = await doFetch(signal);\n if (!signal.aborted && this.evictionGen === genAtStart) this.set(key, result);\n return { kind: 'ready' as const, result, startGen: genAtStart };\n } catch (err) {\n if (isNonRoute(err)) {\n if (!signal.aborted && this.evictionGen === genAtStart) this.setNegative(key);\n return { kind: 'non-route' as const, startGen: genAtStart };\n }\n throw err;\n }\n });\n }\n\n /**\n * Join an in-flight singleflight fetch if one exists for this key.\n * Returns the in-flight promise or undefined. Used by the click path to\n * coalesce with a hover prefetch without starting a new flight — when no\n * flight exists, the click issues its own fetch with the navigation's\n * abort signal so superseded navigations abort immediately (TIM-1438).\n */\n joinInflight(key: PrefetchKey): Promise<FlightOutcome> | undefined {\n return this.flights.get(prefetchMapKey(key)) as Promise<FlightOutcome> | undefined;\n }\n\n /**\n * Store a negative entry — the URL is not a route (non-RSC Content-Type).\n *\n * Keyed like every other entry even though \"not a route\" does not actually\n * vary by departing URL: a source-independent negative would be a second\n * keying rule to keep correct, and the only cost of the uniform one is a\n * repeated fetch for a link hovered from a second page.\n */\n setNegative(key: PrefetchKey): void {\n this.set(key, NEGATIVE_ENTRY);\n }\n\n /** Check if the entry is a negative cache entry (URL is not a route). */\n isNegative(key: PrefetchKey): boolean {\n return this.get(key) === NEGATIVE_ENTRY;\n }\n\n /**\n * Invalidate entries whose destination URL matches (TIM-1454).\n *\n * When `url` has no search string, evicts all entries sharing that\n * pathname — `/products` evicts `/products?page=1` too, because\n * `revalidatePath('/products')` invalidates the route regardless of\n * query (TIM-1465).\n *\n * When `url` has a search string, only the exact URL is evicted.\n *\n * Also bumps the eviction generation so in-flight singleflight\n * flights for the invalidated URL(s) discard their results on\n * completion (TIM-1464).\n */\n invalidateUrl(url: string): void {\n const hasSearch = url.includes('?');\n const pathname = hasSearch ? null : url;\n\n for (const [mapKey] of this.entries) {\n // The map key is `${from.length}:${from}:${scope.length}:${scope}:${url}`.\n // The destination URL is the suffix after the last unescaped colon pair.\n if (hasSearch) {\n if (mapKey.endsWith(':' + url)) {\n this.entries.delete(mapKey);\n }\n } else {\n // Extract the URL suffix — everything after the scope block.\n // Match any entry whose URL pathname matches.\n const entryUrl = extractUrlFromMapKey(mapKey);\n if (entryUrl !== null) {\n const qIndex = entryUrl.indexOf('?');\n const entryPathname = qIndex === -1 ? entryUrl : entryUrl.slice(0, qIndex);\n if (entryPathname === pathname) {\n this.entries.delete(mapKey);\n }\n }\n }\n }\n\n // Fence in-flight flights so a prefetch that started before\n // invalidation cannot store its stale result (TIM-1464).\n this.evictionGen++;\n }\n\n /**\n * Evict all ready entries and fence in-flight singleflights (TIM-1476).\n * Called after a server action that revalidated data — the mutation may\n * affect any route, not just the paths the server named. In-flight\n * singleflights are not aborted (they may carry post-mutation data),\n * but their results are discarded if they complete after eviction:\n * `fetchOrCoalesce` captures the generation before the flight and\n * skips the store when it has been bumped.\n *\n * Consumers that join an in-flight flight via `joinInflight` must\n * check `getEvictionGen()` before and after the await: if the gen\n * changed, the result predates the eviction and must be discarded\n * (codex on #1131 round 2).\n */\n clearReady(): void {\n this.entries.clear();\n this.evictionGen++;\n }\n\n getEvictionGen(): number {\n return this.evictionGen;\n }\n}\n","/**\n * How the client router reads the URLs it is handed.\n *\n * One parser, so the places that key or compare by URL — the history stack,\n * the navigation state a page renders with, the departing page sent as\n * `X-Timber-URL` — cannot disagree about what a URL says. They did: a\n * history entry stored under `navigate('/café')`'s spelling was looked up\n * under the address bar's `/caf%C3%A9`, and missed (TIM-1541).\n */\n\nconst BASE = 'http://localhost';\n\n/**\n * Parse a router URL. A URL that starts with \"/\" is a path — including one\n * that starts with \"//\": that is the pathname a document at\n * `https://host//a/b` reports, and resolved against a base it would parse as\n * a scheme-relative reference to host `a`. Anything else resolves against a\n * placeholder origin, so an absolute URL keeps its own.\n */\nexport function parseRouterUrl(url: string): URL {\n return url.startsWith('/') ? new URL(BASE + url) : new URL(url, BASE);\n}\n\n/**\n * The spelling a URL is stored and looked up under: the browser's own\n * pathname + search, so `/a?` and `/a`, `/café` and `/caf%C3%A9`, are one\n * key. The fragment is dropped — it is client-only.\n */\nexport function routerUrlKey(url: string): string {\n const parsed = parseRouterUrl(url);\n return parsed.pathname + parsed.search;\n}\n","/**\n * What it means for a page to be \"current\" on the client.\n *\n * One module owns every write that makes a navigation's destination the\n * current page, and the read that describes the current page back to the\n * server. Keeping them together is the point: `X-Timber-State-Tree` is\n * derived from the segment cache, so the thing that publishes and the thing\n * that reports have to agree about when a page becomes current.\n *\n * See design/19-client-navigation.md §\"State Update Invariants\".\n */\n\nimport { buildSegmentTree, type SegmentCache } from './segment-cache.ts';\nimport type { HistoryStack } from './history.ts';\nimport type { SegmentInfo, StateTree } from '../shared/segment-info.ts';\nimport type { ParamsSource } from '../shared/payload-root.ts';\nimport type { NavigationState } from './navigation-context.ts';\nimport { parseRouterUrl } from './router-url.ts';\nimport {\n statusPageRendered,\n _setStatusPageRendered,\n onStatusPageRendered,\n _setOnStatusPageRendered,\n} from './state.ts';\n\n// ─── What a status page teaches the cache ─────────────────────────────────\n//\n// A status page replaces a subtree: a deny page lands at the segment owning\n// the matched file and nothing below it mounts; an `error.tsx` fallback\n// discards everything under the boundary that rendered it. `X-Timber-Segments`\n// nonetheless describes the whole chain the payload was built against — it\n// must, because a partial navigation picks its merge point out of it — so the\n// cache has to be told not to learn from such a tree.\n//\n// The HTTP status used to say so, and could not be trusted to: an RSC payload\n// response commits one macrotask after its first chunk, and a nested\n// component that denies after I/O puts its row in the stream after the\n// status line has gone out (TIM-1489). The only thing that reliably knows a\n// status page rendered is the status page itself, and the only moment that\n// matters is the commit that puts it on screen — so every status page the\n// framework produces is wrapped in `StatusPageMarker`, whose layout effect\n// reports on each commit that renders it. Layout effects run child-before-\n// parent, so the report lands before `NavigationRoot`'s publish of that\n// same commit, and never for a render React discards. Without Suspense\n// around the row, the transition cannot commit until the row has arrived, so\n// this covers the delayed nested case too, which no status ever could.\n//\n// The report also clears the cache on the spot, because not every commit\n// has a navigation to consume it: a deny row arriving inside a Suspense\n// boundary after its navigation published, or a status document being\n// hydrated, would otherwise leave a tree in the cache that is no longer on\n// screen. Consuming the flag at commit is what keeps the same navigation from\n// re-seeding it a moment later. Both are over-approximations — a page-level\n// deny leaves every layout standing — at the cost of one full render on the\n// next navigation.\n//\n// Slot boundaries do not report: a slot degrading is the page staying, and\n// the chain it mounted is the chain the header describes. See TIM-1356,\n// TIM-1495, design/04-authorization.md §\"Where a Deny Page Renders\".\n\n/**\n * Record that a status page for the main route is on screen. Called from\n * `StatusPageMarker`'s layout effect; consumed by the commit of the\n * navigation whose tree it belongs to, and acted on immediately for the\n * commits that have none.\n */\nexport function reportStatusPageRendered(): void {\n _setStatusPageRendered(true);\n onStatusPageRendered?.();\n}\n\n/** Everything a commit needs to describe the page it makes current. */\nexport interface NavigationCommitInput {\n payload: unknown;\n /** The params that payload published — replayed with it on popstate. */\n params: ParamsSource;\n /**\n * The rendered chain's metadata, or null/undefined when this commit\n * carries none at all — a revalidation payload, or a history entry\n * stored before the channel existed.\n *\n * An empty *array* is a different statement from an absent one: the\n * server rendered a route with no layout-bearing segments (a layoutless\n * app — the missing-root-layout check is a warning, not an error), so\n * the correct tree is the empty one. Collapsing the two left the\n * departing route's tree in place, which `treePaths` then reported as\n * mounted — enough to select an intercepting rewrite whose slot is not\n * on screen (TIM-1282).\n */\n segmentInfo?: SegmentInfo[] | null;\n /** When true, clear the segment cache if segmentInfo is absent\n * (popstate replay for entries without layout metadata). */\n clearSegmentCacheOnEmpty?: boolean;\n /**\n * Layouts the server skipped on this response (`X-Timber-Skipped-Segments`),\n * when it came from a fetch. Omitted by replays and revalidation.\n *\n * Together with `skipped` slot entries in `segmentInfo`, this decides\n * whether the payload can be *replayed*. A partial payload only renders\n * merged over the tree on screen, and a `skip=true` outlet resolves against\n * the slot content cache at render time — so a stored copy of either,\n * replayed later, shows whatever the client holds *then*, not what was on\n * screen when the entry committed. Such entries store a null payload and\n * traversals to them fetch instead. Decided here, not at the fetch call\n * sites, because there are three of those (`performNavigationFetch`,\n * `refresh()`, and uncached traversal) and a rule applied at one of them\n * holds by accident: `performNavigationFetch` had the check and\n * `fetchCommitAndRender` did not, so a back/forward fetch that was\n * answered with skips stored the holes (TIM-1432).\n */\n skippedSegments?: string[] | null;\n}\n\n/** Whether a response skipped layouts — its payload merges over the tree on screen. */\nexport function isPartialNavigation(skippedSegments: string[] | null | undefined): boolean {\n return skippedSegments != null && skippedSegments.length > 0;\n}\n\n/**\n * Whether a payload can stand on its own when replayed from the history\n * stack. See `NavigationCommitInput.skippedSegments`.\n */\nfunction isReplayable(opts: NavigationCommitInput): boolean {\n return !isPartialNavigation(opts.skippedSegments) && !hasSkippedSlot(opts.segmentInfo);\n}\n\nfunction hasSkippedSlot(segmentInfo: SegmentInfo[] | null | undefined): boolean {\n return segmentInfo?.some((s) => s.slot && s.skipped) ?? false;\n}\n\n/**\n * The metadata a committed page keeps — on its history entry, and as the\n * current page's `committedSegmentInfo()`. `skipped` describes the\n * *response* — \"this slot's content was omitted\" — and neither stores such\n * a payload (the entry stores null). Kept, the flag outlives the response:\n * `applyActionResult()` reuses the current page's metadata beside a full\n * re-render and would have that judged non-replayable too.\n */\nfunction storedSegmentInfo(segmentInfo: SegmentInfo[] | null | undefined) {\n if (!hasSkippedSlot(segmentInfo)) return segmentInfo;\n return segmentInfo!.map(({ skipped: _skipped, ...rest }) => rest);\n}\n\n/**\n * A navigation's destination, split into what a render needs and what a\n * commit publishes.\n */\nexport interface PreparedNavigation {\n /** The state the incoming tree renders with. Pure — safe before winning. */\n navState: NavigationState;\n /** Publishes the destination. Call only once the render has won. */\n commit: () => void;\n}\n\nexport interface NavigationCommitter {\n prepareNavigation(url: string, opts: NavigationCommitInput): PreparedNavigation;\n currentStateTree(): StateTree | undefined;\n /**\n * The segment metadata of the page the last commit made current, as that\n * commit recorded it — null when it carried none.\n *\n * Server-action responses carry no segment metadata, so a revalidation\n * re-renders the current page with this. It is the committer's own record\n * rather than a history-stack lookup: the stack is keyed by the URL string\n * a navigation was asked for, and the current page is known by\n * `window.location`'s spelling of it, and the two need not agree\n * (`/a?` against `/a`, a percent-encoded path against a decoded one).\n */\n committedSegmentInfo(): SegmentInfo[] | null;\n /** Whether segment reuse is currently suppressed (TIM-1466). */\n isSegmentReuseSuppressed(): boolean;\n /** Lift segment reuse suppression after fresh data has been fetched (TIM-1466). */\n restoreSegmentReuse(): void;\n}\n\n/**\n * Derive the navigation state (pathname + search) a URL renders with.\n *\n * Pure. The value travels with the tree it describes — callers pass it to\n * `wrapPayload`, and the router's record of the displayed tree keeps it\n * beside that tree — so there is no store to publish it to (TIM-1541).\n */\nexport function deriveNavigationState(url: string): NavigationState {\n // Params are not part of it. They travel with the payload and are published\n // by the one client-owned `ParamsProvider` as the new tree renders, which is\n // also what clears the previous route's — a route with no params of its own\n // still publishes an empty record (TIM-1294/TIM-1297, and the clearing\n // requirement from TIM-1285).\n const parsed = parseRouterUrl(url);\n return { pathname: parsed.pathname || '/', search: parsed.search };\n}\n\nexport function createNavigationCommitter(deps: {\n segmentCache: SegmentCache;\n historyStack: HistoryStack;\n /** Read at call time — the router's `clientSegmentCache` opt-in. */\n clientSegmentCache: () => boolean | undefined;\n}): NavigationCommitter {\n const { segmentCache, historyStack } = deps;\n\n // See `committedSegmentInfo`. Written only by a commit.\n let committedSegmentInfo: SegmentInfo[] | null = null;\n\n // See `reportStatusPageRendered`: a status page that commits with no\n // navigation to consume the report still empties the cache.\n _setOnStatusPageRendered(() => segmentCache.clear());\n\n /**\n * Update the segment cache from server-provided segment metadata.\n *\n * Runs whether or not `clientSegmentCache` is enabled: the tree is also\n * where the mounted tree paths come from, and those cross on every\n * navigation. What the flag gates is which parts get serialized — see\n * `currentStateTree`.\n */\n function updateSegmentCache(segmentInfo: SegmentInfo[]): void {\n const tree = buildSegmentTree(segmentInfo);\n if (tree) {\n segmentCache.set('/', tree);\n }\n }\n\n return {\n committedSegmentInfo: () => committedSegmentInfo,\n isSegmentReuseSuppressed: () => segmentCache.isReuseSuppressed(),\n restoreSegmentReuse: () => segmentCache.restoreReuse(),\n\n /**\n * The X-Timber-State-Tree to send with the next RSC request.\n *\n * Two different things travel on one header. `segments`/`slots` are the\n * caching opt-in and are omitted unless `clientSegmentCache` is on.\n * `treePaths` is how the server learns which route is actually mounted,\n * which stops being derivable from the address bar as soon as a modal is\n * open — so it crosses regardless (TIM-1282). Undefined when there is\n * nothing to say, so a no-op header never enters the `_rsc` cache key.\n *\n * Reads what the last *committed* navigation published, so a superseded\n * navigation's destination can never end up describing the mounted tree\n * (TIM-1301).\n */\n currentStateTree(): StateTree | undefined {\n const tree = segmentCache.serializeStateTree();\n if (deps.clientSegmentCache()) return tree;\n return tree.treePaths ? { segments: [], treePaths: tree.treePaths } : undefined;\n },\n\n /**\n * Prepare all navigation-owned state for a new page — without publishing\n * any of it. Every code path that changes the \"current page\" must go\n * through this function, which is what makes \"forgot a field\" impossible\n * by construction.\n *\n * Returns the destination's `NavigationState`, which is a pure function of\n * the URL and is what the incoming tree is *rendered* with, plus a\n * `commit` thunk that performs the writes that make a page current:\n * 1. Segment cache — update from server-provided segment metadata\n * 2. The current page's segment metadata (`committedSegmentInfo`)\n * 3. History stack — store the payload for instant back/forward replay\n *\n * Pathname and search are not written here: they are the returned\n * `navState`, which the tree renders with and the router's record of the\n * displayed tree keeps (browser-entry/router-init.ts `publishTree`).\n *\n * Nothing is written until `commit()` runs, and on a transitioned\n * navigation it runs only once the transition is known to have won — see\n * `renderViaTransition` and `NavigationRoot`. A navigation superseded\n * while its payload was in flight never calls it, so the cache, the\n * pathname the client reports and the history stack all keep describing\n * the route still on screen (TIM-1301).\n *\n * Callers with state of their own to publish — the address bar, the\n * client's record of the mounted tree — wrap this thunk rather than\n * commit beside it, so there stays exactly one moment at which a page\n * becomes current.\n */\n prepareNavigation(url: string, opts: NavigationCommitInput): PreparedNavigation {\n const navState = deriveNavigationState(url);\n const payload = isReplayable(opts) ? opts.payload : null;\n\n // The tree this navigation renders has not rendered yet. Whatever a\n // boundary reported before now belongs to a commit that had no\n // navigation to consume it — a hydration, a row that arrived inside a\n // Suspense boundary after its navigation had published — and must not\n // be charged to this one.\n _setStatusPageRendered(false);\n\n return {\n navState,\n commit() {\n // A tree in which a boundary rendered a status page is not one to\n // cache — see the module note. Read at commit rather than at\n // prepare because that is when the boundary has spoken: the row it\n // renders may not have existed when the response headers were read.\n // The history entry records the same thing, or a traversal back to\n // this URL would replay the metadata this drops.\n const cacheable = !statusPageRendered;\n _setStatusPageRendered(false);\n const segmentInfo = cacheable ? opts.segmentInfo : [];\n\n if (segmentInfo && segmentInfo.length > 0) {\n updateSegmentCache(segmentInfo);\n } else if (segmentInfo?.length === 0 || opts.clearSegmentCacheOnEmpty) {\n segmentCache.clear();\n }\n\n committedSegmentInfo = storedSegmentInfo(segmentInfo) ?? null;\n\n historyStack.push(url, {\n payload,\n params: opts.params,\n segmentInfo: committedSegmentInfo,\n });\n },\n };\n },\n };\n}\n","'use client';\n\n/**\n * The one way a status page tells the router it is on screen.\n *\n * A status page replaces a subtree, and the segment cache must not learn a\n * chain that never mounted (see `navigation-commit.ts` §\"What a status page\n * teaches the cache\"). Status pages are produced in three places — an\n * in-tree catch site rendering the page it owns, the server's fallback\n * renderers, and a client boundary rendering its fallback for a Flight row —\n * and every one of them wraps the page in this marker, so the report does\n * not depend on which producer it was. In particular the in-tree case, the\n * common `access.ts` deny, never involves a client boundary at all.\n *\n * A layout effect, on every commit that renders the marker rather than on\n * mount only: React reuses the fiber when one status page is replaced by\n * another at the same position, and the second one must report too. Layout\n * effects run child-before-parent, so the report lands before the ancestor\n * `NavigationRoot` publishes the same commit, and never for a render React\n * discards. Idempotent, so StrictMode's double invocation and a status page\n * re-rendering on its own state are harmless. See TIM-1495.\n */\n\nimport { useLayoutEffect, type ReactNode } from 'react';\nimport { reportStatusPageRendered } from './navigation-commit.ts';\n\nexport function StatusPageMarker({ children }: { children: ReactNode }): ReactNode {\n useLayoutEffect(() => {\n reportStatusPageRendered();\n });\n return children;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as classifyUrlSegment } from "./segment-classify-C539Pa2O.js";
|
|
2
2
|
import { t as readFileCached } from "./file-cache-Dw6BJPG7.js";
|
|
3
|
-
import { n as findSchemaFile, r as parseExistingSchemaKeys } from "./cli-schema-sync
|
|
3
|
+
import { n as findSchemaFile, r as parseExistingSchemaKeys } from "./cli-schema-sync-CbT2AUUI.js";
|
|
4
4
|
//#region src/routing/schema-validation.ts
|
|
5
5
|
/**
|
|
6
6
|
* Schema key/value validation against the filesystem route tree.
|
|
@@ -141,4 +141,4 @@ function walk(node, chain, result, includeSlots) {
|
|
|
141
141
|
//#endregion
|
|
142
142
|
export { collectDynamicSegmentsFromTree as n, validateSchemaAgainstRoutes as r, collectLeafRoutes as t };
|
|
143
143
|
|
|
144
|
-
//# sourceMappingURL=walkers-
|
|
144
|
+
//# sourceMappingURL=walkers-BXExhzzk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walkers-CN2N_bA-.js","names":[],"sources":["../../src/routing/schema-validation.ts","../../src/routing/walkers.ts"],"sourcesContent":["/**\n * Schema key/value validation against the filesystem route tree.\n *\n * Runs at codegen time (build + dev) to catch mismatches between\n * app/schema.ts keys and the actual dynamic segments on disk.\n *\n * Design doc: design/41-global-params.md\n */\n\nimport { readFileCached } from './file-cache.ts';\nimport type { RouteTree, SegmentNode } from './types.ts';\nimport { findSchemaFile, parseExistingSchemaKeys } from '../cli-schema-sync.ts';\nimport { classifyUrlSegment } from './segment-classify.ts';\n\nexport interface SchemaWarning {\n type: 'stale-key' | 'missing-key' | 'bracket-mismatch';\n key: string;\n message: string;\n filesystemKey?: string;\n}\n\n/**\n * Collect all unique bracket-keyed dynamic segment names from a route tree.\n * Returns entries like '[artistSlug]', '[...slug]', '[[...topic]]'.\n */\nexport function collectDynamicSegmentsFromTree(tree: RouteTree): Set<string> {\n const segments = new Set<string>();\n walkTree(tree.root, segments);\n return segments;\n}\n\nfunction walkTree(node: SegmentNode, segments: Set<string>): void {\n if (node.paramName && node.segmentName) {\n const classified = classifyUrlSegment(node.segmentName);\n if (classified.kind !== 'static') {\n // Use bare bracket form for schema keys — affixed segments like\n // `img-[id].png` register as `[id]`, matching runtime codec lookup.\n if (classified.kind === 'dynamic' && (classified.prefix || classified.suffix)) {\n segments.add(`[${classified.name}]`);\n } else {\n segments.add(node.segmentName);\n }\n }\n }\n for (const child of node.children) {\n walkTree(child, segments);\n }\n for (const slot of Object.values(node.slots)) {\n walkTree(slot, segments);\n }\n}\n\n/**\n * Extract the param name from a bracket key.\n * '[id]' → 'id', '[...slug]' → 'slug', '[[...topic]]' → 'topic'\n */\nfunction extractParamName(bracketKey: string): string | null {\n const seg = classifyUrlSegment(bracketKey);\n if (seg.kind === 'static') return null;\n return seg.name;\n}\n\n/**\n * Validate schema keys against the filesystem route tree.\n *\n * Returns warnings for:\n * - Stale keys: schema keys that don't match any filesystem segment\n * - Bracket form mismatches: same param name, different bracket form\n * - Missing keys: filesystem segments not registered in schema (informational)\n */\nexport function validateSchemaAgainstRoutes(tree: RouteTree, appDir: string): SchemaWarning[] {\n const schemaPath = findSchemaFile(appDir);\n if (!schemaPath) return [];\n\n const content = readFileCached(schemaPath);\n const schemaKeys = parseExistingSchemaKeys(content);\n\n if (schemaKeys.length === 0) return [];\n\n const filesystemSegments = collectDynamicSegmentsFromTree(tree);\n\n return validateKeys(schemaKeys, filesystemSegments);\n}\n\n/**\n * Core validation: compare schema keys against filesystem segments.\n * Exported separately for testing without filesystem dependencies.\n */\nexport function validateKeys(\n schemaKeys: string[],\n filesystemSegments: Set<string>\n): SchemaWarning[] {\n const warnings: SchemaWarning[] = [];\n\n // Build a map of param name → bracket form for filesystem segments\n const fsParamToKey = new Map<string, string>();\n for (const fsKey of filesystemSegments) {\n const name = extractParamName(fsKey);\n if (name) {\n fsParamToKey.set(name, fsKey);\n }\n }\n\n // Build a set of schema param names for the missing-key check\n const schemaParamNames = new Set<string>();\n\n for (const schemaKey of schemaKeys) {\n const schemaParamName = extractParamName(schemaKey);\n if (!schemaParamName) continue;\n\n schemaParamNames.add(schemaParamName);\n\n if (filesystemSegments.has(schemaKey)) {\n // Exact match — no issue\n continue;\n }\n\n // Check if the param name exists but with a different bracket form\n const fsKey = fsParamToKey.get(schemaParamName);\n if (fsKey) {\n warnings.push({\n type: 'bracket-mismatch',\n key: schemaKey,\n filesystemKey: fsKey,\n message:\n `Schema key '${schemaKey}' does not match filesystem bracket form '${fsKey}'. ` +\n `Update the schema key to '${fsKey}'.`,\n });\n } else {\n warnings.push({\n type: 'stale-key',\n key: schemaKey,\n message:\n `Schema key '${schemaKey}' does not match any dynamic segment in the filesystem. ` +\n `Remove it from app/schema.ts or create the corresponding route segment.`,\n });\n }\n }\n\n // Check for filesystem segments not in schema (informational)\n for (const fsKey of filesystemSegments) {\n const name = extractParamName(fsKey);\n if (name && !schemaParamNames.has(name)) {\n warnings.push({\n type: 'missing-key',\n key: fsKey,\n message:\n `Dynamic segment '${fsKey}' has no codec in app/schema.ts (defaults to string). ` +\n `Run: timber schema sync`,\n });\n }\n }\n\n return warnings;\n}\n","/**\n * Shared route-tree walkers (TIM-848).\n *\n * Tiny helpers that walk a `SegmentNode<TFile>` tree generically. Both the\n * build-time tree (`SegmentNode<RouteFile>`) and the runtime manifest\n * tree (`SegmentNode<ManifestFile>`) flow through these helpers because\n * the walker only reads the structural fields shared by both shapes\n * (`children`, `slots`, `page`, `route`, `urlPath`).\n *\n * Before this module, three near-identical `collectRoutes` functions\n * lived in `plugins/dev-404-page.ts`, `plugins/build-report.ts`, and\n * `routing/codegen.ts`. The codegen one is special-purpose (it\n * accumulates `ParamEntry[]` and resolves codec chains) and stays\n * local; the other two now share `collectLeafRoutes` from this file.\n */\n\nimport type { SegmentNode } from './types.ts';\n\n/** A leaf route discovered while walking the segment tree. */\nexport interface LeafRoute<TFile> {\n /** URL path of the leaf (root is \"/\"). */\n urlPath: string;\n /** Segment chain from root to this leaf, inclusive. */\n segments: SegmentNode<TFile>[];\n /** The page file at this leaf, if any. */\n page?: TFile;\n /** The route handler file at this leaf, if any. */\n route?: TFile;\n}\n\n/** Options for `collectLeafRoutes`. */\nexport interface CollectLeafRoutesOptions {\n /**\n * If true, recurse into parallel slots and emit slot leaves alongside\n * the main route tree. Defaults to `false` because slots render\n * alongside their parent at the same URL and are not separately\n * URL-addressable. The build report excludes slots; route-listing\n * UIs that want to show \"all leaves with a page handler\" can opt in.\n */\n includeSlots?: boolean;\n}\n\n/**\n * Walk a segment tree and collect every leaf with a `page` or `route`\n * handler. Generic over `TFile` so it works on both the build-time\n * scanner output and the runtime manifest tree.\n *\n * - Pages and route handlers at the same URL produce two distinct\n * entries (the build report deduplicates by URL afterward).\n * - Parallel slots are skipped unless `includeSlots: true` (slots\n * share their parent's URL and are not addressable on their own).\n * - Intercepting subtrees are skipped unconditionally. They render only\n * on soft navigation and add no URL depth, so their computed `urlPath`s\n * are not addresses — listing them would advertise routes (`/[year]`)\n * that no request can reach. This matches every other consumer of the\n * tree that produces URLs: the sitemap generator, the static generator,\n * prerendering and the prebuilt-payload builder all skip them too.\n * - Result is sorted by `urlPath` for deterministic output.\n */\nexport function collectLeafRoutes<TFile>(\n root: SegmentNode<TFile>,\n options: CollectLeafRoutesOptions = {}\n): LeafRoute<TFile>[] {\n const { includeSlots = false } = options;\n const result: LeafRoute<TFile>[] = [];\n walk(root, [], result, includeSlots);\n result.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n return result;\n}\n\nfunction walk<TFile>(\n node: SegmentNode<TFile>,\n chain: SegmentNode<TFile>[],\n result: LeafRoute<TFile>[],\n includeSlots: boolean\n): void {\n if (node.segmentType === 'intercepting') return;\n\n const currentChain = [...chain, node];\n const path = node.urlPath || '/';\n\n if (node.page) {\n result.push({ urlPath: path, segments: currentChain, page: node.page });\n }\n if (node.route) {\n result.push({ urlPath: path, segments: currentChain, route: node.route });\n }\n\n for (const child of node.children) {\n walk(child, currentChain, result, includeSlots);\n }\n\n if (includeSlots) {\n for (const slotNode of Object.values(node.slots)) {\n walk(slotNode, currentChain, result, includeSlots);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"walkers-BXExhzzk.js","names":[],"sources":["../../src/routing/schema-validation.ts","../../src/routing/walkers.ts"],"sourcesContent":["/**\n * Schema key/value validation against the filesystem route tree.\n *\n * Runs at codegen time (build + dev) to catch mismatches between\n * app/schema.ts keys and the actual dynamic segments on disk.\n *\n * Design doc: design/41-global-params.md\n */\n\nimport { readFileCached } from './file-cache.ts';\nimport type { RouteTree, SegmentNode } from './types.ts';\nimport { findSchemaFile, parseExistingSchemaKeys } from '../cli-schema-sync.ts';\nimport { classifyUrlSegment } from './segment-classify.ts';\n\nexport interface SchemaWarning {\n type: 'stale-key' | 'missing-key' | 'bracket-mismatch';\n key: string;\n message: string;\n filesystemKey?: string;\n}\n\n/**\n * Collect all unique bracket-keyed dynamic segment names from a route tree.\n * Returns entries like '[artistSlug]', '[...slug]', '[[...topic]]'.\n */\nexport function collectDynamicSegmentsFromTree(tree: RouteTree): Set<string> {\n const segments = new Set<string>();\n walkTree(tree.root, segments);\n return segments;\n}\n\nfunction walkTree(node: SegmentNode, segments: Set<string>): void {\n if (node.paramName && node.segmentName) {\n const classified = classifyUrlSegment(node.segmentName);\n if (classified.kind !== 'static') {\n // Use bare bracket form for schema keys — affixed segments like\n // `img-[id].png` register as `[id]`, matching runtime codec lookup.\n if (classified.kind === 'dynamic' && (classified.prefix || classified.suffix)) {\n segments.add(`[${classified.name}]`);\n } else {\n segments.add(node.segmentName);\n }\n }\n }\n for (const child of node.children) {\n walkTree(child, segments);\n }\n for (const slot of Object.values(node.slots)) {\n walkTree(slot, segments);\n }\n}\n\n/**\n * Extract the param name from a bracket key.\n * '[id]' → 'id', '[...slug]' → 'slug', '[[...topic]]' → 'topic'\n */\nfunction extractParamName(bracketKey: string): string | null {\n const seg = classifyUrlSegment(bracketKey);\n if (seg.kind === 'static') return null;\n return seg.name;\n}\n\n/**\n * Validate schema keys against the filesystem route tree.\n *\n * Returns warnings for:\n * - Stale keys: schema keys that don't match any filesystem segment\n * - Bracket form mismatches: same param name, different bracket form\n * - Missing keys: filesystem segments not registered in schema (informational)\n */\nexport function validateSchemaAgainstRoutes(tree: RouteTree, appDir: string): SchemaWarning[] {\n const schemaPath = findSchemaFile(appDir);\n if (!schemaPath) return [];\n\n const content = readFileCached(schemaPath);\n const schemaKeys = parseExistingSchemaKeys(content);\n\n if (schemaKeys.length === 0) return [];\n\n const filesystemSegments = collectDynamicSegmentsFromTree(tree);\n\n return validateKeys(schemaKeys, filesystemSegments);\n}\n\n/**\n * Core validation: compare schema keys against filesystem segments.\n * Exported separately for testing without filesystem dependencies.\n */\nexport function validateKeys(\n schemaKeys: string[],\n filesystemSegments: Set<string>\n): SchemaWarning[] {\n const warnings: SchemaWarning[] = [];\n\n // Build a map of param name → bracket form for filesystem segments\n const fsParamToKey = new Map<string, string>();\n for (const fsKey of filesystemSegments) {\n const name = extractParamName(fsKey);\n if (name) {\n fsParamToKey.set(name, fsKey);\n }\n }\n\n // Build a set of schema param names for the missing-key check\n const schemaParamNames = new Set<string>();\n\n for (const schemaKey of schemaKeys) {\n const schemaParamName = extractParamName(schemaKey);\n if (!schemaParamName) continue;\n\n schemaParamNames.add(schemaParamName);\n\n if (filesystemSegments.has(schemaKey)) {\n // Exact match — no issue\n continue;\n }\n\n // Check if the param name exists but with a different bracket form\n const fsKey = fsParamToKey.get(schemaParamName);\n if (fsKey) {\n warnings.push({\n type: 'bracket-mismatch',\n key: schemaKey,\n filesystemKey: fsKey,\n message:\n `Schema key '${schemaKey}' does not match filesystem bracket form '${fsKey}'. ` +\n `Update the schema key to '${fsKey}'.`,\n });\n } else {\n warnings.push({\n type: 'stale-key',\n key: schemaKey,\n message:\n `Schema key '${schemaKey}' does not match any dynamic segment in the filesystem. ` +\n `Remove it from app/schema.ts or create the corresponding route segment.`,\n });\n }\n }\n\n // Check for filesystem segments not in schema (informational)\n for (const fsKey of filesystemSegments) {\n const name = extractParamName(fsKey);\n if (name && !schemaParamNames.has(name)) {\n warnings.push({\n type: 'missing-key',\n key: fsKey,\n message:\n `Dynamic segment '${fsKey}' has no codec in app/schema.ts (defaults to string). ` +\n `Run: timber schema sync`,\n });\n }\n }\n\n return warnings;\n}\n","/**\n * Shared route-tree walkers (TIM-848).\n *\n * Tiny helpers that walk a `SegmentNode<TFile>` tree generically. Both the\n * build-time tree (`SegmentNode<RouteFile>`) and the runtime manifest\n * tree (`SegmentNode<ManifestFile>`) flow through these helpers because\n * the walker only reads the structural fields shared by both shapes\n * (`children`, `slots`, `page`, `route`, `urlPath`).\n *\n * Before this module, three near-identical `collectRoutes` functions\n * lived in `plugins/dev-404-page.ts`, `plugins/build-report.ts`, and\n * `routing/codegen.ts`. The codegen one is special-purpose (it\n * accumulates `ParamEntry[]` and resolves codec chains) and stays\n * local; the other two now share `collectLeafRoutes` from this file.\n */\n\nimport type { SegmentNode } from './types.ts';\n\n/** A leaf route discovered while walking the segment tree. */\nexport interface LeafRoute<TFile> {\n /** URL path of the leaf (root is \"/\"). */\n urlPath: string;\n /** Segment chain from root to this leaf, inclusive. */\n segments: SegmentNode<TFile>[];\n /** The page file at this leaf, if any. */\n page?: TFile;\n /** The route handler file at this leaf, if any. */\n route?: TFile;\n}\n\n/** Options for `collectLeafRoutes`. */\nexport interface CollectLeafRoutesOptions {\n /**\n * If true, recurse into parallel slots and emit slot leaves alongside\n * the main route tree. Defaults to `false` because slots render\n * alongside their parent at the same URL and are not separately\n * URL-addressable. The build report excludes slots; route-listing\n * UIs that want to show \"all leaves with a page handler\" can opt in.\n */\n includeSlots?: boolean;\n}\n\n/**\n * Walk a segment tree and collect every leaf with a `page` or `route`\n * handler. Generic over `TFile` so it works on both the build-time\n * scanner output and the runtime manifest tree.\n *\n * - Pages and route handlers at the same URL produce two distinct\n * entries (the build report deduplicates by URL afterward).\n * - Parallel slots are skipped unless `includeSlots: true` (slots\n * share their parent's URL and are not addressable on their own).\n * - Intercepting subtrees are skipped unconditionally. They render only\n * on soft navigation and add no URL depth, so their computed `urlPath`s\n * are not addresses — listing them would advertise routes (`/[year]`)\n * that no request can reach. This matches every other consumer of the\n * tree that produces URLs: the sitemap generator, the static generator,\n * prerendering and the prebuilt-payload builder all skip them too.\n * - Result is sorted by `urlPath` for deterministic output.\n */\nexport function collectLeafRoutes<TFile>(\n root: SegmentNode<TFile>,\n options: CollectLeafRoutesOptions = {}\n): LeafRoute<TFile>[] {\n const { includeSlots = false } = options;\n const result: LeafRoute<TFile>[] = [];\n walk(root, [], result, includeSlots);\n result.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n return result;\n}\n\nfunction walk<TFile>(\n node: SegmentNode<TFile>,\n chain: SegmentNode<TFile>[],\n result: LeafRoute<TFile>[],\n includeSlots: boolean\n): void {\n if (node.segmentType === 'intercepting') return;\n\n const currentChain = [...chain, node];\n const path = node.urlPath || '/';\n\n if (node.page) {\n result.push({ urlPath: path, segments: currentChain, page: node.page });\n }\n if (node.route) {\n result.push({ urlPath: path, segments: currentChain, route: node.route });\n }\n\n for (const child of node.children) {\n walk(child, currentChain, result, includeSlots);\n }\n\n if (includeSlots) {\n for (const slotNode of Object.values(node.slots)) {\n walk(slotNode, currentChain, result, includeSlots);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
//#region src/utils/write-file-atomic.ts
|
|
4
|
+
/**
|
|
5
|
+
* Replace a file's contents in one step: write a uniquely named temp sibling,
|
|
6
|
+
* then `rename()` it over the target.
|
|
7
|
+
*
|
|
8
|
+
* `writeFile()` opens its target with `O_TRUNC`, so for the length of the write
|
|
9
|
+
* a concurrent reader sees an empty or half-written file under the real name.
|
|
10
|
+
* `rename()` within one directory swaps the name atomically, so a reader sees
|
|
11
|
+
* either the old file or the new one — never a torn one — and a crashed
|
|
12
|
+
* writer leaves no partial artifact under the final name.
|
|
13
|
+
*
|
|
14
|
+
* The temp name is unique per call, not a fixed `${path}.tmp`: two writers of
|
|
15
|
+
* the same path (a dev server and a `vite build` rewriting the same route
|
|
16
|
+
* types, parallel CLI invocations sharing a cache) would otherwise write into
|
|
17
|
+
* one temp file and rename each other's half-written bytes into place.
|
|
18
|
+
*/
|
|
19
|
+
async function writeFileAtomic(path, data) {
|
|
20
|
+
const tmp = `${path}.${randomUUID()}.tmp`;
|
|
21
|
+
try {
|
|
22
|
+
await writeFile(tmp, data);
|
|
23
|
+
await rename(tmp, path);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
await rm(tmp, { force: true }).catch(() => {});
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { writeFileAtomic as t };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=write-file-atomic-D1qWqHb4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-file-atomic-D1qWqHb4.js","names":[],"sources":["../../src/utils/write-file-atomic.ts"],"sourcesContent":["/**\n * Replace a file's contents in one step: write a uniquely named temp sibling,\n * then `rename()` it over the target.\n *\n * `writeFile()` opens its target with `O_TRUNC`, so for the length of the write\n * a concurrent reader sees an empty or half-written file under the real name.\n * `rename()` within one directory swaps the name atomically, so a reader sees\n * either the old file or the new one — never a torn one — and a crashed\n * writer leaves no partial artifact under the final name.\n *\n * The temp name is unique per call, not a fixed `${path}.tmp`: two writers of\n * the same path (a dev server and a `vite build` rewriting the same route\n * types, parallel CLI invocations sharing a cache) would otherwise write into\n * one temp file and rename each other's half-written bytes into place.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { rename, rm, writeFile } from 'node:fs/promises';\n\nexport async function writeFileAtomic(path: string, data: Uint8Array | string): Promise<void> {\n const tmp = `${path}.${randomUUID()}.tmp`;\n try {\n await writeFile(tmp, data);\n await rename(tmp, path);\n } catch (err) {\n // Best-effort cleanup. If the directory refuses the write it may refuse\n // the rm too, and that error — naming a random temp path — must not\n // replace the one that says what actually failed.\n await rm(tmp, { force: true }).catch(() => {});\n throw err;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,eAAsB,gBAAgB,MAAc,MAA0C;CAC5F,MAAM,MAAM,GAAG,KAAK,GAAG,WAAW,EAAE;CACpC,IAAI;EACF,MAAM,UAAU,KAAK,IAAI;EACzB,MAAM,OAAO,KAAK,IAAI;CACxB,SAAS,KAAK;EAIZ,MAAM,GAAG,KAAK,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;EAC7C,MAAM;CACR;AACF"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { TimberConfig } from './types.ts';
|
|
1
|
+
import type { BuildArtifacts, ServerBuildArtifacts, StaticBuildArtifacts, TimberConfig } from './types.ts';
|
|
2
2
|
/** Options for the shared build output steps. */
|
|
3
3
|
export interface BuildOutputBaseOptions {
|
|
4
4
|
/** Resolved timber config. */
|
|
5
5
|
config: TimberConfig;
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
/** Adapter-specific output directory (e.g. `.timber/
|
|
6
|
+
/** What the build produced. */
|
|
7
|
+
artifacts: ServerBuildArtifacts;
|
|
8
|
+
/** Adapter-specific output directory (e.g. `.timber/dist/nitro`). */
|
|
9
9
|
outDir: string;
|
|
10
10
|
/**
|
|
11
11
|
* Name of the public/static directory within outDir.
|
|
@@ -25,13 +25,13 @@ export interface BuildOutputBaseOptions {
|
|
|
25
25
|
* Returns the resolved public directory path for further adapter-specific use.
|
|
26
26
|
*/
|
|
27
27
|
export declare function runSharedBuildSteps(opts: BuildOutputBaseOptions): Promise<string>;
|
|
28
|
-
export declare function findUnhashedStaticFiles(publicDir: string): Promise<string[]>;
|
|
28
|
+
export declare function findUnhashedStaticFiles(publicDir: string, immutableDirs: readonly string[]): Promise<string[]>;
|
|
29
29
|
/**
|
|
30
30
|
* Build a static-only output directory (no server entry). Copies client
|
|
31
31
|
* assets and pre-rendered HTML/RSC/API files into `outDir/publicDirName`.
|
|
32
32
|
* Used by both Cloudflare and Nitro adapters in `output: 'static'` mode.
|
|
33
33
|
*/
|
|
34
|
-
export declare function buildStaticDirectoryOutput(config: TimberConfig,
|
|
34
|
+
export declare function buildStaticDirectoryOutput(config: TimberConfig, artifacts: StaticBuildArtifacts, outDir: string, publicDirName: string): Promise<void>;
|
|
35
35
|
/**
|
|
36
36
|
* Write the `_headers` file, folding in the user's `public/_headers`.
|
|
37
37
|
*
|
|
@@ -57,7 +57,7 @@ export declare function buildStaticDirectoryOutput(config: TimberConfig, buildDi
|
|
|
57
57
|
*
|
|
58
58
|
* @internal Exported for testing.
|
|
59
59
|
*/
|
|
60
|
-
export declare function writeHeadersFile(dir: string, config: TimberConfig,
|
|
60
|
+
export declare function writeHeadersFile(dir: string, config: TimberConfig, artifacts: BuildArtifacts): Promise<void>;
|
|
61
61
|
/**
|
|
62
62
|
* Throw if copying `srcDir` over `destDir` would overwrite an existing file.
|
|
63
63
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-output-helper.d.ts","sourceRoot":"","sources":["../../src/adapters/build-output-helper.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"build-output-helper.d.ts","sourceRoot":"","sources":["../../src/adapters/build-output-helper.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,MAAM,EAAE,YAAY,CAAC;IACrB,+BAA+B;IAC/B,SAAS,EAAE,oBAAoB,CAAC;IAChC,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsDvF;AA8BD,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnB;AA2BD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,oBAAoB,EAC/B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,IAAI,CAAC,CAcf;AAoBD;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B1F"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile server/canonicalize.ts into a standalone ESM module exporting
|
|
3
|
+
* `canonicalize`.
|
|
4
|
+
*
|
|
5
|
+
* @internal Exported for testing.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateCanonicalizeModule(): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=canonicalize-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonicalize-module.d.ts","sourceRoot":"","sources":["../../src/adapters/canonicalize-module.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC,CAQlE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as warnLossyJsonValue } from "../_chunks/json-lossy-check-
|
|
2
|
-
import { l as getCloudflareBindings } from "../_chunks/cloudflare-
|
|
1
|
+
import { t as warnLossyJsonValue } from "../_chunks/json-lossy-check-ip0Qi0MT.js";
|
|
2
|
+
import { l as getCloudflareBindings } from "../_chunks/cloudflare-Byxl8FWP.js";
|
|
3
3
|
//#region src/adapters/cloudflare-kv-cache.ts
|
|
4
4
|
var LEGACY_GRACE_MS = 2592e6;
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TimberPlatformAdapter, TimberConfig } from './types.ts';
|
|
1
|
+
import type { PreviewTarget, StaticBuildArtifacts, TimberPlatformAdapter, TimberConfig } from './types.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Get Cloudflare Worker bindings for the current request.
|
|
4
4
|
*
|
|
@@ -160,7 +160,7 @@ export interface CloudflareAdapterOptions {
|
|
|
160
160
|
*/
|
|
161
161
|
export declare function cloudflare(options?: CloudflareAdapterOptions): TimberPlatformAdapter;
|
|
162
162
|
/** @internal Exported for testing. */
|
|
163
|
-
export declare function generateWorkerEntry(
|
|
163
|
+
export declare function generateWorkerEntry(hasManifestInit?: boolean, hasWorkerHandlers?: boolean): string;
|
|
164
164
|
/** Build-time prebuilt data read from `.timber/dist/prebuilt/`. */
|
|
165
165
|
export interface PrebuiltModuleData {
|
|
166
166
|
/** Raw manifest.json content. */
|
|
@@ -172,12 +172,13 @@ export interface PrebuiltModuleData {
|
|
|
172
172
|
}>;
|
|
173
173
|
}
|
|
174
174
|
/**
|
|
175
|
-
*
|
|
176
|
-
*
|
|
175
|
+
* Read the prebuilt flight payloads the capture pass wrote. Called only
|
|
176
|
+
* when the build produced a `prebuilt` artifact, which always carries its
|
|
177
|
+
* `manifest.json` — so a read failure here is a real error, not absence.
|
|
177
178
|
*
|
|
178
179
|
* @internal Exported for testing.
|
|
179
180
|
*/
|
|
180
|
-
export declare function readPrebuiltData(
|
|
181
|
+
export declare function readPrebuiltData(prebuiltDir: string): Promise<PrebuiltModuleData>;
|
|
181
182
|
/**
|
|
182
183
|
* Generate the prebuilt payload source module for Cloudflare Workers.
|
|
183
184
|
*
|
|
@@ -253,15 +254,36 @@ export declare function generateWranglerConfig(config: TimberConfig, options: Cl
|
|
|
253
254
|
*
|
|
254
255
|
* @internal Exported for testing.
|
|
255
256
|
*/
|
|
256
|
-
export declare function buildStaticOutput(config: TimberConfig,
|
|
257
|
+
export declare function buildStaticOutput(config: TimberConfig, artifacts: StaticBuildArtifacts, outDir: string, _options: CloudflareAdapterOptions): Promise<void>;
|
|
257
258
|
/** Command descriptor for preview — testable without spawning a process. */
|
|
258
259
|
export interface PreviewCommand {
|
|
259
260
|
command: string;
|
|
260
261
|
args: string[];
|
|
261
262
|
cwd: string;
|
|
262
263
|
}
|
|
263
|
-
/**
|
|
264
|
-
|
|
264
|
+
/**
|
|
265
|
+
* A server build runs its Worker under `wrangler dev` with the generated
|
|
266
|
+
* wrangler.jsonc. A static build writes no Worker and no wrangler.jsonc — its
|
|
267
|
+
* output is a Pages directory (`_headers`, `_redirects`, the site) — so it
|
|
268
|
+
* is served by `wrangler pages dev`, which applies those files as Pages does.
|
|
269
|
+
*
|
|
270
|
+
* @internal Exported for testing.
|
|
271
|
+
*/
|
|
272
|
+
export declare function generatePreviewCommand({ output, outputDir }: PreviewTarget, pagesRoot?: string): PreviewCommand;
|
|
273
|
+
/**
|
|
274
|
+
* Stage a static Cloudflare build for `wrangler pages dev` under a non-root
|
|
275
|
+
* base. The build writes the site at the directory root (a Pages project is
|
|
276
|
+
* served at its domain root, and the base path is supplied by whatever routes
|
|
277
|
+
* to it), but its HTML requests `/repo/...` and its `_headers`/`_redirects`
|
|
278
|
+
* rules are base-prefixed. Serving the directory as-is would 404 every page
|
|
279
|
+
* and asset, so the preview mounts the site at the base and keeps the rule
|
|
280
|
+
* files at the root, where Pages reads them and where their prefixed
|
|
281
|
+
* patterns match.
|
|
282
|
+
*
|
|
283
|
+
* @param base Normalized deployment base, not `/`.
|
|
284
|
+
* @internal Exported for testing.
|
|
285
|
+
*/
|
|
286
|
+
export declare function stagePagesPreview(siteDir: string, base: string, stageDir: string): Promise<void>;
|
|
265
287
|
/** @internal Minimal stub — use @cloudflare/workers-types for full types. */
|
|
266
288
|
export interface CfExecutionContext {
|
|
267
289
|
waitUntil(promise: Promise<unknown>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as generatePreviewCommand, c as generateWranglerConfig, d as readUserWranglerConfig, f as runWithBindings, i as generatePrebuiltSourceModule, l as getCloudflareBindings, n as cloudflare, o as generateRuntimeInitModule, r as generateBindingsConfig, s as generateWorkerEntry, t as buildStaticOutput, u as readPrebuiltData } from "../_chunks/cloudflare-
|
|
2
|
-
export { buildStaticOutput, cloudflare, generateBindingsConfig, generatePrebuiltSourceModule, generatePreviewCommand, generateRuntimeInitModule, generateWorkerEntry, generateWranglerConfig, getCloudflareBindings, readPrebuiltData, readUserWranglerConfig, runWithBindings };
|
|
1
|
+
import { a as generatePreviewCommand, c as generateWranglerConfig, d as readUserWranglerConfig, f as runWithBindings, i as generatePrebuiltSourceModule, l as getCloudflareBindings, n as cloudflare, o as generateRuntimeInitModule, p as stagePagesPreview, r as generateBindingsConfig, s as generateWorkerEntry, t as buildStaticOutput, u as readPrebuiltData } from "../_chunks/cloudflare-Byxl8FWP.js";
|
|
2
|
+
export { buildStaticOutput, cloudflare, generateBindingsConfig, generatePrebuiltSourceModule, generatePreviewCommand, generateRuntimeInitModule, generateWorkerEntry, generateWranglerConfig, getCloudflareBindings, readPrebuiltData, readUserWranglerConfig, runWithBindings, stagePagesPreview };
|
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
* @internal Exported for testing.
|
|
11
11
|
*/
|
|
12
12
|
export declare function inlineCompressImports(code: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Throw if type-stripped server source still imports anything but a Node
|
|
15
|
+
* builtin. Such a module is emitted alone into the build output, where no
|
|
16
|
+
* specifier has anything to resolve to.
|
|
17
|
+
*
|
|
18
|
+
* @internal Shared by the standalone-module generators.
|
|
19
|
+
*/
|
|
20
|
+
export declare function assertStandalone(code: string, source: string, emitted: string): void;
|
|
13
21
|
/**
|
|
14
22
|
* Compile server/compress.ts into a standalone ESM module.
|
|
15
23
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress-module.d.ts","sourceRoot":"","sources":["../../src/adapters/compress-module.ts"],"names":[],"mappings":"AAkEA;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"compress-module.d.ts","sourceRoot":"","sources":["../../src/adapters/compress-module.ts"],"names":[],"mappings":"AAkEA;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAUpF;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU9D"}
|
|
@@ -21,9 +21,8 @@
|
|
|
21
21
|
* macOS and a case-insensitive mount on Linux are both ordinary, and the
|
|
22
22
|
* answer that matters is the one for the directory being written.
|
|
23
23
|
*
|
|
24
|
-
* Leaf module — Node built-ins only.
|
|
25
|
-
*
|
|
26
|
-
* stay free of `node:fs` for the Workers bundle.
|
|
24
|
+
* Leaf module — Node built-ins only. Kept apart from `adapters/shared.ts`,
|
|
25
|
+
* whose rule builders are pure string functions: this one touches the disk.
|
|
27
26
|
*/
|
|
28
27
|
/** How the output filesystem decides that two paths name one file. */
|
|
29
28
|
export interface FsIdentity {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs-identity.d.ts","sourceRoot":"","sources":["../../src/adapters/fs-identity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fs-identity.d.ts","sourceRoot":"","sources":["../../src/adapters/fs-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,eAAe,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,wBAAwB,EAAE,OAAO,CAAC;IAClC;;;;OAIG;IACH,2BAA2B,EAAE,OAAO,CAAC;CACtC;AAED,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,EAAE,UAI/B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,MAAM,CAKhE"}
|
|
@@ -11,12 +11,6 @@ export interface PresetConfig {
|
|
|
11
11
|
nitroPreset: string;
|
|
12
12
|
/** Output directory name within the build dir. */
|
|
13
13
|
outputDir: string;
|
|
14
|
-
/**
|
|
15
|
-
* Path to the server bundle directory relative to outputDir.
|
|
16
|
-
* Nitro places the bundled server entry + _chunks/ here.
|
|
17
|
-
* Most presets use `server`; Vercel uses `functions/__server.func`.
|
|
18
|
-
*/
|
|
19
|
-
serverBundleDir: string;
|
|
20
14
|
/** Whether the runtime supports waitUntil. */
|
|
21
15
|
supportsWaitUntil: boolean;
|
|
22
16
|
/** Whether the runtime supports application-level 103 Early Hints. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nitro-presets.d.ts","sourceRoot":"","sources":["../../src/adapters/nitro-presets.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,aAAa,GACb,SAAS,GACT,cAAc,GACd,YAAY,GACZ,aAAa,GACb,iBAAiB,GACjB,aAAa,GACb,KAAK,CAAC;AAEV,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB
|
|
1
|
+
{"version":3,"file":"nitro-presets.d.ts","sourceRoot":"","sources":["../../src/adapters/nitro-presets.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,aAAa,GACb,SAAS,GACT,cAAc,GACd,YAAY,GACZ,aAAa,GACb,iBAAiB,GACjB,aAAa,GACb,KAAK,CAAC;AAEV,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,iBAAiB,EAAE,OAAO,CAAC;IAC3B,sEAAsE;IACtE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,WAAW,EAAE,YAAY,CA0E5D,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,kBAA+C,CAAC;AAEhF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAEjE"}
|
|
@@ -1,21 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
/** What the generated preview server serves, as `buildOutput` knows it. */
|
|
2
|
+
export type PreviewScriptOptions = StaticPreviewScriptOptions | ServerPreviewScriptOptions;
|
|
3
|
+
interface PreviewScriptOptionsBase {
|
|
4
|
+
/**
|
|
5
|
+
* `BuildArtifacts.immutableDirs` — served with a one-year immutable
|
|
6
|
+
* `Cache-Control`, every other file with a revalidating one.
|
|
7
|
+
*/
|
|
8
|
+
immutableDirs: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The deployment base, normalized (`/` or `/repo/`). Requests arrive in
|
|
11
|
+
* deployed-URL space; files are laid out in route space, so the script
|
|
12
|
+
* strips it before looking anything up.
|
|
13
|
+
*/
|
|
14
|
+
base: string;
|
|
15
|
+
}
|
|
16
|
+
/** A static build: serve the pre-rendered site and nothing else. */
|
|
17
|
+
export interface StaticPreviewScriptOptions extends PreviewScriptOptionsBase {
|
|
18
|
+
output: 'static';
|
|
19
|
+
/** `StaticBuildArtifacts.contentTypes` — extensionless API route outputs. */
|
|
20
|
+
contentTypes: Readonly<Record<string, string>>;
|
|
21
|
+
}
|
|
22
|
+
/** A server build: serve `public/`, route everything else to the RSC handler. */
|
|
23
|
+
export interface ServerPreviewScriptOptions extends PreviewScriptOptionsBase {
|
|
24
|
+
output: 'server';
|
|
25
|
+
/** Value for `TIMBER_RUNTIME`, set before the handler evaluates. */
|
|
26
|
+
runtimeName: string;
|
|
27
|
+
/** Import specifier of the RSC handler, relative to the script. */
|
|
28
|
+
rscEntry: string;
|
|
29
|
+
/**
|
|
30
|
+
* Whether this build wrote `_timber-manifest-init.js` beside the script.
|
|
31
|
+
* Recorded from the build, never probed: the Nitro output directory is not
|
|
32
|
+
* cleaned between server builds, so a file on disk can be a stale one.
|
|
33
|
+
*/
|
|
34
|
+
hasManifestInit: boolean;
|
|
35
|
+
}
|
|
2
36
|
/**
|
|
3
37
|
* Generate a standalone preview server script that uses Node's built-in
|
|
4
38
|
* HTTP server. This bypasses Nitro entirely — the Nitro entry.ts imports
|
|
5
39
|
* h3 which isn't available outside a Nitro build. For local preview we
|
|
6
|
-
* just need to serve static files and
|
|
40
|
+
* just need to serve static files and, in a server build, route requests
|
|
41
|
+
* to the RSC handler.
|
|
42
|
+
*
|
|
43
|
+
* Generated at build time rather than at preview time, so everything it
|
|
44
|
+
* serves comes from the build's artifacts instead of guesses about the
|
|
45
|
+
* directory it runs in.
|
|
7
46
|
*
|
|
8
47
|
* @internal Exported for testing.
|
|
9
48
|
*/
|
|
10
|
-
export declare function generatePreviewScript(
|
|
11
|
-
/** Command descriptor for Nitro preview — testable without spawning. */
|
|
12
|
-
export interface NitroPreviewCommand {
|
|
13
|
-
command: string;
|
|
14
|
-
args: string[];
|
|
15
|
-
cwd: string;
|
|
16
|
-
}
|
|
17
|
-
/** @internal Exported for testing. */
|
|
18
|
-
export declare function generateNitroPreviewCommand(buildDir: string, preset: NitroPreset): NitroPreviewCommand | null;
|
|
49
|
+
export declare function generatePreviewScript(options: PreviewScriptOptions): string;
|
|
19
50
|
/** Spawn a Nitro preview process and pipe stdio. */
|
|
20
51
|
export declare function spawnNitroPreview(command: string, args: string[], cwd: string): Promise<void>;
|
|
21
52
|
/**
|
|
@@ -29,4 +60,5 @@ export declare function spawnNitroPreview(command: string, args: string[], cwd:
|
|
|
29
60
|
* @internal Exported for testing.
|
|
30
61
|
*/
|
|
31
62
|
export declare function generateSendResponseModule(): string;
|
|
63
|
+
export {};
|
|
32
64
|
//# sourceMappingURL=nitro-preview.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nitro-preview.d.ts","sourceRoot":"","sources":["../../src/adapters/nitro-preview.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nitro-preview.d.ts","sourceRoot":"","sources":["../../src/adapters/nitro-preview.ts"],"names":[],"mappings":"AAuEA,2EAA2E;AAC3E,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,0BAA0B,CAAC;AAE3F,UAAU,wBAAwB;IAChC;;;OAGG;IACH,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oEAAoE;AACpE,MAAM,WAAW,0BAA2B,SAAQ,wBAAwB;IAC1E,MAAM,EAAE,QAAQ,CAAC;IACjB,6EAA6E;IAC7E,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,iFAAiF;AACjF,MAAM,WAAW,0BAA2B,SAAQ,wBAAwB;IAC1E,MAAM,EAAE,QAAQ,CAAC;IACjB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAiR3E;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAuDnD"}
|
package/dist/adapters/nitro.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface NitroAdapterOptions {
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function nitro(options?: NitroAdapterOptions): TimberPlatformAdapter;
|
|
64
64
|
/** @internal Exported for testing. */
|
|
65
|
-
export declare function generateNitroEntry(
|
|
65
|
+
export declare function generateNitroEntry(preset: NitroPreset, compress?: boolean): string;
|
|
66
66
|
/** @internal Exported for testing. */
|
|
67
67
|
export declare function isSuppressedNitroHint(message: unknown, prefixes?: readonly string[]): boolean;
|
|
68
68
|
/**
|
|
@@ -100,18 +100,6 @@ export declare function wrapNitroLoggerForBuild(logger: NitroBuildLogger, prefix
|
|
|
100
100
|
* @internal Exported for testing.
|
|
101
101
|
*/
|
|
102
102
|
export declare function getPostBuildHint(preset: NitroPreset): string | null;
|
|
103
|
-
/**
|
|
104
|
-
* Resolve the destination path for prebuilt flight payloads in the Nitro
|
|
105
|
-
* output directory. The RSC entry resolves `../prebuilt/` relative to its
|
|
106
|
-
* bundled chunk location (`<serverBundleDir>/_chunks/`), so prebuilt/ must
|
|
107
|
-
* live at `<serverBundleDir>/prebuilt/`.
|
|
108
|
-
*
|
|
109
|
-
* The serverBundleDir varies by preset — Nitro's Vercel preset uses
|
|
110
|
-
* `functions/__server.func` while most others use `server`.
|
|
111
|
-
*
|
|
112
|
-
* @internal Exported for testing.
|
|
113
|
-
*/
|
|
114
|
-
export declare function resolvePrebuiltOutputPath(outDir: string, preset: NitroPreset): string;
|
|
115
103
|
/**
|
|
116
104
|
* Copy prebuilt payloads into cloned Vercel function directories.
|
|
117
105
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nitro.d.ts","sourceRoot":"","sources":["../../src/adapters/nitro.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nitro.d.ts","sourceRoot":"","sources":["../../src/adapters/nitro.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAO3F,OAAO,KAAK,EAIV,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAIpB,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;AAEtD,qCAAqC;AACrC,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAE5B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,KAAK,CAAC,OAAO,GAAE,mBAAwB,GAAG,qBAAqB,CAqK9E;AAgBD,sCAAsC;AACtC,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,UAAO,GAAG,MAAM,CAmF/E;AAkBD,sCAAsC;AACtC,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,QAAQ,GAAE,SAAS,MAAM,EAAmC,GAC3D,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,MAAM,EAAE,CAKX;AAED,4EAA4E;AAC5E,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACzD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,gBAAgB,EACxB,QAAQ,GAAE,SAAS,MAAM,EAAmC,GAC3D,gBAAgB,CAAC,SAAS,CAAC,CAS7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAInE;AAgFD;;;;;;;;;GASG;AACH,wBAAsB,8BAA8B,CAClD,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAcf"}
|