@timber-js/app 0.2.0-alpha.18 → 0.2.0-alpha.180
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/LICENSE +8 -0
- package/agent-skill.md +344 -0
- package/dist/_chunks/actions-O_LsyCE4.js +317 -0
- package/dist/_chunks/actions-O_LsyCE4.js.map +1 -0
- package/dist/_chunks/build-output-helper-DF5uScqS.js +158 -0
- package/dist/_chunks/build-output-helper-DF5uScqS.js.map +1 -0
- package/dist/_chunks/cache-api-B-lhk9p4.js +1202 -0
- package/dist/_chunks/cache-api-B-lhk9p4.js.map +1 -0
- package/dist/_chunks/canonicalize-DQHyFClh.js +248 -0
- package/dist/_chunks/canonicalize-DQHyFClh.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-D3naS3eH.js +688 -0
- package/dist/_chunks/cli-schema-sync-D3naS3eH.js.map +1 -0
- package/dist/_chunks/cloudflare-AHoWYTYr.js +1188 -0
- package/dist/_chunks/cloudflare-AHoWYTYr.js.map +1 -0
- package/dist/_chunks/codec-registry-oOUxugz3.js +21 -0
- package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -0
- package/dist/_chunks/define-COtkxMRT.js +191 -0
- package/dist/_chunks/define-COtkxMRT.js.map +1 -0
- package/dist/_chunks/define-c4au4I9R.js +82 -0
- package/dist/_chunks/define-c4au4I9R.js.map +1 -0
- package/dist/_chunks/dist-BA3u1z3W.js +423 -0
- package/dist/_chunks/dist-BA3u1z3W.js.map +1 -0
- package/dist/_chunks/fast-hash-D6hIVt1Y.js +36 -0
- package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +1 -0
- package/dist/_chunks/format-CfwjgPz9.js +14 -0
- package/dist/_chunks/format-CfwjgPz9.js.map +1 -0
- package/dist/_chunks/href-validation-CMc5JRls.js +141 -0
- package/dist/_chunks/href-validation-CMc5JRls.js.map +1 -0
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js +63 -0
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +1 -0
- package/dist/_chunks/logger-AWfuX-KJ.js +1468 -0
- package/dist/_chunks/logger-AWfuX-KJ.js.map +1 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js +124 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -0
- package/dist/_chunks/plugin-context---kTF5v8.js +315 -0
- package/dist/_chunks/plugin-context---kTF5v8.js.map +1 -0
- package/dist/_chunks/registry-DbJPKoBp.js +20 -0
- package/dist/_chunks/registry-DbJPKoBp.js.map +1 -0
- package/dist/_chunks/resolve-schema-Dz3fcFUo.js +50 -0
- package/dist/_chunks/resolve-schema-Dz3fcFUo.js.map +1 -0
- package/dist/_chunks/router-ref-CtmF-aPv.js +28 -0
- package/dist/_chunks/router-ref-CtmF-aPv.js.map +1 -0
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +119 -0
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +1 -0
- package/dist/_chunks/segment-classify-Byy425ng.js +176 -0
- package/dist/_chunks/segment-classify-Byy425ng.js.map +1 -0
- package/dist/_chunks/segment-context-ZDnXDkbz.js +34 -0
- package/dist/_chunks/segment-context-ZDnXDkbz.js.map +1 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js +35 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-BOWsq18U.js} +1 -1
- package/dist/_chunks/ssr-data-BOWsq18U.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-DFvWd-EA.js} +71 -26
- package/dist/_chunks/use-query-states-DFvWd-EA.js.map +1 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js +151 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -0
- package/dist/_chunks/walkers-BtTlKviE.js +1002 -0
- package/dist/_chunks/walkers-BtTlKviE.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +29 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +73 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +65 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +124 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +189 -21
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -188
- package/dist/adapters/compress-module.d.ts +5 -4
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +41 -3
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +224 -172
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/types.d.ts +2 -6
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/cache-api.d.ts +48 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/handler-store.d.ts +33 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +31 -8
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -326
- package/dist/cache/invalidation-epoch.d.ts +43 -0
- package/dist/cache/invalidation-epoch.d.ts.map +1 -0
- package/dist/cache/json-lossy-check.d.ts +11 -0
- package/dist/cache/json-lossy-check.d.ts.map +1 -0
- package/dist/cache/redis-handler.d.ts +140 -8
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +19 -2
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts +22 -0
- package/dist/cache/sizeof.d.ts.map +1 -0
- package/dist/cache/stable-stringify.d.ts +9 -0
- package/dist/cache/stable-stringify.d.ts.map +1 -1
- package/dist/cache/store.d.ts +53 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
- package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.js +29 -0
- package/dist/cache/stores/cloudflare-kv.js.map +1 -0
- package/dist/cache/stores/memory.d.ts +42 -0
- package/dist/cache/stores/memory.d.ts.map +1 -0
- package/dist/cache/stores/memory.js +90 -0
- package/dist/cache/stores/memory.js.map +1 -0
- package/dist/cache/stores/redis.d.ts +69 -0
- package/dist/cache/stores/redis.d.ts.map +1 -0
- package/dist/cache/stores/redis.js +35 -0
- package/dist/cache/stores/redis.js.map +1 -0
- package/dist/cache/stores/vercel.d.ts +36 -0
- package/dist/cache/stores/vercel.d.ts.map +1 -0
- package/dist/cache/stores/vercel.js +33 -0
- package/dist/cache/stores/vercel.js.map +1 -0
- package/dist/cache/tag-aware-handler.d.ts +52 -0
- package/dist/cache/tag-aware-handler.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts +20 -10
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cdn/cloudflare-purge.d.ts +23 -0
- package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
- package/dist/cdn/fastly-purge.d.ts +25 -0
- package/dist/cdn/fastly-purge.d.ts.map +1 -0
- package/dist/cdn/headers.d.ts +97 -0
- package/dist/cdn/headers.d.ts.map +1 -0
- package/dist/cdn/index.d.ts +5 -0
- package/dist/cdn/index.d.ts.map +1 -0
- package/dist/cdn/purge-store.d.ts +23 -0
- package/dist/cdn/purge-store.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.d.ts +16 -0
- package/dist/cdn/workers-cache-purge.d.ts.map +1 -0
- package/dist/cli-schema-sync.d.ts +59 -0
- package/dist/cli-schema-sync.d.ts.map +1 -0
- package/dist/cli.d.ts +35 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +113 -34
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +37 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +46 -0
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
- package/dist/client/browser-entry/index.d.ts +29 -0
- package/dist/client/browser-entry/index.d.ts.map +1 -0
- package/dist/client/browser-entry/post-hydration.d.ts +26 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +27 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +28 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/error-boundary.d.ts +12 -5
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +47 -10
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +61 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +16 -27
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/history.d.ts +21 -6
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +10 -24
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +185 -1134
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +19 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +887 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link.d.ts +69 -60
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-api.d.ts +121 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +3 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +119 -0
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts +1 -1
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/router.d.ts +99 -14
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +48 -15
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +26 -7
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +57 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/segment-update-context.d.ts +21 -0
- package/dist/client/segment-update-context.d.ts.map +1 -0
- package/dist/client/shallow-url.d.ts +10 -0
- package/dist/client/shallow-url.d.ts.map +1 -0
- package/dist/client/slot-context.d.ts +31 -0
- package/dist/client/slot-context.d.ts.map +1 -0
- package/dist/client/slot-outlet.d.ts +16 -0
- package/dist/client/slot-outlet.d.ts.map +1 -0
- package/dist/client/slot-provider.d.ts +25 -0
- package/dist/client/slot-provider.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +13 -4
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/state.d.ts +1 -1
- package/dist/client/top-loader.d.ts +5 -5
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts +12 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-link-status.d.ts +5 -5
- package/dist/client/use-link-status.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts.map +1 -1
- package/dist/client/use-pending-navigation.d.ts +23 -0
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +12 -5
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +8 -6
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +69 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +76 -0
- package/dist/codec.js.map +1 -0
- package/dist/config-types.d.ts +284 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-validation.d.ts +51 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts +58 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +2 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +257 -36
- package/dist/cookies/index.js.map +1 -1
- package/dist/cookies/json-cookie.d.ts +64 -0
- package/dist/cookies/json-cookie.d.ts.map +1 -0
- package/dist/cookies/validation.d.ts +34 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +50 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +40 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/dev-page-shell.d.ts +78 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +32 -0
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/dev-tools/holding-server.d.ts +54 -0
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/hydration-overlay.d.ts +11 -0
- package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/dev-tools/instrumentation.d.ts +59 -0
- package/dist/dev-tools/instrumentation.d.ts.map +1 -0
- package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
- package/dist/dev-tools/logger.d.ts.map +1 -0
- package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +17 -3
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/dev-tools/overlay.d.ts +91 -0
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/dev-tools/terminal.d.ts +28 -0
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/fonts/ast-walk.d.ts +68 -0
- package/dist/fonts/ast-walk.d.ts.map +1 -0
- package/dist/fonts/ast.d.ts +110 -6
- package/dist/fonts/ast.d.ts.map +1 -1
- package/dist/fonts/bundle.d.ts +50 -0
- package/dist/fonts/bundle.d.ts.map +1 -0
- package/dist/fonts/dev-middleware.d.ts +22 -0
- package/dist/fonts/dev-middleware.d.ts.map +1 -0
- package/dist/fonts/fallbacks.d.ts +0 -7
- package/dist/fonts/fallbacks.d.ts.map +1 -1
- package/dist/fonts/google.d.ts +4 -2
- package/dist/fonts/google.d.ts.map +1 -1
- package/dist/fonts/local.d.ts +4 -4
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/paths.d.ts +43 -0
- package/dist/fonts/paths.d.ts.map +1 -0
- package/dist/fonts/pipeline.d.ts +177 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +82 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +47 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +77 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +46 -180
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9243 -14093
- package/dist/index.js.map +1 -1
- package/dist/params/codec-registry.d.ts +26 -0
- package/dist/params/codec-registry.d.ts.map +1 -0
- package/dist/params/define-schema.d.ts +81 -0
- package/dist/params/define-schema.d.ts.map +1 -0
- package/dist/params/index.d.ts +5 -0
- package/dist/params/index.d.ts.map +1 -0
- package/dist/params/index.js +34 -0
- package/dist/params/index.js.map +1 -0
- package/dist/params/resolve-schema.d.ts +34 -0
- package/dist/params/resolve-schema.d.ts.map +1 -0
- package/dist/plugin-context.d.ts +217 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +21 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +7 -3
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +43 -7
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/cache.d.ts +64 -0
- package/dist/plugins/cache.d.ts.map +1 -0
- package/dist/plugins/callsite-ast.d.ts +117 -0
- package/dist/plugins/callsite-ast.d.ts.map +1 -0
- package/dist/plugins/callsite-jsx.d.ts +35 -0
- package/dist/plugins/callsite-jsx.d.ts.map +1 -0
- package/dist/plugins/chunks.d.ts +11 -4
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +40 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/cloudflare-wasm.d.ts +21 -0
- package/dist/plugins/cloudflare-wasm.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +17 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +28 -4
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +16 -73
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +1 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/prebuilt-capture.d.ts +60 -0
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts +40 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts.map +1 -0
- package/dist/plugins/prebuilt.d.ts +82 -0
- package/dist/plugins/prebuilt.d.ts.map +1 -0
- package/dist/plugins/prerender-sugar.d.ts +42 -0
- package/dist/plugins/prerender-sugar.d.ts.map +1 -0
- package/dist/plugins/request-dep.d.ts +21 -0
- package/dist/plugins/request-dep.d.ts.map +1 -0
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts +29 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +5 -26
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +67 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +64 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +7 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts +41 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/export-detect.d.ts +56 -0
- package/dist/routing/export-detect.d.ts.map +1 -0
- package/dist/routing/file-cache.d.ts +8 -0
- package/dist/routing/file-cache.d.ts.map +1 -0
- package/dist/routing/index.d.ts +7 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +4 -2
- package/dist/routing/interception.d.ts +0 -5
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +90 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/manifest-codegen.d.ts +32 -0
- package/dist/routing/manifest-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +1 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/schema-validation.d.ts +35 -0
- package/dist/routing/schema-validation.d.ts.map +1 -0
- package/dist/routing/segment-classify.d.ts +81 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/segment-codegen.d.ts +38 -0
- package/dist/routing/segment-codegen.d.ts.map +1 -0
- package/dist/routing/types.d.ts +81 -25
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +51 -0
- package/dist/routing/walkers.d.ts.map +1 -0
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +91 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +188 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +34 -441
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/registry.d.ts +2 -2
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/segment-params/define.d.ts +89 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +3 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +2 -0
- package/dist/server/access-gate.d.ts +8 -3
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +42 -7
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts +35 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +6 -30
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +93 -11
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +8 -18
- package/dist/server/asset-headers.d.ts.map +1 -1
- package/dist/server/body-limits.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +12 -29
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/canonicalize.d.ts +10 -0
- package/dist/server/canonicalize.d.ts.map +1 -1
- package/dist/server/coalesce-tick.d.ts +40 -0
- package/dist/server/coalesce-tick.d.ts.map +1 -0
- package/dist/server/cookie-context.d.ts +170 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +65 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/csrf.d.ts +3 -2
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +117 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +2 -2
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-source-map.d.ts +22 -0
- package/dist/server/dev-source-map.d.ts.map +1 -0
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -11
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +12 -7
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/form-data.d.ts +41 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +242 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +82 -41
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +11 -47
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +182 -2906
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +49 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +3892 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +39 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/metadata-routes.d.ts +60 -11
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata.d.ts +8 -0
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +19 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +119 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +54 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +95 -0
- package/dist/server/pipeline-helpers.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +6 -0
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +59 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +140 -19
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +117 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/prebuilt/cache-key.d.ts +62 -0
- package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +57 -0
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
- package/dist/server/prebuilt/key-discipline.d.ts +23 -0
- package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
- package/dist/server/prebuilt/overlay.d.ts +100 -0
- package/dist/server/prebuilt/overlay.d.ts.map +1 -0
- package/dist/server/prebuilt/payload-source.d.ts +78 -0
- package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +99 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -0
- package/dist/server/prebuilt/synthetic-store.d.ts +66 -0
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts +120 -0
- package/dist/server/prebuilt-builder.d.ts.map +1 -0
- package/dist/server/prebuilt-runtime.d.ts +111 -0
- package/dist/server/prebuilt-runtime.d.ts.map +1 -0
- package/dist/server/primitives.d.ts +88 -43
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/render-utils.d.ts +25 -0
- package/dist/server/render-utils.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +62 -107
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-dep.d.ts +15 -0
- package/dist/server/request-dep.d.ts.map +1 -0
- package/dist/server/route-element-builder.d.ts +53 -25
- 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 +25 -36
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts +12 -3
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +29 -0
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
- package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +69 -37
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +28 -6
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +51 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +108 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts +6 -6
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +25 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +36 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +89 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/sensitive-fields.d.ts +74 -0
- package/dist/server/sensitive-fields.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +129 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +66 -5
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +121 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -0
- package/dist/server/ssr-entry.d.ts +2 -43
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +64 -21
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +50 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/state-tree-diff.d.ts +72 -9
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +22 -11
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +47 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +44 -9
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +69 -30
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/tree-match.d.ts +49 -0
- package/dist/server/tree-match.d.ts.map +1 -0
- package/dist/server/types.d.ts +71 -6
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/utils/mdx-file.d.ts +15 -0
- package/dist/server/utils/mdx-file.d.ts.map +1 -0
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/workers-cache-bridge.d.ts +26 -0
- package/dist/server/workers-cache-bridge.d.ts.map +1 -0
- package/dist/shared/href-validation.d.ts +49 -0
- package/dist/shared/href-validation.d.ts.map +1 -0
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shared/redirect-type.d.ts +17 -0
- package/dist/shared/redirect-type.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.d.ts +26 -0
- package/dist/shims/font-local.d.ts.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/dist/shims/headers.d.ts +53 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/image.d.ts +120 -120
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +35 -11
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +11 -5
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +233 -0
- package/docs/api/31-api-client.mdx +161 -0
- package/docs/api/32-api-cache.mdx +311 -0
- package/docs/api/33-api-search-params.mdx +154 -0
- package/docs/api/34-api-config.mdx +325 -0
- package/docs/api/35-api-typescript.mdx +170 -0
- package/docs/api/36-cli.mdx +143 -0
- package/docs/learn/00-introduction.mdx +109 -0
- package/docs/learn/01-quick-start.mdx +94 -0
- package/docs/learn/02-pages-and-layouts.mdx +147 -0
- package/docs/learn/03-fetching-data.mdx +211 -0
- package/docs/learn/03b-access-control.mdx +130 -0
- package/docs/learn/04-loading-states.mdx +67 -0
- package/docs/learn/04b-the-flush-point.mdx +115 -0
- package/docs/learn/05-typed-params.mdx +275 -0
- package/docs/learn/06-forms-and-actions.mdx +146 -0
- package/docs/learn/07-typed-routes.mdx +127 -0
- package/docs/learn/08-streaming.mdx +146 -0
- package/docs/learn/09-caching.mdx +252 -0
- package/docs/learn/10-middleware.mdx +157 -0
- package/docs/learn/11-error-handling.mdx +156 -0
- package/docs/learn/12-client-navigation.mdx +176 -0
- package/docs/learn/13-configuration.mdx +162 -0
- package/docs/learn/14-deploying.mdx +264 -0
- package/docs/more/01-advanced-routing.mdx +173 -0
- package/docs/more/02-advanced-forms.mdx +137 -0
- package/docs/more/03-coming-from-nextjs.mdx +186 -0
- package/docs/more/04-metadata-and-fonts.mdx +193 -0
- package/docs/more/04b-mdx.mdx +209 -0
- package/docs/more/05-content-collections.mdx +90 -0
- package/docs/more/06-instrumentation.mdx +214 -0
- package/docs/more/07-security.mdx +129 -0
- package/docs/more/08-developer-experience.mdx +134 -0
- package/docs/more/40-why-timber.mdx +50 -0
- package/docs/more/41-timber-vs-nextjs.mdx +81 -0
- package/docs/more/42-timber-vs-others.mdx +68 -0
- package/docs/more/50-ai-agent-instructions.mdx +169 -0
- package/llms.txt +55 -0
- package/package.json +105 -26
- package/src/adapters/build-output-helper.ts +199 -0
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +204 -0
- package/src/adapters/cloudflare.ts +620 -129
- package/src/adapters/compress-module.ts +27 -92
- package/src/adapters/nitro.ts +266 -122
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/adapters/shared.ts +68 -0
- package/src/adapters/types.ts +2 -7
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +107 -0
- package/src/cache/handler-store.ts +76 -0
- package/src/cache/index.ts +114 -21
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/json-lossy-check.ts +75 -0
- package/src/cache/redis-handler.ts +197 -19
- package/src/cache/singleflight.ts +64 -6
- package/src/cache/sizeof.ts +33 -0
- package/src/cache/stable-stringify.ts +65 -2
- package/src/cache/store.ts +71 -0
- package/src/cache/stores/cloudflare-kv.ts +52 -0
- package/src/cache/stores/memory.ts +125 -0
- package/src/cache/stores/redis.ts +97 -0
- package/src/cache/stores/vercel.ts +59 -0
- package/src/cache/tag-aware-handler.ts +237 -0
- package/src/cache/timber-cache.ts +161 -36
- package/src/cdn/cloudflare-purge.ts +50 -0
- package/src/cdn/fastly-purge.ts +63 -0
- package/src/cdn/headers.ts +153 -0
- package/src/cdn/index.ts +17 -0
- package/src/cdn/purge-store.ts +34 -0
- package/src/cdn/workers-cache-purge.ts +30 -0
- package/src/cli-schema-sync.ts +401 -0
- package/src/cli.ts +167 -34
- package/src/client/browser-dev.ts +156 -1
- package/src/client/browser-entry/action-dispatch.ts +124 -0
- package/src/client/browser-entry/hmr.ts +70 -0
- package/src/client/browser-entry/hydrate.ts +187 -0
- package/src/client/browser-entry/index.ts +113 -0
- package/src/client/browser-entry/post-hydration.ts +110 -0
- package/src/client/browser-entry/router-init.ts +286 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +50 -0
- package/src/client/error-boundary.tsx +127 -22
- package/src/client/error-reconstituter.tsx +79 -0
- package/src/client/form.tsx +31 -32
- package/src/client/history.ts +21 -6
- package/src/client/index.ts +67 -45
- package/src/client/internal.ts +58 -0
- package/src/client/link.tsx +349 -150
- package/src/client/navigation-api.ts +345 -0
- package/src/client/navigation-context.ts +15 -7
- package/src/client/navigation-root.tsx +355 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +565 -212
- package/src/client/rsc-fetch.ts +215 -34
- package/src/client/segment-cache.ts +91 -17
- package/src/client/segment-outlet.tsx +141 -0
- package/src/client/segment-update-context.ts +42 -0
- package/src/client/shallow-url.ts +22 -0
- package/src/client/slot-context.ts +50 -0
- package/src/client/slot-outlet.tsx +22 -0
- package/src/client/slot-provider.tsx +32 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/state.ts +2 -2
- package/src/client/top-loader.tsx +11 -9
- package/src/client/use-cookie.ts +60 -15
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-pathname.ts +1 -0
- package/src/client/use-pending-navigation.ts +40 -0
- package/src/client/use-query-states.ts +108 -10
- package/src/client/use-router.ts +4 -1
- package/src/client/use-search-params.ts +31 -44
- package/src/client/{use-params.ts → use-segment-params.ts} +9 -6
- package/src/codec.ts +149 -0
- package/src/config-types.ts +282 -0
- package/src/config-validation.ts +330 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +217 -53
- package/src/cookies/index.ts +12 -1
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +192 -0
- package/src/dev-tools/404-page.ts +286 -0
- package/src/dev-tools/browser-logs.ts +55 -0
- package/src/dev-tools/dev-page-shell.ts +260 -0
- package/src/dev-tools/error-page.ts +331 -0
- package/src/dev-tools/holding-server.ts +187 -0
- package/src/dev-tools/hydration-overlay.ts +158 -0
- package/src/dev-tools/index.ts +83 -0
- package/src/dev-tools/instrumentation.ts +213 -0
- package/src/{server/dev-logger.ts → dev-tools/logger.ts} +33 -51
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +122 -26
- package/src/dev-tools/overlay.ts +469 -0
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +182 -0
- package/src/fonts/ast-walk.ts +235 -0
- package/src/fonts/ast.ts +477 -126
- package/src/fonts/bundle.ts +138 -0
- package/src/fonts/dev-middleware.ts +85 -0
- package/src/fonts/fallbacks.ts +0 -23
- package/src/fonts/google.ts +100 -18
- package/src/fonts/local.ts +9 -8
- package/src/fonts/paths.ts +58 -0
- package/src/fonts/pipeline.ts +348 -0
- package/src/fonts/transform.ts +311 -0
- package/src/fonts/types.ts +52 -1
- package/src/fonts/virtual-modules.ts +179 -0
- package/src/index.ts +446 -352
- package/src/params/codec-registry.ts +34 -0
- package/src/params/define-schema.ts +115 -0
- package/src/params/index.ts +17 -0
- package/src/params/resolve-schema.ts +84 -0
- package/src/plugin-context.ts +432 -0
- package/src/plugins/adapter-build.ts +220 -7
- package/src/plugins/build-manifest.ts +177 -23
- package/src/plugins/build-report.ts +253 -35
- package/src/plugins/cache.ts +243 -0
- package/src/plugins/callsite-ast.ts +472 -0
- package/src/plugins/callsite-jsx.ts +243 -0
- package/src/plugins/chunks.ts +74 -5
- package/src/plugins/client-chunks.ts +185 -0
- package/src/plugins/cloudflare-wasm.ts +141 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-server.ts +284 -94
- package/src/plugins/entries.ts +134 -16
- package/src/plugins/fonts.ts +225 -660
- package/src/plugins/mdx.ts +47 -10
- package/src/plugins/prebuilt-capture.ts +217 -0
- package/src/plugins/prebuilt-options-analysis.ts +175 -0
- package/src/plugins/prebuilt.ts +655 -0
- package/src/plugins/prerender-sugar.ts +328 -0
- package/src/plugins/request-dep.ts +458 -0
- package/src/plugins/routing.ts +237 -241
- package/src/plugins/server-bundle.ts +89 -12
- package/src/plugins/shims.ts +241 -64
- package/src/plugins/static-build.ts +15 -90
- package/src/routing/codegen-shared.ts +115 -0
- package/src/routing/codegen-types.ts +65 -0
- package/src/routing/codegen.ts +372 -178
- package/src/routing/convention-lint.ts +394 -0
- package/src/routing/export-detect.ts +304 -0
- package/src/routing/file-cache.ts +23 -0
- package/src/routing/index.ts +10 -1
- package/src/routing/interception.ts +3 -22
- package/src/routing/link-codegen.ts +313 -0
- package/src/routing/manifest-codegen.ts +287 -0
- package/src/routing/scanner.ts +338 -189
- package/src/routing/schema-validation.ts +155 -0
- package/src/routing/segment-classify.ts +223 -0
- package/src/routing/segment-codegen.ts +98 -0
- package/src/routing/types.ts +82 -25
- package/src/routing/walkers.ts +90 -0
- package/src/rsc-runtime/rsc.ts +9 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/schema-bridge.ts +253 -0
- package/src/search-params/define.ts +576 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +101 -0
- package/src/segment-params/define.ts +249 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +111 -34
- package/src/server/action-client.ts +120 -29
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +123 -33
- package/src/server/actions.ts +48 -54
- package/src/server/als-registry.ts +137 -20
- package/src/server/asset-headers.ts +15 -37
- package/src/server/body-limits.ts +10 -2
- package/src/server/build-manifest.ts +19 -56
- package/src/server/canonicalize.ts +6 -3
- package/src/server/coalesce-tick.ts +75 -0
- package/src/server/compress.ts +34 -7
- package/src/server/cookie-context.ts +484 -0
- package/src/server/cookie-parsing.ts +163 -0
- package/src/server/csrf.ts +39 -6
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-boundary.ts +314 -0
- package/src/server/deny-renderer.ts +85 -77
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/early-hints.ts +37 -27
- package/src/server/error-boundary-wrapper.ts +61 -22
- package/src/server/fallback-error.ts +79 -102
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/form-data.ts +124 -12
- package/src/server/html-injector-core.ts +495 -0
- package/src/server/html-injectors.ts +271 -254
- package/src/server/index.ts +31 -185
- package/src/server/internal.ts +181 -0
- package/src/server/logger.ts +72 -36
- package/src/server/metadata-routes.ts +205 -24
- package/src/server/metadata.ts +21 -0
- package/src/server/middleware-runner.ts +31 -4
- package/src/server/node-stream-transforms.ts +336 -0
- package/src/server/param-coercion.ts +207 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +45 -18
- package/src/server/pipeline-metadata.ts +14 -0
- package/src/server/pipeline-outcome.ts +197 -0
- package/src/server/pipeline-phases.ts +545 -0
- package/src/server/pipeline.ts +274 -382
- package/src/server/port-resolution.ts +215 -0
- package/src/server/prebuilt/cache-key.ts +298 -0
- package/src/server/prebuilt/capture-state.ts +89 -0
- package/src/server/prebuilt/key-discipline.ts +53 -0
- package/src/server/prebuilt/manifest-tag-index.ts +46 -0
- package/src/server/prebuilt/overlay.ts +256 -0
- package/src/server/prebuilt/payload-source.ts +201 -0
- package/src/server/prebuilt/slots.ts +190 -0
- package/src/server/prebuilt/synthetic-store.ts +121 -0
- package/src/server/prebuilt-builder.ts +809 -0
- package/src/server/prebuilt-runtime.ts +815 -0
- package/src/server/primitives.ts +160 -83
- package/src/server/render-timeout.ts +108 -0
- package/src/server/render-utils.ts +31 -0
- package/src/server/request-context.ts +170 -337
- package/src/server/request-dep.ts +37 -0
- package/src/server/route-element-builder.ts +699 -295
- package/src/server/route-handler.ts +31 -4
- package/src/server/route-matcher.ts +158 -277
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +69 -32
- package/src/server/rsc-entry/deny-fallback.ts +92 -0
- package/src/server/rsc-entry/error-renderer.ts +306 -89
- package/src/server/rsc-entry/helpers.ts +210 -85
- package/src/server/rsc-entry/index.ts +332 -332
- package/src/server/rsc-entry/render-route.ts +300 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +349 -0
- package/src/server/rsc-entry/rsc-payload.ts +102 -42
- package/src/server/rsc-entry/rsc-stream.ts +93 -13
- package/src/server/rsc-entry/ssr-bridge.ts +18 -5
- package/src/server/rsc-entry/ssr-renderer.ts +275 -43
- package/src/server/rsc-entry/wrap-action-dispatch.ts +186 -0
- package/src/server/safe-load.ts +60 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/server-only-guard-noop.js +3 -0
- package/src/server/sitemap-generator.ts +345 -0
- package/src/server/sitemap-handler.ts +157 -0
- package/src/server/slot-resolver.ts +574 -250
- package/src/server/ssr-bridge-types.ts +124 -0
- package/src/server/ssr-entry.ts +206 -86
- package/src/server/ssr-render.ts +345 -86
- package/src/server/ssr-wrappers.tsx +141 -0
- package/src/server/state-tree-diff.ts +177 -30
- package/src/server/status-code-resolver.ts +115 -130
- package/src/server/stream-utils.ts +288 -0
- package/src/server/tracing.ts +126 -14
- package/src/server/tree-builder.ts +214 -90
- package/src/server/tree-match.ts +262 -0
- package/src/server/types.ts +78 -9
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/utils/mdx-file.ts +22 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/workers-cache-bridge.ts +33 -0
- package/src/shared/href-validation.ts +159 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shared/redirect-type.ts +17 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +122 -1
- package/src/shims/navigation-client.ts +51 -29
- package/src/shims/navigation.ts +14 -7
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js +0 -41
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-B3Gypr3D.js +0 -108
- package/dist/_chunks/debug-B3Gypr3D.js.map +0 -1
- package/dist/_chunks/format-RyoGQL74.js +0 -164
- package/dist/_chunks/format-RyoGQL74.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js +0 -676
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/metadata-routes-Cjmvi3rQ.js +0 -153
- package/dist/_chunks/metadata-routes-Cjmvi3rQ.js.map +0 -1
- package/dist/_chunks/request-context-BQUC8PHn.js +0 -330
- package/dist/_chunks/request-context-BQUC8PHn.js.map +0 -1
- package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
- package/dist/_chunks/tracing-CemImE6h.js +0 -187
- package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
- package/dist/adapters/cloudflare.js.map +0 -1
- package/dist/cache/index.js.map +0 -1
- package/dist/cache/register-cached-function.d.ts +0 -17
- package/dist/cache/register-cached-function.d.ts.map +0 -1
- package/dist/client/browser-entry.d.ts +0 -21
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/head.d.ts +0 -16
- package/dist/client/head.d.ts.map +0 -1
- package/dist/client/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/client/segment-merger.d.ts +0 -119
- package/dist/client/segment-merger.d.ts.map +0 -1
- package/dist/client/stale-reload.d.ts +0 -44
- package/dist/client/stale-reload.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts +0 -74
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts +0 -26
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts +0 -60
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/plugins/server-action-exports.d.ts +0 -26
- package/dist/plugins/server-action-exports.d.ts.map +0 -1
- package/dist/routing/status-file-lint.d.ts +0 -33
- package/dist/routing/status-file-lint.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/codecs.d.ts +0 -53
- package/dist/search-params/codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/server/client-module-map.d.ts +0 -47
- package/dist/server/client-module-map.d.ts.map +0 -1
- package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
- package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts +0 -29
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts +0 -129
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/flush.d.ts +0 -74
- package/dist/server/flush.d.ts.map +0 -1
- package/dist/server/manifest-status-resolver.d.ts +0 -58
- package/dist/server/manifest-status-resolver.d.ts.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/utils/directive-parser.d.ts +0 -70
- package/dist/utils/directive-parser.d.ts.map +0 -1
- package/src/cache/register-cached-function.ts +0 -103
- package/src/client/browser-entry.ts +0 -678
- package/src/client/head.ts +0 -61
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/segment-merger.ts +0 -339
- package/src/client/stale-reload.ts +0 -87
- package/src/client/transition-root.tsx +0 -166
- package/src/client/use-navigation-pending.ts +0 -38
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dev-error-overlay.ts +0 -230
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/plugins/server-action-exports.ts +0 -220
- package/src/routing/status-file-lint.ts +0 -112
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/codecs.ts +0 -153
- package/src/search-params/create.ts +0 -321
- package/src/server/client-module-map.ts +0 -58
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/dev-warnings.ts +0 -283
- package/src/server/flush.ts +0 -182
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/prerender.ts +0 -139
- package/src/utils/directive-parser.ts +0 -529
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convention linter — validates common misconfigurations in the route tree.
|
|
3
|
+
*
|
|
4
|
+
* Runs at scan time (build and dev startup). Each check produces a warning
|
|
5
|
+
* with the file path, what's wrong, and what to do about it.
|
|
6
|
+
*
|
|
7
|
+
* These are warnings, not errors — they don't block the build. The goal is
|
|
8
|
+
* to catch issues that would otherwise produce cryptic runtime behavior
|
|
9
|
+
* (silent 404s, empty pages, confusing React errors).
|
|
10
|
+
*
|
|
11
|
+
* Design doc: 07-routing.md, 10-error-handling.md
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { existsSync } from 'node:fs';
|
|
15
|
+
import type { RouteTree, SegmentNode } from './types.js';
|
|
16
|
+
import { swallow } from '../server/logger.js';
|
|
17
|
+
import {
|
|
18
|
+
fileHasAnyExport,
|
|
19
|
+
fileHasDefaultExport,
|
|
20
|
+
fileHasDirective,
|
|
21
|
+
fileHasStarExport,
|
|
22
|
+
} from './export-detect.js';
|
|
23
|
+
|
|
24
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export interface ConventionWarning {
|
|
27
|
+
/** Warning ID for deduplication and filtering. */
|
|
28
|
+
id: string;
|
|
29
|
+
/** Human-readable single-line summary. */
|
|
30
|
+
summary: string;
|
|
31
|
+
/** Multi-line details with file path and fix suggestion. */
|
|
32
|
+
details: string;
|
|
33
|
+
/** Severity: 'warn' for potential issues, 'error' for definite misconfigurations. */
|
|
34
|
+
level: 'warn' | 'error';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ─── Lint Rules ─────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Run all convention lint checks on a route tree.
|
|
41
|
+
*
|
|
42
|
+
* Returns an array of warnings. Empty array means everything looks good.
|
|
43
|
+
*/
|
|
44
|
+
export function lintConventions(tree: RouteTree, appDir: string): ConventionWarning[] {
|
|
45
|
+
const warnings: ConventionWarning[] = [];
|
|
46
|
+
|
|
47
|
+
// Check 1: app/ directory exists (caller should check before scanning,
|
|
48
|
+
// but we validate the root has at least one routable file)
|
|
49
|
+
checkEmptyApp(tree.root, appDir, warnings);
|
|
50
|
+
|
|
51
|
+
// Check 2: route.ts without recognized HTTP method exports
|
|
52
|
+
checkRouteExports(tree.root, warnings);
|
|
53
|
+
|
|
54
|
+
// Check 3: Segments with layout but no page/route anywhere in subtree
|
|
55
|
+
// (not a misconfiguration per se — layouts without pages are valid for
|
|
56
|
+
// route groups. Skip this check.)
|
|
57
|
+
|
|
58
|
+
// Check 4: Root segment has no layout.tsx (no HTML shell)
|
|
59
|
+
checkRootLayout(tree.root, warnings);
|
|
60
|
+
|
|
61
|
+
// Check 5: page.tsx / layout.tsx without default export
|
|
62
|
+
checkDefaultExports(tree.root, warnings);
|
|
63
|
+
|
|
64
|
+
// Check 6: error.tsx / global-error.tsx without 'use client' directive
|
|
65
|
+
checkErrorDirectives(tree.root, warnings);
|
|
66
|
+
if (tree.globalError && isScriptExtension(tree.globalError.extension)) {
|
|
67
|
+
checkFileUseClientDirective(tree.globalError.filePath, 'global-error', warnings);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return warnings;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── Check: Empty App ───────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Warn when the app/ directory has no routable files at all.
|
|
77
|
+
*
|
|
78
|
+
* This catches the "I created app/ but didn't add any pages" case where
|
|
79
|
+
* every request silently 404s with no guidance.
|
|
80
|
+
*/
|
|
81
|
+
function checkEmptyApp(root: SegmentNode, appDir: string, warnings: ConventionWarning[]): void {
|
|
82
|
+
if (hasAnyRoutable(root)) return;
|
|
83
|
+
|
|
84
|
+
warnings.push({
|
|
85
|
+
id: 'EMPTY_APP',
|
|
86
|
+
summary: 'No pages or route handlers found in app/',
|
|
87
|
+
details:
|
|
88
|
+
` Directory: ${appDir}\n\n` +
|
|
89
|
+
' Your app/ directory has no page.tsx or route.ts files.\n' +
|
|
90
|
+
' Every request will return 404.\n\n' +
|
|
91
|
+
' To fix: Create app/page.tsx with a default export:\n\n' +
|
|
92
|
+
' export default function Home() {\n return <h1>Hello</h1>;\n }\n',
|
|
93
|
+
level: 'warn',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Check if a segment tree has any routable files (page or route) anywhere.
|
|
99
|
+
*/
|
|
100
|
+
function hasAnyRoutable(node: SegmentNode): boolean {
|
|
101
|
+
if (node.page || node.route) return true;
|
|
102
|
+
for (const child of node.children) {
|
|
103
|
+
if (hasAnyRoutable(child)) return true;
|
|
104
|
+
}
|
|
105
|
+
for (const slot of Object.values(node.slots)) {
|
|
106
|
+
if (hasAnyRoutable(slot)) return true;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if a segment tree has any page files (not just route handlers).
|
|
113
|
+
* Used by checkRootLayout to avoid false positives for API-only apps (TIM-794).
|
|
114
|
+
* API-only apps (just route.ts handlers) don't need a root layout.
|
|
115
|
+
*/
|
|
116
|
+
function hasAnyPage(node: SegmentNode): boolean {
|
|
117
|
+
if (node.page) return true;
|
|
118
|
+
for (const child of node.children) {
|
|
119
|
+
if (hasAnyPage(child)) return true;
|
|
120
|
+
}
|
|
121
|
+
for (const slot of Object.values(node.slots)) {
|
|
122
|
+
if (hasAnyPage(slot)) return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ─── Check: Route Exports ───────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
/** HTTP methods that route.ts can export. */
|
|
130
|
+
const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Warn when a route.ts file doesn't appear to export any recognized HTTP methods.
|
|
134
|
+
*
|
|
135
|
+
* Uses AST-based detection via parseAst for precise matching.
|
|
136
|
+
* Falls back silently when the file can't be parsed (syntax errors produce
|
|
137
|
+
* no spurious warning — the TS compiler will catch those).
|
|
138
|
+
*/
|
|
139
|
+
function checkRouteExports(node: SegmentNode, warnings: ConventionWarning[]): void {
|
|
140
|
+
if (node.route) {
|
|
141
|
+
const filePath = node.route.filePath;
|
|
142
|
+
try {
|
|
143
|
+
const methods = fileHasAnyExport(filePath, HTTP_METHODS);
|
|
144
|
+
if (methods.size === 0 && !fileHasStarExport(filePath)) {
|
|
145
|
+
const hasDefault = fileHasDefaultExport(filePath);
|
|
146
|
+
const hint = hasDefault
|
|
147
|
+
? ' It looks like you have a default export. route.ts uses named exports\n' +
|
|
148
|
+
' for HTTP methods (GET, POST, etc.), not a default export.\n'
|
|
149
|
+
: '';
|
|
150
|
+
|
|
151
|
+
warnings.push({
|
|
152
|
+
id: 'ROUTE_NO_METHODS',
|
|
153
|
+
summary: `route.ts has no HTTP method exports: ${filePath}`,
|
|
154
|
+
details:
|
|
155
|
+
` File: ${filePath}\n\n` +
|
|
156
|
+
' route.ts files must export named HTTP method handlers.\n' +
|
|
157
|
+
' Without them, the route matches but returns 405 Method Not Allowed.\n\n' +
|
|
158
|
+
hint +
|
|
159
|
+
' Example:\n\n' +
|
|
160
|
+
' export function GET(ctx: RouteContext) {\n' +
|
|
161
|
+
" return Response.json({ hello: 'world' });\n" +
|
|
162
|
+
' }\n',
|
|
163
|
+
level: 'warn',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
swallow(err, `convention-lint: unreadable route.ts ${filePath}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Recurse
|
|
172
|
+
for (const child of node.children) {
|
|
173
|
+
checkRouteExports(child, warnings);
|
|
174
|
+
}
|
|
175
|
+
for (const slot of Object.values(node.slots)) {
|
|
176
|
+
checkRouteExports(slot, warnings);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ─── Check: Root Layout ─────────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Warn when the root segment has no layout.tsx.
|
|
184
|
+
*
|
|
185
|
+
* Without a root layout, there's no HTML shell (<html>, <body>).
|
|
186
|
+
* The page will render but may have hydration issues or no proper document structure.
|
|
187
|
+
*/
|
|
188
|
+
function checkRootLayout(root: SegmentNode, warnings: ConventionWarning[]): void {
|
|
189
|
+
if (root.layout) return;
|
|
190
|
+
|
|
191
|
+
// Only warn if there are pages — API-only apps (just route.ts handlers)
|
|
192
|
+
// don't need a root layout (TIM-794).
|
|
193
|
+
if (!hasAnyPage(root)) return;
|
|
194
|
+
|
|
195
|
+
warnings.push({
|
|
196
|
+
id: 'NO_ROOT_LAYOUT',
|
|
197
|
+
summary: 'No root layout.tsx found',
|
|
198
|
+
details:
|
|
199
|
+
' Your app has pages but no root layout.\n' +
|
|
200
|
+
' Without app/layout.tsx, pages have no <html> or <body> wrapper.\n\n' +
|
|
201
|
+
' To fix: Create app/layout.tsx:\n\n' +
|
|
202
|
+
' export default function RootLayout({ children }: { children: React.ReactNode }) {\n' +
|
|
203
|
+
' return (\n' +
|
|
204
|
+
' <html lang="en">\n' +
|
|
205
|
+
' <body>{children}</body>\n' +
|
|
206
|
+
' </html>\n' +
|
|
207
|
+
' );\n' +
|
|
208
|
+
' }\n',
|
|
209
|
+
level: 'warn',
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ─── Check: Default Exports ───────────────────────────────────────────
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Warn when page.tsx or layout.tsx files don't have a default export.
|
|
217
|
+
*
|
|
218
|
+
* Without a default export:
|
|
219
|
+
* - page.tsx: the page renders nothing (empty content)
|
|
220
|
+
* - layout.tsx: the layout module loads but has no component to render
|
|
221
|
+
*
|
|
222
|
+
* Uses AST-based detection via parseAst for precise matching. Falls back
|
|
223
|
+
* silently when the file can't be parsed (no spurious warning on syntax errors).
|
|
224
|
+
*/
|
|
225
|
+
function checkDefaultExports(node: SegmentNode, warnings: ConventionWarning[]): void {
|
|
226
|
+
// Check page files (tsx/ts/jsx/js only — not mdx, which is default-exported by the mdx compiler)
|
|
227
|
+
if (node.page && isScriptExtension(node.page.extension)) {
|
|
228
|
+
checkFileDefaultExport(node.page.filePath, 'page', warnings);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Check layout files
|
|
232
|
+
if (node.layout && isScriptExtension(node.layout.extension)) {
|
|
233
|
+
checkFileDefaultExport(node.layout.filePath, 'layout', warnings);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Recurse
|
|
237
|
+
for (const child of node.children) {
|
|
238
|
+
checkDefaultExports(child, warnings);
|
|
239
|
+
}
|
|
240
|
+
for (const slot of Object.values(node.slots)) {
|
|
241
|
+
checkDefaultExports(slot, warnings);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function isScriptExtension(ext: string): boolean {
|
|
246
|
+
return ext === 'tsx' || ext === 'ts' || ext === 'jsx' || ext === 'js';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function checkFileDefaultExport(
|
|
250
|
+
filePath: string,
|
|
251
|
+
fileType: string,
|
|
252
|
+
warnings: ConventionWarning[]
|
|
253
|
+
): void {
|
|
254
|
+
try {
|
|
255
|
+
if (!fileHasDefaultExport(filePath)) {
|
|
256
|
+
warnings.push({
|
|
257
|
+
id: `NO_DEFAULT_EXPORT:${filePath}`,
|
|
258
|
+
summary: `${fileType}.tsx has no default export: ${filePath}`,
|
|
259
|
+
details:
|
|
260
|
+
` File: ${filePath}\n\n` +
|
|
261
|
+
` ${fileType}.tsx files must export a default React component.\n` +
|
|
262
|
+
` Without a default export, the ${fileType === 'page' ? 'page renders nothing' : 'layout has no component to wrap children'}.\n\n` +
|
|
263
|
+
` To fix: Add a default export:\n\n` +
|
|
264
|
+
` export default function My${fileType === 'page' ? 'Page' : 'Layout'}(${fileType === 'layout' ? '{ children }' : ''}) {\n` +
|
|
265
|
+
` return ${fileType === 'layout' ? '<div>{children}</div>' : '<h1>Hello</h1>'};\n` +
|
|
266
|
+
` }\n`,
|
|
267
|
+
level: 'warn',
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
} catch (err) {
|
|
271
|
+
swallow(err, `convention-lint: unreadable ${fileType} file ${filePath}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ─── Check: Error Directive ─────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Warn when error.tsx or global-error.tsx is missing 'use client'.
|
|
279
|
+
*
|
|
280
|
+
* React's error boundary API requires client components. Without the directive,
|
|
281
|
+
* the error boundary silently fails — the component renders as a server component
|
|
282
|
+
* with no error catching. Users discover this only via cryptic runtime errors.
|
|
283
|
+
*/
|
|
284
|
+
function checkErrorDirectives(node: SegmentNode, warnings: ConventionWarning[]): void {
|
|
285
|
+
if (node.error && isScriptExtension(node.error.extension)) {
|
|
286
|
+
checkFileUseClientDirective(node.error.filePath, 'error', warnings);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
for (const child of node.children) {
|
|
290
|
+
checkErrorDirectives(child, warnings);
|
|
291
|
+
}
|
|
292
|
+
for (const slot of Object.values(node.slots)) {
|
|
293
|
+
checkErrorDirectives(slot, warnings);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function checkFileUseClientDirective(
|
|
298
|
+
filePath: string,
|
|
299
|
+
fileType: string,
|
|
300
|
+
warnings: ConventionWarning[]
|
|
301
|
+
): void {
|
|
302
|
+
try {
|
|
303
|
+
if (!fileHasDirective(filePath, 'use client')) {
|
|
304
|
+
warnings.push({
|
|
305
|
+
id: `ERROR_NO_USE_CLIENT:${filePath}`,
|
|
306
|
+
summary: `${fileType}.tsx is missing 'use client': ${filePath}`,
|
|
307
|
+
details:
|
|
308
|
+
` File: ${filePath}\n\n` +
|
|
309
|
+
` ${fileType}.tsx must start with 'use client' because React error\n` +
|
|
310
|
+
' boundaries require client components. Without it, the error boundary\n' +
|
|
311
|
+
' silently fails and errors are uncaught.\n\n' +
|
|
312
|
+
" To fix: Add 'use client' as the first line of the file:\n\n" +
|
|
313
|
+
" 'use client';\n\n" +
|
|
314
|
+
` export default function ${fileType === 'global-error' ? 'GlobalError' : 'ErrorBoundary'}({ error, reset }) {\n` +
|
|
315
|
+
' return <div><h2>Something went wrong</h2><button onClick={reset}>Try again</button></div>;\n' +
|
|
316
|
+
' }\n',
|
|
317
|
+
level: 'warn',
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
} catch (err) {
|
|
321
|
+
swallow(err, `convention-lint: unreadable ${fileType} file ${filePath}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ─── Check: App Directory Exists ────────────────────────────────────────────
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Check if the app/ directory exists. Called before scanning.
|
|
329
|
+
* Returns a warning if missing, or null if the directory exists.
|
|
330
|
+
*/
|
|
331
|
+
export function checkAppDirExists(appDir: string): ConventionWarning | null {
|
|
332
|
+
if (existsSync(appDir)) return null;
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
id: 'NO_APP_DIR',
|
|
336
|
+
summary: 'No app/ directory found',
|
|
337
|
+
details:
|
|
338
|
+
` Expected: ${appDir}\n\n` +
|
|
339
|
+
' timber.js requires an app/ directory for file-system routing.\n' +
|
|
340
|
+
' Every request will return 404 until you create it.\n\n' +
|
|
341
|
+
' To fix: Create the app/ directory with a page:\n\n' +
|
|
342
|
+
' mkdir -p app\n' +
|
|
343
|
+
' # Create app/layout.tsx and app/page.tsx\n',
|
|
344
|
+
level: 'error',
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ─── Formatting ─────────────────────────────────────────────────────────────
|
|
349
|
+
|
|
350
|
+
import type { InspectColor } from 'node:util';
|
|
351
|
+
import { styleText } from 'node:util';
|
|
352
|
+
|
|
353
|
+
type Format = InspectColor | readonly InspectColor[];
|
|
354
|
+
const noValidate = { validateStream: false } as const;
|
|
355
|
+
const style = (fmt: Format, text: string) => styleText(fmt, text, noValidate);
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Format warnings for terminal output.
|
|
359
|
+
*
|
|
360
|
+
* Groups by severity, uses colors, and includes fix suggestions.
|
|
361
|
+
*/
|
|
362
|
+
export function formatConventionWarnings(warnings: ConventionWarning[]): string {
|
|
363
|
+
if (warnings.length === 0) return '';
|
|
364
|
+
|
|
365
|
+
const errors = warnings.filter((w) => w.level === 'error');
|
|
366
|
+
const warns = warnings.filter((w) => w.level === 'warn');
|
|
367
|
+
|
|
368
|
+
const lines: string[] = [];
|
|
369
|
+
|
|
370
|
+
if (errors.length > 0) {
|
|
371
|
+
lines.push(
|
|
372
|
+
`${style(['red', 'bold'], '[timber]')} ${style('red', `${errors.length} configuration error${errors.length !== 1 ? 's' : ''}:`)}`
|
|
373
|
+
);
|
|
374
|
+
for (const e of errors) {
|
|
375
|
+
lines.push('');
|
|
376
|
+
lines.push(` ${style('red', '✗')} ${e.summary}`);
|
|
377
|
+
lines.push(style('dim', e.details));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (warns.length > 0) {
|
|
382
|
+
if (errors.length > 0) lines.push('');
|
|
383
|
+
lines.push(
|
|
384
|
+
`${style(['yellow', 'bold'], '[timber]')} ${style('yellow', `${warns.length} configuration warning${warns.length !== 1 ? 's' : ''}:`)}`
|
|
385
|
+
);
|
|
386
|
+
for (const w of warns) {
|
|
387
|
+
lines.push('');
|
|
388
|
+
lines.push(` ${style('yellow', '⚠')} ${w.summary}`);
|
|
389
|
+
lines.push(style('dim', w.details));
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return lines.join('\n');
|
|
394
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-based export detection for route files.
|
|
3
|
+
*
|
|
4
|
+
* Uses Vite's `parseAst` (backed by oxc) to precisely detect named and
|
|
5
|
+
* default exports, replacing the regex-based approach that was fragile
|
|
6
|
+
* with TypeScript syntax (type exports, `as` aliases, comments, etc.).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import { parseAst } from 'vite';
|
|
11
|
+
import { readFileCached } from './file-cache.js';
|
|
12
|
+
|
|
13
|
+
interface AstNode {
|
|
14
|
+
type: string;
|
|
15
|
+
exportKind?: string;
|
|
16
|
+
declaration?: AstNode;
|
|
17
|
+
specifiers?: Array<{
|
|
18
|
+
exported?: { name: string };
|
|
19
|
+
local?: { name: string };
|
|
20
|
+
exportKind?: string;
|
|
21
|
+
}>;
|
|
22
|
+
id?: { name: string };
|
|
23
|
+
declarations?: Array<{ id?: { name: string } }>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ProgramNode {
|
|
27
|
+
body: AstNode[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function tryParse(source: string): ProgramNode | null {
|
|
31
|
+
try {
|
|
32
|
+
return parseAst(source, { lang: 'tsx' }) as unknown as ProgramNode;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Collect all named export identifiers from a parsed program.
|
|
40
|
+
* Handles: `export function X`, `export const X`, `export { X }`,
|
|
41
|
+
* `export { X } from '...'`, `export { Y as X }`.
|
|
42
|
+
*/
|
|
43
|
+
function collectNamedExports(program: ProgramNode): Set<string> {
|
|
44
|
+
const names = new Set<string>();
|
|
45
|
+
for (const stmt of program.body) {
|
|
46
|
+
if (stmt.type !== 'ExportNamedDeclaration') continue;
|
|
47
|
+
// Skip `export type ...` declarations — they're erased at runtime
|
|
48
|
+
if (stmt.exportKind === 'type') continue;
|
|
49
|
+
|
|
50
|
+
if (stmt.declaration) {
|
|
51
|
+
if (stmt.declaration.id?.name) {
|
|
52
|
+
names.add(stmt.declaration.id.name);
|
|
53
|
+
}
|
|
54
|
+
if (stmt.declaration.declarations) {
|
|
55
|
+
for (const decl of stmt.declaration.declarations) {
|
|
56
|
+
if (decl.id?.name) names.add(decl.id.name);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (stmt.specifiers) {
|
|
62
|
+
for (const spec of stmt.specifiers) {
|
|
63
|
+
// Skip `export { type X }` — per-specifier type exports
|
|
64
|
+
if (spec.exportKind === 'type') continue;
|
|
65
|
+
if (spec.exported?.name && spec.exported.name !== 'default') {
|
|
66
|
+
names.add(spec.exported.name);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return names;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check whether a program has a default export.
|
|
76
|
+
* Handles: `export default ...`, `export { X as default }`,
|
|
77
|
+
* `export { default } from '...'`.
|
|
78
|
+
*/
|
|
79
|
+
function hasDefaultExport(program: ProgramNode): boolean {
|
|
80
|
+
for (const stmt of program.body) {
|
|
81
|
+
if (stmt.type === 'ExportDefaultDeclaration') return true;
|
|
82
|
+
if (stmt.type === 'ExportNamedDeclaration' && stmt.specifiers) {
|
|
83
|
+
for (const spec of stmt.specifiers) {
|
|
84
|
+
if (spec.exported?.name === 'default') return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check whether a program has any bare `export * from '...'` declarations.
|
|
93
|
+
* Excludes `export * as X from '...'` (namespace re-exports) since those
|
|
94
|
+
* create a namespace object, not individual top-level exports.
|
|
95
|
+
*/
|
|
96
|
+
function hasStarExport(program: ProgramNode): boolean {
|
|
97
|
+
return program.body.some(
|
|
98
|
+
(stmt) =>
|
|
99
|
+
stmt.type === 'ExportAllDeclaration' && !(stmt as any).exported && stmt.exportKind !== 'type'
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if a file exports a specific named export.
|
|
105
|
+
* Returns false if the file doesn't exist or can't be parsed.
|
|
106
|
+
*/
|
|
107
|
+
export function fileHasExport(filePath: string, exportName: string): boolean {
|
|
108
|
+
if (!existsSync(filePath)) return false;
|
|
109
|
+
try {
|
|
110
|
+
const source = readFileCached(filePath);
|
|
111
|
+
const program = tryParse(source);
|
|
112
|
+
if (!program) return false;
|
|
113
|
+
return collectNamedExports(program).has(exportName);
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Check if a file has any of the given named exports.
|
|
121
|
+
* Returns the set of matching export names.
|
|
122
|
+
*/
|
|
123
|
+
export function fileHasAnyExport(filePath: string, exportNames: readonly string[]): Set<string> {
|
|
124
|
+
const matches = new Set<string>();
|
|
125
|
+
try {
|
|
126
|
+
const source = readFileCached(filePath);
|
|
127
|
+
const program = tryParse(source);
|
|
128
|
+
if (!program) return matches;
|
|
129
|
+
const exports = collectNamedExports(program);
|
|
130
|
+
for (const name of exportNames) {
|
|
131
|
+
if (exports.has(name)) matches.add(name);
|
|
132
|
+
}
|
|
133
|
+
} catch {
|
|
134
|
+
// Graceful fallback: return empty set
|
|
135
|
+
}
|
|
136
|
+
return matches;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check if a file has a default export.
|
|
141
|
+
* Returns false if the file doesn't exist or can't be parsed.
|
|
142
|
+
*/
|
|
143
|
+
export function fileHasDefaultExport(filePath: string): boolean {
|
|
144
|
+
if (!existsSync(filePath)) return false;
|
|
145
|
+
try {
|
|
146
|
+
const source = readFileCached(filePath);
|
|
147
|
+
const program = tryParse(source);
|
|
148
|
+
if (!program) return false;
|
|
149
|
+
return hasDefaultExport(program);
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check if a file has any `export * from '...'` declarations.
|
|
157
|
+
* Returns false if the file doesn't exist or can't be parsed.
|
|
158
|
+
*/
|
|
159
|
+
export function fileHasStarExport(filePath: string): boolean {
|
|
160
|
+
if (!existsSync(filePath)) return false;
|
|
161
|
+
try {
|
|
162
|
+
const source = readFileCached(filePath);
|
|
163
|
+
const program = tryParse(source);
|
|
164
|
+
if (!program) return false;
|
|
165
|
+
return hasStarExport(program);
|
|
166
|
+
} catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Parsed value of `export const prerender` from a route file.
|
|
173
|
+
*
|
|
174
|
+
* - `true` / `false` — literal boolean
|
|
175
|
+
* - `{ ttl?, tags? }` — ISR options object (prerender: true is implied)
|
|
176
|
+
* - `undefined` — no `export const prerender` found
|
|
177
|
+
*
|
|
178
|
+
* See design/45-cache-lifetimes.md §"Route-Level Static".
|
|
179
|
+
*/
|
|
180
|
+
export type PrerenderExportValue = boolean | { ttl?: number; tags?: string[] };
|
|
181
|
+
|
|
182
|
+
function extractLiteralValue(node: AstNode): unknown {
|
|
183
|
+
if (!node) return undefined;
|
|
184
|
+
const n = node as any;
|
|
185
|
+
if (n.type === 'Literal') return n.value;
|
|
186
|
+
if (n.type === 'UnaryExpression' && n.operator === '-' && n.argument?.type === 'Literal') {
|
|
187
|
+
return -(n.argument.value as number);
|
|
188
|
+
}
|
|
189
|
+
if (n.type === 'ArrayExpression') {
|
|
190
|
+
const elements = n.elements as AstNode[] | undefined;
|
|
191
|
+
if (!elements) return undefined;
|
|
192
|
+
const result: unknown[] = [];
|
|
193
|
+
for (const el of elements) {
|
|
194
|
+
const v = extractLiteralValue(el);
|
|
195
|
+
if (v === undefined) return undefined;
|
|
196
|
+
result.push(v);
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function extractObjectLiteral(node: AstNode): Record<string, unknown> | undefined {
|
|
204
|
+
if ((node as any).type !== 'ObjectExpression') return undefined;
|
|
205
|
+
const props = (node as any).properties as AstNode[] | undefined;
|
|
206
|
+
if (!props) return undefined;
|
|
207
|
+
const result: Record<string, unknown> = {};
|
|
208
|
+
for (const prop of props) {
|
|
209
|
+
const p = prop as any;
|
|
210
|
+
if (p.type === 'SpreadElement') return undefined;
|
|
211
|
+
if (p.type !== 'Property' || p.computed) return undefined;
|
|
212
|
+
const key =
|
|
213
|
+
p.key?.type === 'Identifier'
|
|
214
|
+
? p.key.name
|
|
215
|
+
: p.key?.type === 'Literal'
|
|
216
|
+
? String(p.key.value)
|
|
217
|
+
: undefined;
|
|
218
|
+
if (!key) return undefined;
|
|
219
|
+
const value = extractLiteralValue(p.value);
|
|
220
|
+
if (value === undefined) return undefined;
|
|
221
|
+
result[key] = value;
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Extract the value of `export const prerender` from a file.
|
|
228
|
+
* Returns undefined if the file doesn't export `prerender` or can't be parsed.
|
|
229
|
+
*
|
|
230
|
+
* Supports:
|
|
231
|
+
* export const prerender = true;
|
|
232
|
+
* export const prerender = false;
|
|
233
|
+
* export const prerender = { ttl: 3600, tags: ['docs'] };
|
|
234
|
+
*/
|
|
235
|
+
export function getPrerenderExport(filePath: string): PrerenderExportValue | undefined {
|
|
236
|
+
if (!existsSync(filePath)) return undefined;
|
|
237
|
+
try {
|
|
238
|
+
const source = readFileCached(filePath);
|
|
239
|
+
const program = tryParse(source);
|
|
240
|
+
if (!program) return undefined;
|
|
241
|
+
|
|
242
|
+
for (const stmt of program.body) {
|
|
243
|
+
if (stmt.type !== 'ExportNamedDeclaration') continue;
|
|
244
|
+
if (stmt.exportKind === 'type') continue;
|
|
245
|
+
if (!stmt.declaration) continue;
|
|
246
|
+
const decl = stmt.declaration;
|
|
247
|
+
if (decl.type !== 'VariableDeclaration') continue;
|
|
248
|
+
const declarations = decl.declarations as
|
|
249
|
+
| Array<{
|
|
250
|
+
id?: { name?: string };
|
|
251
|
+
init?: AstNode;
|
|
252
|
+
}>
|
|
253
|
+
| undefined;
|
|
254
|
+
if (!declarations) continue;
|
|
255
|
+
for (const d of declarations) {
|
|
256
|
+
if (d.id?.name !== 'prerender' || !d.init) continue;
|
|
257
|
+
const init = d.init as any;
|
|
258
|
+
if (init.type === 'Literal' && typeof init.value === 'boolean') {
|
|
259
|
+
return init.value;
|
|
260
|
+
}
|
|
261
|
+
if (init.type === 'ObjectExpression') {
|
|
262
|
+
const obj = extractObjectLiteral(init);
|
|
263
|
+
if (!obj) return undefined;
|
|
264
|
+
const result: { ttl?: number; tags?: string[] } = {};
|
|
265
|
+
if ('ttl' in obj && typeof obj.ttl === 'number') result.ttl = obj.ttl;
|
|
266
|
+
if (
|
|
267
|
+
'tags' in obj &&
|
|
268
|
+
Array.isArray(obj.tags) &&
|
|
269
|
+
obj.tags.every((t: unknown) => typeof t === 'string')
|
|
270
|
+
) {
|
|
271
|
+
result.tags = obj.tags as string[];
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return undefined;
|
|
279
|
+
} catch {
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Check if a file starts with a specific directive (e.g. "use client").
|
|
286
|
+
* Directives are string literal expression statements at the top of the file.
|
|
287
|
+
*/
|
|
288
|
+
export function fileHasDirective(filePath: string, directive: string): boolean {
|
|
289
|
+
if (!existsSync(filePath)) return false;
|
|
290
|
+
try {
|
|
291
|
+
const source = readFileCached(filePath);
|
|
292
|
+
const program = tryParse(source);
|
|
293
|
+
if (!program) return false;
|
|
294
|
+
for (const stmt of program.body) {
|
|
295
|
+
if (stmt.type !== 'ExpressionStatement') break;
|
|
296
|
+
const expr = (stmt as any).expression;
|
|
297
|
+
if (expr?.type !== 'Literal' || typeof expr.value !== 'string') break;
|
|
298
|
+
if (expr.value === directive) return true;
|
|
299
|
+
}
|
|
300
|
+
return false;
|
|
301
|
+
} catch {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|