@timber-js/app 0.2.0-alpha.185 → 0.2.0-alpha.187
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/{actions-O_LsyCE4.js → actions-35jnMdeJ.js} +4 -3
- package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-35jnMdeJ.js.map} +1 -1
- package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
- package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
- package/dist/_chunks/base-path-DaQrzbez.js +80 -0
- package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/build-output-helper-C3DrfzZR.js +369 -0
- package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +1 -0
- package/dist/_chunks/{cache-api-B-lhk9p4.js → cache-api-DjNrIWRR.js} +8 -14
- package/dist/_chunks/cache-api-DjNrIWRR.js.map +1 -0
- package/dist/_chunks/cli-check-CpmN7Nh-.js +256 -0
- package/dist/_chunks/cli-check-CpmN7Nh-.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-CGMp_Psg.js +298 -0
- package/dist/_chunks/cli-schema-sync-CGMp_Psg.js.map +1 -0
- package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-CGP6BZKO.js} +92 -14
- package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-CGP6BZKO.js.map} +1 -1
- package/dist/_chunks/convention-lint-kXsgc_-7.js +784 -0
- package/dist/_chunks/convention-lint-kXsgc_-7.js.map +1 -0
- package/dist/_chunks/error-boundary-D-ODYX41.js +353 -0
- package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -0
- package/dist/_chunks/{fast-hash-D6hIVt1Y.js → fast-hash-C-tVYrLb.js} +6 -1
- package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
- package/dist/_chunks/file-cache-DmX7OqZP.js +454 -0
- package/dist/_chunks/file-cache-DmX7OqZP.js.map +1 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
- package/dist/_chunks/{logger-AWfuX-KJ.js → logger-D8xJZXIN.js} +34 -51
- package/dist/_chunks/logger-D8xJZXIN.js.map +1 -0
- package/dist/_chunks/mdx-file-C005ay-P.js +25 -0
- package/dist/_chunks/mdx-file-C005ay-P.js.map +1 -0
- package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-rCinWLiE.js} +8 -2
- package/dist/_chunks/plugin-context-rCinWLiE.js.map +1 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
- package/dist/_chunks/{resolve-schema-Dz3fcFUo.js → resolve-schema-5ma5pp1b.js} +2 -2
- package/dist/_chunks/{resolve-schema-Dz3fcFUo.js.map → resolve-schema-5ma5pp1b.js.map} +1 -1
- package/dist/_chunks/{router-ref-CtmF-aPv.js → router-ref-DuYuV_0Q.js} +2 -2
- package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -0
- package/dist/_chunks/rsc-cache-key-DD0fl_-s.js +243 -0
- package/dist/_chunks/rsc-cache-key-DD0fl_-s.js.map +1 -0
- package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js +40 -0
- package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js.map +1 -0
- package/dist/_chunks/rsc-media-type-DRqE_lD_.js +46 -0
- package/dist/_chunks/rsc-media-type-DRqE_lD_.js.map +1 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
- package/dist/_chunks/scanner-C8b0Gcw3.js +1564 -0
- package/dist/_chunks/scanner-C8b0Gcw3.js.map +1 -0
- package/dist/_chunks/schema-bridge-Cc2Gngu1.js +199 -0
- package/dist/_chunks/schema-bridge-Cc2Gngu1.js.map +1 -0
- package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
- package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
- package/dist/_chunks/segment-context-CjOlyB8Y.js +97 -0
- package/dist/_chunks/segment-context-CjOlyB8Y.js.map +1 -0
- package/dist/_chunks/{canonicalize-DQHyFClh.js → segment-keys-BawYuNFO.js} +61 -2
- package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -0
- package/dist/_chunks/slot-params-BCTmZkQB.js +76 -0
- package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -0
- package/dist/_chunks/{ssr-data-BOWsq18U.js → ssr-data-14MXm7Pj.js} +17 -2
- package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -0
- package/dist/_chunks/{use-query-states-DFvWd-EA.js → use-query-states-BbU5Ge1V.js} +74 -26
- package/dist/_chunks/use-query-states-BbU5Ge1V.js.map +1 -0
- package/dist/_chunks/use-segment-params-C4r4BD9T.js +398 -0
- package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -0
- package/dist/_chunks/walkers-RzN6AFjr.js +141 -0
- package/dist/_chunks/walkers-RzN6AFjr.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +37 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -1
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +1 -1
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +1 -1
- package/dist/adapters/compress-module.d.ts +12 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +64 -0
- package/dist/adapters/fs-identity.d.ts.map +1 -0
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +56 -5
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +57 -1
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +13 -1
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/fast-hash.d.ts +5 -0
- package/dist/cache/fast-hash.d.ts.map +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cdn/cloudflare-purge.js +30 -0
- package/dist/cdn/cloudflare-purge.js.map +1 -0
- package/dist/cdn/fastly-purge.js +33 -0
- package/dist/cdn/fastly-purge.js.map +1 -0
- package/dist/cdn/index.js +94 -0
- package/dist/cdn/index.js.map +1 -0
- package/dist/cdn/workers-cache-purge.js +35 -0
- package/dist/cdn/workers-cache-purge.js.map +1 -0
- package/dist/cli-check.d.ts +153 -0
- package/dist/cli-check.d.ts.map +1 -0
- package/dist/cli.d.ts +34 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +46 -21
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/hydrate.d.ts +20 -9
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
- package/dist/client/browser-entry/index.d.ts +1 -1
- package/dist/client/browser-entry/index.d.ts.map +1 -1
- package/dist/client/browser-entry/post-hydration.d.ts +4 -1
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts +3 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/browser-entry/rsc-stream.d.ts +8 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +7 -0
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -162
- package/dist/client/history.d.ts +13 -6
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +42 -41
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +4 -3
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +877 -311
- package/dist/client/internal.js.map +1 -1
- package/dist/client/link.d.ts +1 -7
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-api.d.ts +2 -2
- package/dist/client/navigation-commit.d.ts +87 -0
- package/dist/client/navigation-commit.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +37 -20
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +63 -23
- package/dist/client/navigation-root.d.ts.map +1 -1
- package/dist/client/params-context.d.ts +81 -0
- package/dist/client/params-context.d.ts.map +1 -0
- package/dist/client/router-effects.d.ts +129 -0
- package/dist/client/router-effects.d.ts.map +1 -0
- package/dist/client/router-lifecycle.d.ts +55 -0
- package/dist/client/router-lifecycle.d.ts.map +1 -0
- package/dist/client/router-pipeline.d.ts +84 -0
- package/dist/client/router-pipeline.d.ts.map +1 -0
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/router-ref.d.ts.map +1 -1
- package/dist/client/router-skew.d.ts +21 -0
- package/dist/client/router-skew.d.ts.map +1 -0
- package/dist/client/router-types.d.ts +207 -0
- package/dist/client/router-types.d.ts.map +1 -0
- package/dist/client/router.d.ts +1 -182
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +47 -26
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +87 -34
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/ssr-data.d.ts +6 -0
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-client.d.ts +69 -0
- package/dist/client/stale-client.d.ts.map +1 -0
- package/dist/client/state.d.ts +10 -1
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +2 -1
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/unload-guard.d.ts +5 -0
- package/dist/client/unload-guard.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts +9 -3
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/client/use-segment-params.d.ts +18 -8
- package/dist/client/use-segment-params.d.ts.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +5 -5
- package/dist/cookies/index.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1009 -759
- package/dist/index.js.map +1 -1
- package/dist/params/index.js +1 -1
- package/dist/plugin-context.d.ts +46 -0
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/request-dep/analysis.d.ts +106 -0
- package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
- package/dist/plugins/request-dep/index.d.ts +75 -0
- package/dist/plugins/request-dep/index.d.ts.map +1 -0
- package/dist/plugins/request-dep/origin.d.ts +61 -0
- package/dist/plugins/request-dep/origin.d.ts.map +1 -0
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +160 -8
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +3 -44
- package/dist/routing/codegen-shared.d.ts.map +1 -1
- package/dist/routing/codegen-types.d.ts +28 -31
- package/dist/routing/codegen-types.d.ts.map +1 -1
- package/dist/routing/codegen-write.d.ts +51 -0
- package/dist/routing/codegen-write.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/collision-probe.d.ts +104 -0
- package/dist/routing/collision-probe.d.ts.map +1 -0
- package/dist/routing/collision-spaces.d.ts +26 -0
- package/dist/routing/collision-spaces.d.ts.map +1 -0
- package/dist/routing/convention-lint.d.ts +18 -4
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/export-detect.d.ts +16 -0
- package/dist/routing/export-detect.d.ts.map +1 -1
- package/dist/routing/index.js +4 -3
- package/dist/routing/interception.d.ts +235 -6
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +19 -4
- package/dist/routing/link-codegen.d.ts.map +1 -1
- package/dist/routing/manifest-codegen.d.ts +1 -7
- package/dist/routing/manifest-codegen.d.ts.map +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +33 -0
- package/dist/routing/segment-classify.d.ts.map +1 -1
- package/dist/routing/segment-keys.d.ts +95 -0
- package/dist/routing/segment-keys.d.ts.map +1 -0
- package/dist/routing/slot-placement.d.ts +48 -0
- package/dist/routing/slot-placement.d.ts.map +1 -0
- package/dist/routing/types.d.ts +0 -6
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +6 -0
- package/dist/routing/walkers.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +60 -9
- package/dist/schema-bridge.d.ts.map +1 -1
- package/dist/search-params/define.d.ts +62 -14
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.d.ts +0 -1
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +221 -10
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/parse-total.d.ts +70 -0
- package/dist/search-params/parse-total.d.ts.map +1 -0
- package/dist/search-params/wrappers.d.ts +26 -3
- package/dist/search-params/wrappers.d.ts.map +1 -1
- package/dist/server/access-gate.d.ts +19 -8
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +6 -3
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +18 -1
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +13 -1
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/chain-url-parts.d.ts +82 -0
- package/dist/server/chain-url-parts.d.ts.map +1 -0
- package/dist/server/children-interception.d.ts +49 -0
- package/dist/server/children-interception.d.ts.map +1 -0
- package/dist/server/compress.d.ts.map +1 -1
- package/dist/server/default-status-page.d.ts +45 -0
- package/dist/server/default-status-page.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +148 -15
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +15 -4
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +85 -15
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/head-response.d.ts +35 -0
- package/dist/server/head-response.d.ts.map +1 -0
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +3 -1
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +712 -418
- package/dist/server/internal.js.map +1 -1
- package/dist/server/metadata-collector.d.ts +52 -0
- package/dist/server/metadata-collector.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +22 -6
- package/dist/server/param-coercion.d.ts.map +1 -1
- package/dist/server/pipeline-helpers.d.ts +0 -18
- package/dist/server/pipeline-helpers.d.ts.map +1 -1
- package/dist/server/pipeline-interception.d.ts +59 -9
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +11 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +23 -0
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/publish-params.d.ts +33 -0
- package/dist/server/publish-params.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +48 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +22 -3
- 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 +13 -0
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-cache-key-guard.d.ts +78 -0
- package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +15 -3
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +2 -17
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +0 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +1 -2
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +15 -2
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/skippable-prefix.d.ts +23 -0
- package/dist/server/skippable-prefix.d.ts.map +1 -0
- package/dist/server/slot-interception.d.ts +80 -0
- package/dist/server/slot-interception.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +70 -8
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +17 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +0 -1
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +24 -13
- package/dist/server/ssr-wrappers.d.ts.map +1 -1
- package/dist/server/state-tree-diff.d.ts +6 -27
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/static-generator.d.ts +6 -0
- package/dist/server/static-generator.d.ts.map +1 -1
- package/dist/server/static-not-found.d.ts +52 -0
- package/dist/server/static-not-found.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +8 -1
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +28 -36
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +12 -7
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/element-type.d.ts +40 -0
- package/dist/server/utils/element-type.d.ts.map +1 -0
- package/dist/shared/als-slots.d.ts +41 -0
- package/dist/shared/als-slots.d.ts.map +1 -0
- package/dist/shared/base-path.d.ts +56 -0
- package/dist/shared/base-path.d.ts.map +1 -0
- package/dist/shared/param-value.d.ts +80 -0
- package/dist/shared/param-value.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +108 -0
- package/dist/shared/payload-root.d.ts.map +1 -0
- package/dist/shared/rsc-cache-key.d.ts +163 -0
- package/dist/shared/rsc-cache-key.d.ts.map +1 -0
- package/dist/shared/rsc-error-envelope.d.ts +25 -0
- package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
- package/dist/shared/rsc-manifest.d.ts +28 -0
- package/dist/shared/rsc-manifest.d.ts.map +1 -0
- package/dist/shared/rsc-media-type.d.ts +40 -0
- package/dist/shared/rsc-media-type.d.ts.map +1 -0
- package/dist/shared/rsc-payload-path.d.ts +42 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -0
- package/dist/shared/segment-info.d.ts +59 -0
- package/dist/shared/segment-info.d.ts.map +1 -0
- package/dist/shared/slot-params.d.ts +51 -0
- package/dist/shared/slot-params.d.ts.map +1 -0
- package/dist/shared/static-platform-files.d.ts +71 -0
- package/dist/shared/static-platform-files.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +1 -1
- package/docs/api/31-api-client.mdx +4 -2
- package/docs/api/33-api-search-params.mdx +38 -16
- package/docs/api/35-api-typescript.mdx +3 -3
- package/docs/api/36-cli.mdx +34 -7
- package/docs/learn/00-introduction.mdx +1 -1
- package/docs/learn/02-pages-and-layouts.mdx +2 -2
- package/docs/learn/05-typed-params.mdx +8 -8
- package/docs/learn/07-typed-routes.mdx +12 -7
- package/docs/learn/11-error-handling.mdx +18 -0
- package/docs/learn/12-client-navigation.mdx +2 -2
- package/docs/learn/14-deploying.mdx +23 -0
- package/docs/more/01-advanced-routing.mdx +173 -3
- package/docs/more/03-coming-from-nextjs.mdx +2 -2
- package/docs/more/04-metadata-and-fonts.mdx +1 -1
- package/docs/more/50-ai-agent-instructions.mdx +6 -4
- package/package.json +9 -6
- package/src/adapters/build-output-helper.ts +116 -3
- package/src/adapters/cloudflare.ts +90 -12
- package/src/adapters/compress-module.ts +79 -1
- package/src/adapters/fs-identity.ts +156 -0
- package/src/adapters/nitro.ts +6 -6
- package/src/adapters/shared.ts +196 -21
- package/src/adapters/types.ts +13 -1
- package/src/cache/fast-hash.ts +5 -0
- package/src/cli-check.ts +458 -0
- package/src/cli.ts +59 -24
- package/src/client/browser-entry/action-dispatch.ts +11 -5
- package/src/client/browser-entry/hydrate.ts +40 -29
- package/src/client/browser-entry/index.ts +15 -6
- package/src/client/browser-entry/post-hydration.ts +10 -9
- package/src/client/browser-entry/router-init.ts +104 -48
- package/src/client/browser-entry/rsc-stream.ts +11 -2
- package/src/client/error-boundary.tsx +85 -16
- package/src/client/history.ts +13 -6
- package/src/client/index.ts +14 -3
- package/src/client/internal.ts +4 -3
- package/src/client/link.tsx +120 -72
- package/src/client/navigation-api.ts +3 -3
- package/src/client/navigation-commit.ts +197 -0
- package/src/client/navigation-context.ts +40 -67
- package/src/client/navigation-root.tsx +326 -101
- package/src/client/params-context.ts +192 -0
- package/src/client/router-effects.ts +231 -0
- package/src/client/router-lifecycle.ts +288 -0
- package/src/client/router-pipeline.ts +393 -0
- package/src/client/router-ref.ts +1 -1
- package/src/client/router-skew.ts +30 -0
- package/src/client/router-types.ts +230 -0
- package/src/client/router.ts +243 -707
- package/src/client/rsc-fetch.ts +183 -106
- package/src/client/segment-cache.ts +129 -44
- package/src/client/ssr-data.ts +6 -0
- package/src/client/stale-client.ts +191 -0
- package/src/client/state.ts +14 -1
- package/src/client/top-loader.tsx +2 -1
- package/src/client/unload-guard.ts +34 -2
- package/src/client/use-cookie.ts +9 -2
- package/src/client/use-query-states.ts +102 -39
- package/src/client/use-router.ts +1 -1
- package/src/client/use-segment-params.ts +41 -18
- package/src/cookies/define-cookie.ts +6 -1
- package/src/index.ts +25 -4
- package/src/plugin-context.ts +58 -0
- package/src/plugins/adapter-build.ts +4 -0
- package/src/plugins/build-manifest.ts +34 -13
- package/src/plugins/entries.ts +4 -0
- package/src/plugins/fonts.ts +11 -8
- package/src/plugins/request-dep/analysis.ts +447 -0
- package/src/plugins/request-dep/index.ts +376 -0
- package/src/plugins/request-dep/origin.ts +310 -0
- package/src/plugins/routing.ts +97 -102
- package/src/plugins/shims.ts +0 -1
- package/src/plugins/static-build.ts +391 -95
- package/src/routing/codegen-shared.ts +3 -79
- package/src/routing/codegen-types.ts +28 -31
- package/src/routing/codegen-write.ts +139 -0
- package/src/routing/codegen.ts +86 -172
- package/src/routing/collision-probe.ts +438 -0
- package/src/routing/collision-spaces.ts +281 -0
- package/src/routing/convention-lint.ts +139 -40
- package/src/routing/export-detect.ts +151 -7
- package/src/routing/interception.ts +896 -50
- package/src/routing/link-codegen.ts +32 -65
- package/src/routing/manifest-codegen.ts +6 -62
- package/src/routing/scanner.ts +117 -92
- package/src/routing/segment-classify.ts +57 -0
- package/src/routing/segment-keys.ts +146 -0
- package/src/routing/slot-placement.ts +97 -0
- package/src/routing/types.ts +0 -6
- package/src/routing/walkers.ts +8 -0
- package/src/schema-bridge.ts +180 -58
- package/src/search-params/define.ts +108 -66
- package/src/search-params/index.ts +0 -1
- package/src/search-params/parse-total.ts +78 -0
- package/src/search-params/wrappers.ts +60 -11
- package/src/server/access-gate.tsx +60 -40
- package/src/server/action-handler.ts +4 -5
- package/src/server/actions.ts +6 -3
- package/src/server/als-registry.ts +18 -1
- package/src/server/build-manifest.ts +14 -1
- package/src/server/chain-url-parts.ts +163 -0
- package/src/server/children-interception.ts +115 -0
- package/src/server/compress.ts +9 -1
- package/src/server/default-status-page.ts +127 -0
- package/src/server/deny-boundary.ts +269 -41
- package/src/server/deny-renderer.ts +111 -39
- package/src/server/error-boundary-wrapper.ts +166 -79
- package/src/server/head-response.ts +54 -0
- package/src/server/index.ts +1 -3
- package/src/server/internal.ts +2 -2
- package/src/server/metadata-collector.ts +115 -0
- package/src/server/param-coercion.ts +51 -69
- package/src/server/pipeline-helpers.ts +2 -47
- package/src/server/pipeline-interception.ts +81 -32
- package/src/server/pipeline-outcome.ts +4 -5
- package/src/server/pipeline-phases.ts +77 -25
- package/src/server/pipeline.ts +57 -10
- package/src/server/prebuilt-runtime.ts +4 -4
- package/src/server/primitives.ts +25 -0
- package/src/server/publish-params.ts +42 -0
- package/src/server/request-context.ts +97 -18
- package/src/server/route-element-builder.ts +241 -253
- package/src/server/route-handler.ts +8 -8
- package/src/server/route-matcher.ts +21 -9
- package/src/server/rsc-cache-key-guard.ts +164 -0
- package/src/server/rsc-entry/api-handler.ts +6 -8
- package/src/server/rsc-entry/deny-fallback.ts +3 -2
- package/src/server/rsc-entry/error-renderer.ts +94 -35
- package/src/server/rsc-entry/helpers.ts +33 -28
- package/src/server/rsc-entry/index.ts +36 -33
- package/src/server/rsc-entry/render-route.ts +18 -10
- package/src/server/rsc-entry/revalidate-renderer.ts +3 -2
- package/src/server/rsc-entry/rsc-payload.ts +113 -40
- package/src/server/rsc-entry/rsc-stream.ts +29 -5
- package/src/server/rsc-entry/ssr-renderer.ts +38 -22
- package/src/server/skippable-prefix.ts +92 -0
- package/src/server/slot-interception.ts +168 -0
- package/src/server/slot-resolver.ts +263 -158
- package/src/server/ssr-bridge-types.ts +18 -0
- package/src/server/ssr-entry.ts +20 -10
- package/src/server/ssr-wrappers.tsx +33 -32
- package/src/server/state-tree-diff.ts +14 -55
- package/src/server/static-generator.ts +68 -29
- package/src/server/static-not-found.ts +134 -0
- package/src/server/status-code-resolver.ts +28 -11
- package/src/server/tree-builder.ts +35 -218
- package/src/server/types.ts +12 -7
- package/src/server/utils/element-type.ts +72 -0
- package/src/shared/als-slots.ts +72 -0
- package/src/shared/base-path.ts +80 -0
- package/src/shared/param-value.ts +244 -0
- package/src/shared/payload-root.ts +151 -0
- package/src/shared/rsc-cache-key.ts +269 -0
- package/src/shared/rsc-error-envelope.ts +31 -0
- package/src/shared/rsc-manifest.ts +29 -0
- package/src/shared/rsc-media-type.ts +43 -0
- package/src/shared/rsc-payload-path.ts +45 -0
- package/src/shared/segment-info.ts +60 -0
- package/src/shared/slot-params.ts +111 -0
- package/src/shared/static-platform-files.ts +75 -0
- package/dist/_chunks/build-output-helper-DOGYFb_X.js +0 -196
- package/dist/_chunks/build-output-helper-DOGYFb_X.js.map +0 -1
- package/dist/_chunks/cache-api-B-lhk9p4.js.map +0 -1
- package/dist/_chunks/canonicalize-DQHyFClh.js.map +0 -1
- package/dist/_chunks/cli-schema-sync-BTWEKJXo.js +0 -668
- package/dist/_chunks/cli-schema-sync-BTWEKJXo.js.map +0 -1
- package/dist/_chunks/define-COtkxMRT.js +0 -191
- package/dist/_chunks/define-COtkxMRT.js.map +0 -1
- package/dist/_chunks/define-c4au4I9R.js +0 -82
- package/dist/_chunks/define-c4au4I9R.js.map +0 -1
- package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +0 -1
- package/dist/_chunks/logger-AWfuX-KJ.js.map +0 -1
- package/dist/_chunks/navigation-root-bUDZLw74.js +0 -124
- package/dist/_chunks/navigation-root-bUDZLw74.js.map +0 -1
- package/dist/_chunks/plugin-context---kTF5v8.js.map +0 -1
- package/dist/_chunks/registry-DbJPKoBp.js +0 -20
- package/dist/_chunks/registry-DbJPKoBp.js.map +0 -1
- package/dist/_chunks/router-ref-CtmF-aPv.js.map +0 -1
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +0 -119
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +0 -1
- package/dist/_chunks/segment-classify-Byy425ng.js.map +0 -1
- package/dist/_chunks/segment-context-ZDnXDkbz.js +0 -34
- package/dist/_chunks/segment-context-ZDnXDkbz.js.map +0 -1
- package/dist/_chunks/ssr-data-BOWsq18U.js.map +0 -1
- package/dist/_chunks/use-query-states-DFvWd-EA.js.map +0 -1
- package/dist/_chunks/use-segment-params-D1CzlgBo.js +0 -151
- package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +0 -1
- package/dist/_chunks/walkers-_6zKFlch.js +0 -1002
- package/dist/_chunks/walkers-_6zKFlch.js.map +0 -1
- package/dist/client/error-boundary.js.map +0 -1
- package/dist/plugins/request-dep.d.ts +0 -32
- package/dist/plugins/request-dep.d.ts.map +0 -1
- package/dist/search-params/registry.d.ts +0 -20
- package/dist/search-params/registry.d.ts.map +0 -1
- package/dist/segment-params/define.d.ts +0 -89
- package/dist/segment-params/define.d.ts.map +0 -1
- package/dist/segment-params/index.d.ts +0 -3
- package/dist/segment-params/index.d.ts.map +0 -1
- package/dist/segment-params/index.js +0 -2
- package/src/plugins/request-dep.ts +0 -499
- package/src/search-params/registry.ts +0 -31
- package/src/segment-params/define.ts +0 -249
- package/src/segment-params/index.ts +0 -9
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { o as __exportAll } from "./dist-BA3u1z3W.js";
|
|
2
|
+
import { t as scanRoutes } from "./scanner-C8b0Gcw3.js";
|
|
3
|
+
import { o as resolveAppDir } from "./plugin-context-rCinWLiE.js";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
//#region src/cli-schema-sync.ts
|
|
7
|
+
/**
|
|
8
|
+
* `timber schema sync` — scan filesystem for dynamic segments, append
|
|
9
|
+
* missing entries with `codec.string` defaults, and remove stale entries
|
|
10
|
+
* whose segments no longer exist in the filesystem.
|
|
11
|
+
*
|
|
12
|
+
* Design doc: design/41-global-params.md §Auto-Scaffolding
|
|
13
|
+
*/
|
|
14
|
+
var cli_schema_sync_exports = /* @__PURE__ */ __exportAll({
|
|
15
|
+
collectDynamicSegments: () => collectDynamicSegments,
|
|
16
|
+
defaultCodecForSegment: () => defaultCodecForSegment,
|
|
17
|
+
findSchemaFile: () => findSchemaFile,
|
|
18
|
+
findSegmentParamsBlock: () => findSegmentParamsBlock,
|
|
19
|
+
parseExistingSchemaKeys: () => parseExistingSchemaKeys,
|
|
20
|
+
runSchemaSync: () => runSchemaSync
|
|
21
|
+
});
|
|
22
|
+
function toBracketKey(node) {
|
|
23
|
+
if (node.paramPrefix || node.paramSuffix) return `[${node.paramName}]`;
|
|
24
|
+
switch (node.segmentType) {
|
|
25
|
+
case "catch-all": return `[...${node.paramName}]`;
|
|
26
|
+
case "optional-catch-all": return `[[...${node.paramName}]]`;
|
|
27
|
+
default: return `[${node.paramName}]`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Collect all unique bracket-keyed dynamic segment names from the route tree.
|
|
32
|
+
* Returns entries like '[artistSlug]', '[...slug]', '[[...topic]]'.
|
|
33
|
+
*/
|
|
34
|
+
function collectDynamicSegments(appDir) {
|
|
35
|
+
const tree = scanRoutes(appDir);
|
|
36
|
+
const segments = /* @__PURE__ */ new Set();
|
|
37
|
+
walkSegments(tree.root, segments);
|
|
38
|
+
return [...segments].sort();
|
|
39
|
+
}
|
|
40
|
+
function walkSegments(node, segments) {
|
|
41
|
+
if (node.paramName) segments.add(toBracketKey(node));
|
|
42
|
+
for (const child of node.children) walkSegments(child, segments);
|
|
43
|
+
for (const slot of Object.values(node.slots)) walkSegments(slot, segments);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Replace comment bodies (and optionally string contents) with spaces,
|
|
47
|
+
* preserving length and newlines so every index maps 1:1 to the original.
|
|
48
|
+
* Lets the structural scanning below ignore `segmentParams` mentions and
|
|
49
|
+
* braces inside comments/strings without a TS parser (fine pre-alpha,
|
|
50
|
+
* see TIM-1066).
|
|
51
|
+
*
|
|
52
|
+
* With `maskStrings`, string contents are blanked too — except literal
|
|
53
|
+
* 'segmentParams' strings, kept so a quoted property key stays findable.
|
|
54
|
+
*/
|
|
55
|
+
function maskSource(content, maskStrings) {
|
|
56
|
+
const out = content.split("");
|
|
57
|
+
const n = content.length;
|
|
58
|
+
let i = 0;
|
|
59
|
+
const blank = (from, to) => {
|
|
60
|
+
for (let j = from; j < to; j++) if (content[j] !== "\n") out[j] = " ";
|
|
61
|
+
};
|
|
62
|
+
while (i < n) {
|
|
63
|
+
const ch = content[i];
|
|
64
|
+
const next = content[i + 1];
|
|
65
|
+
if (ch === "/" && next === "/") {
|
|
66
|
+
const start = i;
|
|
67
|
+
while (i < n && content[i] !== "\n") i++;
|
|
68
|
+
blank(start, i);
|
|
69
|
+
} else if (ch === "/" && next === "*") {
|
|
70
|
+
const start = i;
|
|
71
|
+
i += 2;
|
|
72
|
+
while (i < n && !(content[i] === "*" && content[i + 1] === "/")) i++;
|
|
73
|
+
i = Math.min(i + 2, n);
|
|
74
|
+
blank(start, i);
|
|
75
|
+
} else if (ch === "\"" || ch === "'" || ch === "`") {
|
|
76
|
+
const start = i;
|
|
77
|
+
i++;
|
|
78
|
+
while (i < n && content[i] !== ch) {
|
|
79
|
+
if (content[i] === "\\") i++;
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
const end = i;
|
|
83
|
+
if (maskStrings && content.slice(start + 1, end) !== "segmentParams") blank(start + 1, end);
|
|
84
|
+
i++;
|
|
85
|
+
} else i++;
|
|
86
|
+
}
|
|
87
|
+
return out.join("");
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Locate the `segmentParams: { ... }` block in a schema file.
|
|
91
|
+
* Returns the indices of the opening and matching closing brace, or null
|
|
92
|
+
* if no segmentParams property is found. Comments and strings are masked
|
|
93
|
+
* first, so a JSDoc example mentioning `segmentParams: { ... }` above the
|
|
94
|
+
* real defineSchema call is not mistaken for the block, and braces inside
|
|
95
|
+
* comments/strings don't skew the depth count. The search is anchored to
|
|
96
|
+
* the `defineSchema(` call when present, so helper objects with their own
|
|
97
|
+
* segmentParams property earlier in the file are skipped.
|
|
98
|
+
*/
|
|
99
|
+
function findSegmentParamsBlock(content) {
|
|
100
|
+
const masked = maskSource(content, true);
|
|
101
|
+
const defineCall = /\bdefineSchema\s*\(/.exec(masked);
|
|
102
|
+
const keyRe = /(['"]?)segmentParams\1\s*:\s*\{/g;
|
|
103
|
+
keyRe.lastIndex = defineCall ? defineCall.index + defineCall[0].length : 0;
|
|
104
|
+
const keyMatch = keyRe.exec(masked);
|
|
105
|
+
if (!keyMatch) return null;
|
|
106
|
+
const openBrace = keyMatch.index + keyMatch[0].length - 1;
|
|
107
|
+
let depth = 1;
|
|
108
|
+
let i = openBrace + 1;
|
|
109
|
+
while (i < masked.length && depth > 0) {
|
|
110
|
+
if (masked[i] === "{") depth++;
|
|
111
|
+
else if (masked[i] === "}") depth--;
|
|
112
|
+
i++;
|
|
113
|
+
}
|
|
114
|
+
if (depth > 0) return null;
|
|
115
|
+
return {
|
|
116
|
+
openBrace,
|
|
117
|
+
closeBrace: i - 1
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Parse existing bracket keys from an app/schema.ts file.
|
|
122
|
+
* Scoped to the segmentParams: { ... } block — bracket keys elsewhere in
|
|
123
|
+
* the file (unrelated objects, comments above defineSchema) are ignored.
|
|
124
|
+
* Comments inside the block are masked, so a commented-out entry does not
|
|
125
|
+
* count as registered.
|
|
126
|
+
*
|
|
127
|
+
* The key charset matches the route classifier (segment-classify.ts):
|
|
128
|
+
* any character except `]`, so hyphenated params like '[my-param]' parse.
|
|
129
|
+
*/
|
|
130
|
+
function parseExistingSchemaKeys(content) {
|
|
131
|
+
const block = findSegmentParamsBlock(content);
|
|
132
|
+
if (!block) return [];
|
|
133
|
+
const blockContent = maskSource(content, false).slice(block.openBrace, block.closeBrace);
|
|
134
|
+
const keys = [];
|
|
135
|
+
const re = /['"](\[{1,2}(?:\.{3})?[^\]]+\]{1,2})['"]\s*:/g;
|
|
136
|
+
let m;
|
|
137
|
+
while ((m = re.exec(blockContent)) !== null) keys.push(m[1]);
|
|
138
|
+
return keys;
|
|
139
|
+
}
|
|
140
|
+
/** Schema file extensions to check. */
|
|
141
|
+
var SCHEMA_EXTENSIONS = [
|
|
142
|
+
".ts",
|
|
143
|
+
".tsx",
|
|
144
|
+
".js",
|
|
145
|
+
".jsx"
|
|
146
|
+
];
|
|
147
|
+
/**
|
|
148
|
+
* Find the schema file path if it exists.
|
|
149
|
+
*/
|
|
150
|
+
function findSchemaFile(appDir) {
|
|
151
|
+
for (const ext of SCHEMA_EXTENSIONS) {
|
|
152
|
+
const p = join(appDir, `schema${ext}`);
|
|
153
|
+
if (existsSync(p)) return p;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function defaultCodecForSegment(seg) {
|
|
157
|
+
if (seg.startsWith("[[...")) return "codec.optionalCatchAll(codec.string)";
|
|
158
|
+
if (seg.startsWith("[...")) return "codec.stringArray";
|
|
159
|
+
return "codec.string";
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate the content for a new app/schema.ts with the given segment keys.
|
|
163
|
+
*/
|
|
164
|
+
function generateNewSchema(segments) {
|
|
165
|
+
const lines = [];
|
|
166
|
+
lines.push("import { defineSchema } from '@timber-js/app/params';");
|
|
167
|
+
lines.push("import { codec } from '@timber-js/app/codec';");
|
|
168
|
+
lines.push("");
|
|
169
|
+
lines.push("export default defineSchema({");
|
|
170
|
+
lines.push(" segmentParams: {");
|
|
171
|
+
for (const seg of segments) lines.push(` '${seg}': ${defaultCodecForSegment(seg)},`);
|
|
172
|
+
lines.push(" },");
|
|
173
|
+
lines.push("});");
|
|
174
|
+
lines.push("");
|
|
175
|
+
return lines.join("\n");
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Append missing segment entries to an existing schema file.
|
|
179
|
+
* Inserts new entries before the closing `}` of segmentParams.
|
|
180
|
+
*/
|
|
181
|
+
var CODEC_IMPORT = "import { codec } from '@timber-js/app/codec';";
|
|
182
|
+
function hasCodecImport(content) {
|
|
183
|
+
return /import\s+\{[^}]*\bcodec\b[^}]*\}\s+from\s+['"]@timber-js\/app\/codec['"]/.test(content);
|
|
184
|
+
}
|
|
185
|
+
function ensureCodecImport(content) {
|
|
186
|
+
if (hasCodecImport(content)) return content;
|
|
187
|
+
const lines = content.split("\n");
|
|
188
|
+
let lastImportIndex = -1;
|
|
189
|
+
for (let i = 0; i < lines.length; i++) if (/^\s*import\s/.test(lines[i])) lastImportIndex = i;
|
|
190
|
+
if (lastImportIndex === -1) return "import { codec } from '@timber-js/app/codec';\n" + content;
|
|
191
|
+
lines.splice(lastImportIndex + 1, 0, CODEC_IMPORT);
|
|
192
|
+
return lines.join("\n");
|
|
193
|
+
}
|
|
194
|
+
function appendToSchema(content, newSegments) {
|
|
195
|
+
content = ensureCodecImport(content);
|
|
196
|
+
const block = findSegmentParamsBlock(content);
|
|
197
|
+
if (!block) throw new Error("[timber] Could not find segmentParams in schema file. Expected a defineSchema({ segmentParams: { ... } }) call.");
|
|
198
|
+
const { openBrace, closeBrace } = block;
|
|
199
|
+
const existingLine = content.slice(openBrace, closeBrace).match(/^(\s+)['"]\[/m);
|
|
200
|
+
const indent = existingLine ? existingLine[1] : " ";
|
|
201
|
+
const insertion = newSegments.map((seg) => `${indent}'${seg}': ${defaultCodecForSegment(seg)},`).join("\n");
|
|
202
|
+
const before = content.slice(0, closeBrace);
|
|
203
|
+
const after = content.slice(closeBrace);
|
|
204
|
+
return before + (before.trimEnd().endsWith(",") ? "\n" : "\n") + insertion + "\n" + after;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Remove entries from the segmentParams block whose keys match `staleSegments`.
|
|
208
|
+
* Removes the entire entry including trailing comma/whitespace. Scoped to
|
|
209
|
+
* the segmentParams block — identical keys in unrelated objects elsewhere
|
|
210
|
+
* in the file are left untouched.
|
|
211
|
+
*/
|
|
212
|
+
function removeFromSchema(content, staleSegments) {
|
|
213
|
+
const block = findSegmentParamsBlock(content);
|
|
214
|
+
if (!block) return content;
|
|
215
|
+
let blockContent = content.slice(block.openBrace, block.closeBrace);
|
|
216
|
+
let blockMasked = maskSource(blockContent, false);
|
|
217
|
+
for (const seg of staleSegments) {
|
|
218
|
+
const escaped = seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
219
|
+
const keyRe = new RegExp(`^[ \t]*['"]${escaped}['"][ \t]*:`, "gm");
|
|
220
|
+
let m;
|
|
221
|
+
while ((m = keyRe.exec(blockMasked)) !== null) {
|
|
222
|
+
const start = m.index;
|
|
223
|
+
let i = m.index + m[0].length;
|
|
224
|
+
let depth = 0;
|
|
225
|
+
let inString = null;
|
|
226
|
+
while (i < blockMasked.length) {
|
|
227
|
+
const ch = blockMasked[i];
|
|
228
|
+
if (inString) {
|
|
229
|
+
if (ch === "\\") i++;
|
|
230
|
+
else if (ch === inString) inString = null;
|
|
231
|
+
} else if (ch === "\"" || ch === "'" || ch === "`") inString = ch;
|
|
232
|
+
else if (ch === "(" || ch === "{" || ch === "[") depth++;
|
|
233
|
+
else if (ch === ")" || ch === "}" || ch === "]") depth--;
|
|
234
|
+
else if (depth === 0 && ch === ",") {
|
|
235
|
+
i++;
|
|
236
|
+
break;
|
|
237
|
+
} else if (depth === 0 && (ch === "\n" || ch === "}")) break;
|
|
238
|
+
i++;
|
|
239
|
+
}
|
|
240
|
+
if (i < blockMasked.length && blockMasked[i] === "\n") i++;
|
|
241
|
+
blockContent = blockContent.slice(0, start) + blockContent.slice(i);
|
|
242
|
+
blockMasked = blockMasked.slice(0, start) + blockMasked.slice(i);
|
|
243
|
+
keyRe.lastIndex = start;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return content.slice(0, block.openBrace) + blockContent + content.slice(block.closeBrace);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Run the schema sync: scan filesystem, diff against schema, append missing.
|
|
250
|
+
*/
|
|
251
|
+
function runSchemaSync(projectRoot) {
|
|
252
|
+
const appDir = resolveAppDir(projectRoot);
|
|
253
|
+
const filesystemSegments = collectDynamicSegments(appDir);
|
|
254
|
+
const schemaPath = findSchemaFile(appDir);
|
|
255
|
+
if (filesystemSegments.length === 0 && !schemaPath) return {
|
|
256
|
+
filesystemSegments: [],
|
|
257
|
+
existingSegments: [],
|
|
258
|
+
addedSegments: [],
|
|
259
|
+
removedSegments: [],
|
|
260
|
+
created: false
|
|
261
|
+
};
|
|
262
|
+
if (!schemaPath) {
|
|
263
|
+
writeFileSync(join(appDir, "schema.ts"), generateNewSchema(filesystemSegments), "utf-8");
|
|
264
|
+
return {
|
|
265
|
+
filesystemSegments,
|
|
266
|
+
existingSegments: [],
|
|
267
|
+
addedSegments: filesystemSegments,
|
|
268
|
+
removedSegments: [],
|
|
269
|
+
created: true
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const content = readFileSync(schemaPath, "utf-8");
|
|
273
|
+
const existingSegments = parseExistingSchemaKeys(content);
|
|
274
|
+
const missing = filesystemSegments.filter((seg) => !existingSegments.includes(seg));
|
|
275
|
+
const stale = existingSegments.filter((seg) => !filesystemSegments.includes(seg));
|
|
276
|
+
if (missing.length === 0 && stale.length === 0) return {
|
|
277
|
+
filesystemSegments,
|
|
278
|
+
existingSegments,
|
|
279
|
+
addedSegments: [],
|
|
280
|
+
removedSegments: [],
|
|
281
|
+
created: false
|
|
282
|
+
};
|
|
283
|
+
let updated = content;
|
|
284
|
+
if (stale.length > 0) updated = removeFromSchema(updated, stale);
|
|
285
|
+
if (missing.length > 0) updated = appendToSchema(updated, missing);
|
|
286
|
+
writeFileSync(schemaPath, updated, "utf-8");
|
|
287
|
+
return {
|
|
288
|
+
filesystemSegments,
|
|
289
|
+
existingSegments,
|
|
290
|
+
addedSegments: missing,
|
|
291
|
+
removedSegments: stale,
|
|
292
|
+
created: false
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
//#endregion
|
|
296
|
+
export { findSchemaFile as n, parseExistingSchemaKeys as r, cli_schema_sync_exports as t };
|
|
297
|
+
|
|
298
|
+
//# sourceMappingURL=cli-schema-sync-CGMp_Psg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-schema-sync-CGMp_Psg.js","names":[],"sources":["../../src/cli-schema-sync.ts"],"sourcesContent":["/**\n * `timber schema sync` — scan filesystem for dynamic segments, append\n * missing entries with `codec.string` defaults, and remove stale entries\n * whose segments no longer exist in the filesystem.\n *\n * Design doc: design/41-global-params.md §Auto-Scaffolding\n */\n\nimport { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { scanRoutes } from './routing/scanner.js';\nimport type { SegmentNode } from './routing/types.js';\nimport { resolveAppDir } from './plugin-context.js';\n\nfunction toBracketKey(node: SegmentNode): string {\n if (node.paramPrefix || node.paramSuffix) return `[${node.paramName}]`;\n switch (node.segmentType) {\n case 'catch-all':\n return `[...${node.paramName}]`;\n case 'optional-catch-all':\n return `[[...${node.paramName}]]`;\n default:\n return `[${node.paramName}]`;\n }\n}\n\n/**\n * Collect all unique bracket-keyed dynamic segment names from the route tree.\n * Returns entries like '[artistSlug]', '[...slug]', '[[...topic]]'.\n */\nexport function collectDynamicSegments(appDir: string): string[] {\n const tree = scanRoutes(appDir);\n const segments = new Set<string>();\n walkSegments(tree.root, segments);\n return [...segments].sort();\n}\n\nfunction walkSegments(node: SegmentNode, segments: Set<string>): void {\n if (node.paramName) {\n // Use bare bracket form for schema keys — affixed segments like\n // `img-[id].png` register as `[id]`, matching runtime codec lookup.\n segments.add(toBracketKey(node));\n }\n for (const child of node.children) {\n walkSegments(child, segments);\n }\n for (const slot of Object.values(node.slots)) {\n walkSegments(slot, segments);\n }\n}\n\n/**\n * Replace comment bodies (and optionally string contents) with spaces,\n * preserving length and newlines so every index maps 1:1 to the original.\n * Lets the structural scanning below ignore `segmentParams` mentions and\n * braces inside comments/strings without a TS parser (fine pre-alpha,\n * see TIM-1066).\n *\n * With `maskStrings`, string contents are blanked too — except literal\n * 'segmentParams' strings, kept so a quoted property key stays findable.\n */\nfunction maskSource(content: string, maskStrings: boolean): string {\n const out = content.split('');\n const n = content.length;\n let i = 0;\n\n const blank = (from: number, to: number): void => {\n for (let j = from; j < to; j++) {\n if (content[j] !== '\\n') out[j] = ' ';\n }\n };\n\n while (i < n) {\n const ch = content[i];\n const next = content[i + 1];\n if (ch === '/' && next === '/') {\n const start = i;\n while (i < n && content[i] !== '\\n') i++;\n blank(start, i);\n } else if (ch === '/' && next === '*') {\n const start = i;\n i += 2;\n while (i < n && !(content[i] === '*' && content[i + 1] === '/')) i++;\n i = Math.min(i + 2, n);\n blank(start, i);\n } else if (ch === '\"' || ch === \"'\" || ch === '`') {\n const start = i;\n i++;\n while (i < n && content[i] !== ch) {\n if (content[i] === '\\\\') i++;\n i++;\n }\n const end = i; // at closing quote (or n if unterminated)\n if (maskStrings && content.slice(start + 1, end) !== 'segmentParams') {\n blank(start + 1, end);\n }\n i++;\n } else {\n i++;\n }\n }\n return out.join('');\n}\n\n/**\n * Locate the `segmentParams: { ... }` block in a schema file.\n * Returns the indices of the opening and matching closing brace, or null\n * if no segmentParams property is found. Comments and strings are masked\n * first, so a JSDoc example mentioning `segmentParams: { ... }` above the\n * real defineSchema call is not mistaken for the block, and braces inside\n * comments/strings don't skew the depth count. The search is anchored to\n * the `defineSchema(` call when present, so helper objects with their own\n * segmentParams property earlier in the file are skipped.\n */\nexport function findSegmentParamsBlock(\n content: string\n): { openBrace: number; closeBrace: number } | null {\n const masked = maskSource(content, true);\n\n const defineCall = /\\bdefineSchema\\s*\\(/.exec(masked);\n const keyRe = /(['\"]?)segmentParams\\1\\s*:\\s*\\{/g;\n keyRe.lastIndex = defineCall ? defineCall.index + defineCall[0].length : 0;\n const keyMatch = keyRe.exec(masked);\n if (!keyMatch) return null;\n\n const openBrace = keyMatch.index + keyMatch[0].length - 1;\n let depth = 1;\n let i = openBrace + 1;\n while (i < masked.length && depth > 0) {\n if (masked[i] === '{') depth++;\n else if (masked[i] === '}') depth--;\n i++;\n }\n if (depth > 0) return null;\n // i now points to just after the closing brace\n return { openBrace, closeBrace: i - 1 };\n}\n\n/**\n * Parse existing bracket keys from an app/schema.ts file.\n * Scoped to the segmentParams: { ... } block — bracket keys elsewhere in\n * the file (unrelated objects, comments above defineSchema) are ignored.\n * Comments inside the block are masked, so a commented-out entry does not\n * count as registered.\n *\n * The key charset matches the route classifier (segment-classify.ts):\n * any character except `]`, so hyphenated params like '[my-param]' parse.\n */\nexport function parseExistingSchemaKeys(content: string): string[] {\n const block = findSegmentParamsBlock(content);\n if (!block) return [];\n\n const blockContent = maskSource(content, false).slice(block.openBrace, block.closeBrace);\n const keys: string[] = [];\n // Match quoted bracket keys like '[artistSlug]', '[...slug]', '[[...topic]]'\n const re = /['\"](\\[{1,2}(?:\\.{3})?[^\\]]+\\]{1,2})['\"]\\s*:/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(blockContent)) !== null) {\n keys.push(m[1]);\n }\n return keys;\n}\n\n/** Schema file extensions to check. */\nconst SCHEMA_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'];\n\n/**\n * Find the schema file path if it exists.\n */\nexport function findSchemaFile(appDir: string): string | undefined {\n for (const ext of SCHEMA_EXTENSIONS) {\n const p = join(appDir, `schema${ext}`);\n if (existsSync(p)) return p;\n }\n return undefined;\n}\n\nexport function defaultCodecForSegment(seg: string): string {\n if (seg.startsWith('[[...')) return 'codec.optionalCatchAll(codec.string)';\n if (seg.startsWith('[...')) return 'codec.stringArray';\n return 'codec.string';\n}\n\n/**\n * Generate the content for a new app/schema.ts with the given segment keys.\n */\nfunction generateNewSchema(segments: string[]): string {\n const lines: string[] = [];\n lines.push(\"import { defineSchema } from '@timber-js/app/params';\");\n lines.push(\"import { codec } from '@timber-js/app/codec';\");\n lines.push('');\n lines.push('export default defineSchema({');\n lines.push(' segmentParams: {');\n for (const seg of segments) {\n lines.push(` '${seg}': ${defaultCodecForSegment(seg)},`);\n }\n lines.push(' },');\n lines.push('});');\n lines.push('');\n return lines.join('\\n');\n}\n\n/**\n * Append missing segment entries to an existing schema file.\n * Inserts new entries before the closing `}` of segmentParams.\n */\nconst CODEC_IMPORT = \"import { codec } from '@timber-js/app/codec';\";\n\nfunction hasCodecImport(content: string): boolean {\n return /import\\s+\\{[^}]*\\bcodec\\b[^}]*\\}\\s+from\\s+['\"]@timber-js\\/app\\/codec['\"]/.test(content);\n}\n\nfunction ensureCodecImport(content: string): string {\n if (hasCodecImport(content)) return content;\n\n // Insert after the last existing import statement\n const lines = content.split('\\n');\n let lastImportIndex = -1;\n for (let i = 0; i < lines.length; i++) {\n if (/^\\s*import\\s/.test(lines[i])) lastImportIndex = i;\n }\n\n if (lastImportIndex === -1) {\n return CODEC_IMPORT + '\\n' + content;\n }\n\n lines.splice(lastImportIndex + 1, 0, CODEC_IMPORT);\n return lines.join('\\n');\n}\n\nfunction appendToSchema(content: string, newSegments: string[]): string {\n content = ensureCodecImport(content);\n\n const block = findSegmentParamsBlock(content);\n if (!block) {\n throw new Error(\n '[timber] Could not find segmentParams in schema file. ' +\n 'Expected a defineSchema({ segmentParams: { ... } }) call.'\n );\n }\n const { openBrace, closeBrace } = block;\n\n // Detect indentation from existing entries\n const existingLine = content.slice(openBrace, closeBrace).match(/^(\\s+)['\"]\\[/m);\n const indent = existingLine ? existingLine[1] : ' ';\n\n // Build insertion text\n const insertion = newSegments\n .map((seg) => `${indent}'${seg}': ${defaultCodecForSegment(seg)},`)\n .join('\\n');\n\n // Insert before the closing brace\n const before = content.slice(0, closeBrace);\n const after = content.slice(closeBrace);\n\n // Add newline if the content before doesn't end with one\n const separator = before.trimEnd().endsWith(',') ? '\\n' : '\\n';\n\n return before + separator + insertion + '\\n' + after;\n}\n\n/**\n * Remove entries from the segmentParams block whose keys match `staleSegments`.\n * Removes the entire entry including trailing comma/whitespace. Scoped to\n * the segmentParams block — identical keys in unrelated objects elsewhere\n * in the file are left untouched.\n */\nfunction removeFromSchema(content: string, staleSegments: string[]): string {\n const block = findSegmentParamsBlock(content);\n if (!block) return content;\n\n let blockContent = content.slice(block.openBrace, block.closeBrace);\n // Key matching and the entry walk run on a comment-masked copy (same\n // length, indices align) so commented-out entries are never removed.\n // Both copies are spliced in sync to keep indices valid.\n let blockMasked = maskSource(blockContent, false);\n\n for (const seg of staleSegments) {\n const escaped = seg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const keyRe = new RegExp(`^[ \\t]*['\"]${escaped}['\"][ \\t]*:`, 'gm');\n let m: RegExpExecArray | null;\n while ((m = keyRe.exec(blockMasked)) !== null) {\n const start = m.index;\n let i = m.index + m[0].length;\n let depth = 0;\n let inString: string | null = null;\n\n while (i < blockMasked.length) {\n const ch = blockMasked[i];\n if (inString) {\n if (ch === '\\\\') {\n i++;\n } else if (ch === inString) {\n inString = null;\n }\n } else if (ch === '\"' || ch === \"'\" || ch === '`') {\n inString = ch;\n } else if (ch === '(' || ch === '{' || ch === '[') {\n depth++;\n } else if (ch === ')' || ch === '}' || ch === ']') {\n depth--;\n } else if (depth === 0 && ch === ',') {\n i++;\n break;\n } else if (depth === 0 && (ch === '\\n' || ch === '}')) {\n break;\n }\n i++;\n }\n\n // Consume trailing newline\n if (i < blockMasked.length && blockMasked[i] === '\\n') i++;\n\n blockContent = blockContent.slice(0, start) + blockContent.slice(i);\n blockMasked = blockMasked.slice(0, start) + blockMasked.slice(i);\n keyRe.lastIndex = start;\n }\n }\n\n return content.slice(0, block.openBrace) + blockContent + content.slice(block.closeBrace);\n}\n\nexport interface SchemaSyncResult {\n /** Segments found in the filesystem. */\n filesystemSegments: string[];\n /** Segments already defined in app/schema.ts. */\n existingSegments: string[];\n /** Segments that were added. */\n addedSegments: string[];\n /** Segments that were removed (no longer in filesystem). */\n removedSegments: string[];\n /** Whether a new schema file was created. */\n created: boolean;\n}\n\n/**\n * Run the schema sync: scan filesystem, diff against schema, append missing.\n */\nexport function runSchemaSync(projectRoot: string): SchemaSyncResult {\n const appDir = resolveAppDir(projectRoot);\n\n const filesystemSegments = collectDynamicSegments(appDir);\n\n const schemaPath = findSchemaFile(appDir);\n\n if (filesystemSegments.length === 0 && !schemaPath) {\n return {\n filesystemSegments: [],\n existingSegments: [],\n addedSegments: [],\n removedSegments: [],\n created: false,\n };\n }\n\n if (!schemaPath) {\n // Create new schema file\n const newPath = join(appDir, 'schema.ts');\n writeFileSync(newPath, generateNewSchema(filesystemSegments), 'utf-8');\n return {\n filesystemSegments,\n existingSegments: [],\n addedSegments: filesystemSegments,\n removedSegments: [],\n created: true,\n };\n }\n\n // Read existing schema and diff\n const content = readFileSync(schemaPath, 'utf-8');\n const existingSegments = parseExistingSchemaKeys(content);\n const missing = filesystemSegments.filter((seg) => !existingSegments.includes(seg));\n const stale = existingSegments.filter((seg) => !filesystemSegments.includes(seg));\n\n if (missing.length === 0 && stale.length === 0) {\n return {\n filesystemSegments,\n existingSegments,\n addedSegments: [],\n removedSegments: [],\n created: false,\n };\n }\n\n let updated = content;\n if (stale.length > 0) {\n updated = removeFromSchema(updated, stale);\n }\n if (missing.length > 0) {\n updated = appendToSchema(updated, missing);\n }\n writeFileSync(schemaPath, updated, 'utf-8');\n\n return {\n filesystemSegments,\n existingSegments,\n addedSegments: missing,\n removedSegments: stale,\n created: false,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as RSC_CONTENT_TYPE } from "./rsc-media-type-DRqE_lD_.js";
|
|
2
|
+
import { t as RSC_KEY_HEADERS } from "./rsc-cache-key-DD0fl_-s.js";
|
|
3
|
+
import { i as writeHeadersFile, n as findUnhashedStaticFiles, r as runSharedBuildSteps, t as buildStaticDirectoryOutput } from "./build-output-helper-C3DrfzZR.js";
|
|
2
4
|
import { join, relative } from "node:path";
|
|
3
|
-
import { access, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
4
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
|
+
import { access, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
5
7
|
import { execFile } from "node:child_process";
|
|
6
8
|
//#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
7
9
|
/**
|
|
@@ -825,6 +827,9 @@ function cloudflare(options = {}) {
|
|
|
825
827
|
function generateWorkerEntry(buildDir, outDir, hasManifestInit = false, hasWorkerHandlers = false) {
|
|
826
828
|
let rscEntryRelative = relative(outDir, join(buildDir, "rsc", "index.js"));
|
|
827
829
|
if (!rscEntryRelative.startsWith(".")) rscEntryRelative = "./" + rscEntryRelative;
|
|
830
|
+
const manifestImport = hasManifestInit ? "import './_timber-manifest-init.js'\n" : "";
|
|
831
|
+
const handlersImport = hasWorkerHandlers ? "import * as workerHandlers from './_worker-handlers.js'\n" : "";
|
|
832
|
+
const handlersSpread = hasWorkerHandlers ? " ...workerHandlers,\n" : "";
|
|
828
833
|
return `// Generated by @timber-js/app/adapters/cloudflare
|
|
829
834
|
// Do not edit — this file is regenerated on each build.
|
|
830
835
|
|
|
@@ -837,8 +842,8 @@ import { AsyncLocalStorage } from 'node:async_hooks'
|
|
|
837
842
|
// for cache.component payloads.
|
|
838
843
|
import './_timber-runtime-init.js'
|
|
839
844
|
import './_timber-prebuilt-source.js'
|
|
840
|
-
${
|
|
841
|
-
${
|
|
845
|
+
${manifestImport}import handler, { runWithWaitUntil, runWithWorkersCachePurge } from '${rscEntryRelative}'
|
|
846
|
+
${handlersImport}
|
|
842
847
|
|
|
843
848
|
// Bind Cloudflare env to ALS so getCloudflareBindings() works at runtime.
|
|
844
849
|
// Uses the same Symbol.for key as getCloudflareBindings() reads from.
|
|
@@ -873,15 +878,79 @@ function initPlatformTracer() {
|
|
|
873
878
|
return tracerInit
|
|
874
879
|
}
|
|
875
880
|
|
|
881
|
+
// The \`Vary\` tokens this cache can serve a correct answer for.
|
|
882
|
+
//
|
|
883
|
+
// Cloudflare's Cache API keys on the request URL. It does not implement
|
|
884
|
+
// RFC 9111 §4.1 secondary key selection, so a stored response is handed to
|
|
885
|
+
// every request for that URL regardless of what \`Vary\` nominates — except
|
|
886
|
+
// \`Accept-Encoding\`, which the platform segregates itself. Storing a
|
|
887
|
+
// response whose \`Vary\` says "this answer is specific to header H" under a
|
|
888
|
+
// key that ignores H is cross-client reuse (TIM-1269): a developer writing
|
|
889
|
+
// the correct \`public, s-maxage=60\` + \`Vary: Cookie\` gets their logged-in
|
|
890
|
+
// page served to anonymous visitors. Refusing to store is the conservative
|
|
891
|
+
// answer, and the only one available without rewriting the key.
|
|
892
|
+
//
|
|
893
|
+
// The framework's own tokens are on this list because the adapter already
|
|
894
|
+
// segregates them, more strictly than \`Vary\` would:
|
|
895
|
+
//
|
|
896
|
+
// - \`Accept\` — \`isRsc\` above excludes \`text/x-component\` from both lookup
|
|
897
|
+
// and store, so the HTML/Flight split \`Vary: Accept\` exists to protect
|
|
898
|
+
// never reaches this cache in the first place.
|
|
899
|
+
// - \`X-Timber-State-Tree\`, \`X-Timber-URL\`, \`X-Timber-Deployment-Id\` — the
|
|
900
|
+
// origin reads all three only on RSC requests (version skew at
|
|
901
|
+
// \`server/pipeline-phases.ts\`, interception rewrites likewise, state-tree
|
|
902
|
+
// diffing at \`server/rsc-entry/render-route.ts\`). On the non-RSC requests
|
|
903
|
+
// this cache stores, they cannot change the response.
|
|
904
|
+
//
|
|
905
|
+
// That second bullet is a coupling, not an observation: if any of those
|
|
906
|
+
// headers ever starts varying a document response, this list is wrong and
|
|
907
|
+
// the cache poisons. Because the list is derived, a header added to
|
|
908
|
+
// \`RSC_KEY_HEADERS\` inherits the exemption silently — so
|
|
909
|
+
// \`tests/adapters/cloudflare-vary.test.ts\` fails until that header is named
|
|
910
|
+
// there alongside the evidence for its gate, and the gates themselves are
|
|
911
|
+
// covered there, in \`tests/render-route.test.ts\`, and in
|
|
912
|
+
// \`tests/interception-x-timber-url.test.ts\`.
|
|
913
|
+
//
|
|
914
|
+
// Interpolated from \`RSC_KEY_HEADERS\` rather than spelled again — "which
|
|
915
|
+
// headers vary an RSC response" has one answer, and a hand-copied second
|
|
916
|
+
// list here would drift silently on the fallback path nobody exercises.
|
|
917
|
+
//
|
|
918
|
+
// Known residual: a route handler that content-negotiates on \`Accept\`
|
|
919
|
+
// (JSON vs HTML) *and* marks itself \`public\` is still mis-keyed, because the
|
|
920
|
+
// \`isRsc\` split is binary and does not separate those two. That is no worse
|
|
921
|
+
// than the pre-TIM-1269 behaviour, which stored every \`Vary\` but \`*\`.
|
|
922
|
+
const VARY_HONORED = new Set(${JSON.stringify(["accept-encoding", ...RSC_KEY_HEADERS.map((h) => h.toLowerCase())])})
|
|
923
|
+
|
|
924
|
+
// Applied to BOTH sides of the cache — what may be stored, and what a hit
|
|
925
|
+
// may serve. Refusing to store only stops new poisoning: entries a previous
|
|
926
|
+
// deployment wrote under the old predicate stay servable for whatever
|
|
927
|
+
// s-maxage the developer chose, which can be a day. Checking on the way out
|
|
928
|
+
// makes the fix take effect on deploy rather than on expiry, and costs one
|
|
929
|
+
// header read per hit. A rejected entry falls through to the origin and is
|
|
930
|
+
// then declined by the same predicate on the way back in, so it is not
|
|
931
|
+
// rewritten — it simply ages out.
|
|
932
|
+
function canHonorVary(vary) {
|
|
933
|
+
// Absent or empty Vary nominates nothing — the URL is the whole key.
|
|
934
|
+
if (!vary) return true
|
|
935
|
+
return vary.split(',').every((token) => VARY_HONORED.has(token.trim().toLowerCase()))
|
|
936
|
+
}
|
|
937
|
+
|
|
876
938
|
export default {
|
|
877
|
-
${
|
|
939
|
+
${handlersSpread} async fetch(request, env, ctx) {
|
|
878
940
|
// One-time on first request; resolved-promise await thereafter.
|
|
879
941
|
await initPlatformTracer()
|
|
880
942
|
|
|
881
943
|
// Edge-cache GET/HEAD responses via the Cache API. RSC navigation
|
|
882
|
-
// requests (Accept: text/x-component) are excluded
|
|
883
|
-
//
|
|
884
|
-
|
|
944
|
+
// requests (Accept: text/x-component) are excluded. Their varying
|
|
945
|
+
// inputs are now in the URL via ?_rsc= (TIM-1268), but this cache keys
|
|
946
|
+
// on the request URL alone and cannot honour Vary, so a payload request
|
|
947
|
+
// that arrives without the param — stripped query, hand-rolled client —
|
|
948
|
+
// would share a key with the document.
|
|
949
|
+
//
|
|
950
|
+
// This exclusion is load-bearing in the other direction too: the store
|
|
951
|
+
// predicate below treats "Vary: Accept" as honoured *because* of it
|
|
952
|
+
// (see VARY_HONORED). Removing it would make that allowlist unsound.
|
|
953
|
+
const isRsc = request.headers.get('Accept')?.includes(${JSON.stringify(RSC_CONTENT_TYPE)})
|
|
885
954
|
const reqCc = request.headers.get('Cache-Control') || ''
|
|
886
955
|
const bypassCache = reqCc.includes('no-cache') || reqCc.includes('max-age=0')
|
|
887
956
|
|| request.headers.has('Pragma')
|
|
@@ -890,7 +959,17 @@ ${hasWorkerHandlers ? " ...workerHandlers,\n" : ""} async fetch(request, env,
|
|
|
890
959
|
const cache = cacheable && typeof caches !== 'undefined' ? caches.default : null
|
|
891
960
|
if (cache) {
|
|
892
961
|
const cached = await cache.match(request)
|
|
893
|
-
|
|
962
|
+
// A hit whose Vary this cache cannot key on is treated as a miss —
|
|
963
|
+
// see canHonorVary. Entries written before that predicate existed are
|
|
964
|
+
// exactly the ones that would be served to the wrong client.
|
|
965
|
+
if (cached) {
|
|
966
|
+
if (canHonorVary(cached.headers.get('Vary'))) return cached
|
|
967
|
+
// Declining the hit means nobody will ever read this body. Release
|
|
968
|
+
// it rather than leaving the stream dangling for the rest of the
|
|
969
|
+
// request (design/02-rendering-pipeline.md §"Cancel Readers When You
|
|
970
|
+
// No Longer Need the Stream").
|
|
971
|
+
cached.body?.cancel().catch(() => {})
|
|
972
|
+
}
|
|
894
973
|
}
|
|
895
974
|
|
|
896
975
|
// Bridge ctx.cache into the per-request ALS so WorkersCachePurge can
|
|
@@ -913,10 +992,10 @@ ${hasWorkerHandlers ? " ...workerHandlers,\n" : ""} async fetch(request, env,
|
|
|
913
992
|
// See design/25-production-deployments.md §"CDN / Edge Cache".
|
|
914
993
|
if (cache && request.method === 'GET' && response.status === 200) {
|
|
915
994
|
const cc = response.headers.get('Cache-Control')
|
|
916
|
-
const vary = response.headers.get('Vary')
|
|
917
995
|
if (cc && !cc.includes('no-store') && !cc.includes('private')
|
|
918
996
|
&& (cc.includes('public') || cc.includes('s-maxage'))
|
|
919
|
-
&&
|
|
997
|
+
&& canHonorVary(response.headers.get('Vary'))
|
|
998
|
+
&& !response.headers.has('Set-Cookie')) {
|
|
920
999
|
ctx.waitUntil(cache.put(request, response.clone()))
|
|
921
1000
|
}
|
|
922
1001
|
}
|
|
@@ -1169,8 +1248,7 @@ function generateWranglerConfig(config, options, userConfig) {
|
|
|
1169
1248
|
*/
|
|
1170
1249
|
async function buildStaticOutput(config, buildDir, outDir, _options) {
|
|
1171
1250
|
await buildStaticDirectoryOutput(config, buildDir, outDir, ".");
|
|
1172
|
-
|
|
1173
|
-
await writeFile(join(outDir, "_headers"), generateHeadersFile(unhashedPaths, config.staticContentTypes));
|
|
1251
|
+
await writeHeadersFile(outDir, config, await findUnhashedStaticFiles(outDir));
|
|
1174
1252
|
}
|
|
1175
1253
|
/** @internal Exported for testing. */
|
|
1176
1254
|
function generatePreviewCommand(buildDir) {
|
|
@@ -1203,4 +1281,4 @@ function spawnPreviewProcess(command, args, cwd) {
|
|
|
1203
1281
|
//#endregion
|
|
1204
1282
|
export { generatePreviewCommand as a, generateWranglerConfig as c, readUserWranglerConfig as d, runWithBindings as f, generatePrebuiltSourceModule as i, getCloudflareBindings as l, cloudflare as n, generateRuntimeInitModule as o, generateBindingsConfig as r, generateWorkerEntry as s, buildStaticOutput as t, readPrebuiltData as u };
|
|
1205
1283
|
|
|
1206
|
-
//# sourceMappingURL=cloudflare-
|
|
1284
|
+
//# sourceMappingURL=cloudflare-CGP6BZKO.js.map
|