@timber-js/app 0.2.0-alpha.16 → 0.2.0-alpha.161
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-cjklt63G.js +317 -0
- package/dist/_chunks/actions-cjklt63G.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-CzYUlgXA.js +1125 -0
- package/dist/_chunks/cache-api-CzYUlgXA.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → canonicalize-P41GR6tY.js} +94 -18
- package/dist/_chunks/canonicalize-P41GR6tY.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-NfLbLnDw.js +638 -0
- package/dist/_chunks/cli-schema-sync-NfLbLnDw.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-Bssfp6ot.js +82 -0
- package/dist/_chunks/define-Bssfp6ot.js.map +1 -0
- package/dist/_chunks/define-CFmvb4Bt.js +203 -0
- package/dist/_chunks/define-CFmvb4Bt.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/logger-B_O6-mdJ.js +1485 -0
- package/dist/_chunks/logger-B_O6-mdJ.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-DeAxFRMq.js +280 -0
- package/dist/_chunks/plugin-context-DeAxFRMq.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-3iUvBV5T.js +50 -0
- package/dist/_chunks/resolve-schema-3iUvBV5T.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-BY3QLBL7.js +119 -0
- package/dist/_chunks/schema-bridge-BY3QLBL7.js.map +1 -0
- package/dist/_chunks/segment-classify-CDDRVKs7.js +137 -0
- package/dist/_chunks/segment-classify-CDDRVKs7.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/tree-match-D2l830j2.js +102 -0
- package/dist/_chunks/tree-match-D2l830j2.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-CbeQmext.js} +7 -20
- package/dist/_chunks/use-query-states-CbeQmext.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-9mz9T7mb.js +988 -0
- package/dist/_chunks/walkers-9mz9T7mb.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 +64 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +117 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +177 -20
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +337 -64
- package/dist/adapters/cloudflare.js.map +1 -1
- 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 +1 -3
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +144 -152
- 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 +0 -6
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/cache-api.d.ts +26 -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 +27 -7
- 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/redis-handler.d.ts +97 -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 +51 -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 +34 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +107 -33
- 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 +26 -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/child-segment-context.d.ts +22 -0
- package/dist/client/child-segment-context.d.ts.map +1 -0
- package/dist/client/child-segment-outlet.d.ts +18 -0
- package/dist/client/child-segment-outlet.d.ts.map +1 -0
- package/dist/client/child-segment-provider.d.ts +21 -0
- package/dist/client/child-segment-provider.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 +11 -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 +182 -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 +825 -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 +120 -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 +87 -14
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +47 -14
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +4 -4
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +49 -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/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 +75 -0
- package/dist/codec.js.map +1 -0
- package/dist/config-types.d.ts +304 -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} +2 -2
- 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 +158 -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 +8471 -14108
- 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 +190 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +20 -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 +1 -1
- 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.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/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 +75 -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 +77 -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 +157 -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 +37 -440
- 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 +41 -6
- 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 +86 -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 +6 -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 +115 -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 +221 -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 +170 -2911
- 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 +3652 -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 +23 -7
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +36 -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 +56 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +122 -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 +58 -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/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/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 +101 -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/route-element-builder.d.ts +46 -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/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 +51 -28
- 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 +50 -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 +5 -6
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +17 -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 +34 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +119 -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 +7 -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 +12 -5
- 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 +62 -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 +16 -16
- 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 +199 -0
- package/docs/api/33-api-search-params.mdx +141 -0
- package/docs/api/34-api-config.mdx +189 -0
- package/docs/api/35-api-typescript.mdx +170 -0
- package/docs/api/36-cli.mdx +143 -0
- package/docs/learn/00-introduction.mdx +76 -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 +136 -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 +168 -0
- package/docs/learn/13-configuration.mdx +145 -0
- package/docs/learn/14-deploying.mdx +264 -0
- package/docs/more/01-advanced-routing.mdx +139 -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 +103 -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 +179 -0
- package/src/adapters/cloudflare.ts +571 -118
- package/src/adapters/compress-module.ts +27 -92
- package/src/adapters/nitro.ts +131 -107
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/adapters/shared.ts +68 -0
- package/src/adapters/types.ts +0 -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 +88 -18
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/redis-handler.ts +122 -15
- 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 +233 -0
- package/src/cache/timber-cache.ts +142 -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 +388 -0
- package/src/cli.ts +157 -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 +111 -0
- package/src/client/browser-entry/post-hydration.ts +103 -0
- package/src/client/browser-entry/router-init.ts +287 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +50 -0
- package/src/client/child-segment-context.ts +40 -0
- package/src/client/child-segment-outlet.tsx +25 -0
- package/src/client/child-segment-provider.tsx +27 -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 +11 -7
- package/src/client/index.ts +67 -45
- package/src/client/internal.ts +58 -0
- package/src/client/link.tsx +346 -150
- package/src/client/navigation-api.ts +341 -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 +482 -166
- package/src/client/rsc-fetch.ts +214 -33
- package/src/client/segment-cache.ts +7 -7
- package/src/client/segment-outlet.tsx +77 -0
- package/src/client/segment-update-context.ts +42 -0
- package/src/client/shallow-url.ts +22 -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 +9 -3
- 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 +147 -0
- package/src/config-types.ts +302 -0
- package/src/config-validation.ts +328 -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} +9 -5
- 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 +63 -8
- package/src/fonts/local.ts +9 -8
- package/src/fonts/paths.ts +58 -0
- package/src/fonts/pipeline.ts +316 -0
- package/src/fonts/transform.ts +305 -0
- package/src/fonts/types.ts +52 -1
- package/src/fonts/virtual-modules.ts +179 -0
- package/src/index.ts +431 -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 +378 -0
- package/src/plugins/adapter-build.ts +98 -4
- package/src/plugins/build-manifest.ts +168 -23
- package/src/plugins/build-report.ts +253 -35
- package/src/plugins/cache.ts +229 -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 +144 -0
- package/src/plugins/cloudflare-wasm.ts +141 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-server.ts +293 -46
- package/src/plugins/entries.ts +129 -8
- package/src/plugins/fonts.ts +199 -664
- package/src/plugins/mdx.ts +47 -10
- package/src/plugins/prebuilt-capture.ts +217 -0
- package/src/plugins/prebuilt.ts +700 -0
- package/src/plugins/prerender-sugar.ts +329 -0
- package/src/plugins/routing.ts +237 -241
- package/src/plugins/server-bundle.ts +97 -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 +360 -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 +310 -0
- package/src/routing/manifest-codegen.ts +281 -0
- package/src/routing/scanner.ts +248 -188
- package/src/routing/schema-validation.ts +149 -0
- package/src/routing/segment-classify.ts +188 -0
- package/src/routing/segment-codegen.ts +98 -0
- package/src/routing/types.ts +78 -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 +252 -0
- package/src/search-params/define.ts +570 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +110 -0
- package/src/segment-params/define.ts +249 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +84 -34
- package/src/server/action-client.ts +119 -28
- 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 +130 -20
- package/src/server/asset-headers.ts +15 -37
- package/src/server/body-limits.ts +10 -2
- package/src/server/build-manifest.ts +13 -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 +311 -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 +437 -0
- package/src/server/html-injectors.ts +267 -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 +44 -19
- package/src/server/middleware-runner.ts +75 -4
- package/src/server/node-stream-transforms.ts +331 -0
- package/src/server/param-coercion.ts +206 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +32 -18
- package/src/server/pipeline-metadata.ts +14 -0
- package/src/server/pipeline-outcome.ts +197 -0
- package/src/server/pipeline-phases.ts +538 -0
- package/src/server/pipeline.ts +226 -382
- package/src/server/port-resolution.ts +215 -0
- package/src/server/prebuilt/cache-key.ts +224 -0
- package/src/server/prebuilt/capture-state.ts +89 -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/synthetic-store.ts +121 -0
- package/src/server/prebuilt-builder.ts +774 -0
- package/src/server/prebuilt-runtime.ts +731 -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 +168 -337
- package/src/server/route-element-builder.ts +548 -233
- package/src/server/route-handler.ts +31 -4
- package/src/server/route-matcher.ts +144 -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/error-renderer.ts +306 -89
- package/src/server/rsc-entry/helpers.ts +160 -76
- package/src/server/rsc-entry/index.ts +394 -330
- package/src/server/rsc-entry/render-route.ts +288 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +349 -0
- package/src/server/rsc-entry/rsc-payload.ts +74 -35
- package/src/server/rsc-entry/rsc-stream.ts +85 -13
- package/src/server/rsc-entry/ssr-bridge.ts +18 -5
- package/src/server/rsc-entry/ssr-renderer.ts +273 -43
- package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -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 +344 -0
- package/src/server/sitemap-handler.ts +157 -0
- package/src/server/slot-resolver.ts +258 -257
- package/src/server/ssr-bridge-types.ts +124 -0
- package/src/server/ssr-entry.ts +206 -78
- package/src/server/ssr-render.ts +345 -82
- package/src/server/ssr-wrappers.tsx +141 -0
- package/src/server/state-tree-diff.ts +30 -23
- package/src/server/status-code-resolver.ts +115 -130
- package/src/server/stream-utils.ts +286 -0
- package/src/server/tracing.ts +126 -14
- package/src/server/tree-builder.ts +204 -90
- package/src/server/tree-match.ts +220 -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.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/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,107 @@
|
|
|
1
|
+
import type { CacheOptions } from './index';
|
|
2
|
+
import type { PrebuiltComponentOptions } from '../server/prebuilt-runtime';
|
|
3
|
+
import { createCache } from './timber-cache';
|
|
4
|
+
import { getCacheHandler } from './handler-store';
|
|
5
|
+
import { recordInvalidation } from './invalidation-epoch';
|
|
6
|
+
import { writeTombstonesForTag } from '../server/prebuilt/overlay.js';
|
|
7
|
+
import { getCdnPurgeHandler } from '../cdn/purge-store.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Public caching API: `cache(fn, opts)`.
|
|
11
|
+
*
|
|
12
|
+
* Wraps an async function with cross-request caching. Uses the configured
|
|
13
|
+
* cache handler (defaults to MemoryCacheHandler, overridable via timber.config.ts).
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { cache } from '@timber-js/app/cache';
|
|
17
|
+
*
|
|
18
|
+
* const getUser = cache(
|
|
19
|
+
* async (id: string) => db.users.findUnique({ where: { id } }),
|
|
20
|
+
* { ttl: 60, tags: (id) => [`user:${id}`] }
|
|
21
|
+
* );
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
export function cache<Fn extends (...args: any[]) => Promise<any>>(
|
|
26
|
+
fn: Fn,
|
|
27
|
+
opts: CacheOptions<Fn>,
|
|
28
|
+
stableId?: string
|
|
29
|
+
): Fn {
|
|
30
|
+
// Pass the getter, not a resolved handler: the wrapper re-resolves it on
|
|
31
|
+
// every call, so module-scope wrappers created before the framework's boot
|
|
32
|
+
// wiring calls setCacheHandler() still pick up the configured handler
|
|
33
|
+
// instead of permanently binding the in-memory fallback (TIM-1029).
|
|
34
|
+
return createCache(fn, opts, getCacheHandler, stableId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Invalidate cache entries by tag or key.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* cache.invalidate({ tag: 'products' });
|
|
42
|
+
* cache.invalidate({ key: 'user:abc' });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
cache.invalidate = async function invalidate(opts: { key?: string; tag?: string }): Promise<void> {
|
|
46
|
+
// Record before the handler delete so a cached fn in flight skips its
|
|
47
|
+
// post-resolve set instead of resurrecting the invalidated value (TIM-1028).
|
|
48
|
+
recordInvalidation(opts);
|
|
49
|
+
await getCacheHandler().invalidate(opts);
|
|
50
|
+
// Write tombstones for build-seed entries carrying the tag (design/45
|
|
51
|
+
// §ISR mechanics). Runs AFTER handler.invalidate so the tombstone
|
|
52
|
+
// overwrites the cleared overlay slot. This covers ALL invalidation
|
|
53
|
+
// paths — actions, webhooks, route handlers — not just executeAction.
|
|
54
|
+
if (opts.tag) {
|
|
55
|
+
await writeTombstonesForTag(opts.tag);
|
|
56
|
+
}
|
|
57
|
+
// Trigger CDN purge if a handler is configured (design/25 §Layer 2).
|
|
58
|
+
// Purge is best-effort: a CDN API failure or timeout must not block
|
|
59
|
+
// cache invalidation. 10s ceiling prevents a hung CDN API from stalling
|
|
60
|
+
// the entire revalidateTag/action flow.
|
|
61
|
+
if (opts.tag) {
|
|
62
|
+
const purgeHandler = getCdnPurgeHandler();
|
|
63
|
+
if (purgeHandler) {
|
|
64
|
+
try {
|
|
65
|
+
await Promise.race([
|
|
66
|
+
purgeHandler.purgeTags([opts.tag]),
|
|
67
|
+
new Promise<void>((_, reject) =>
|
|
68
|
+
setTimeout(() => reject(new Error('CDN purge timed out (10s)')), 10_000)
|
|
69
|
+
),
|
|
70
|
+
]);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error('[timber] CDN purge failed for tag:', err);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const componentFallbackWarned = new WeakSet<object>();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Runtime fallback for `cache.component(...)` callsites the timber-prebuilt
|
|
82
|
+
* transform does not rewrite — nested/computed/argument-position forms (see
|
|
83
|
+
* plugins/prebuilt.ts). Only module-scope `const X = cache.component(...)`
|
|
84
|
+
* declarations are transformed and eligible for prebuilding; everything else
|
|
85
|
+
* lands here, warns once per component, and renders dynamically. Same
|
|
86
|
+
* safety-net pattern as the data cache's runtime fnId fallback (TIM-1054):
|
|
87
|
+
* an untraceable callsite degrades in performance, never in correctness.
|
|
88
|
+
*
|
|
89
|
+
* The full public surface (types, docs, `timber` namespace) is TIM-1121;
|
|
90
|
+
* design/45-cache-lifetimes.md specifies the options.
|
|
91
|
+
*/
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
+
cache.component = function component<C extends (props: any) => unknown>(
|
|
94
|
+
componentFn: C,
|
|
95
|
+
_options?: PrebuiltComponentOptions
|
|
96
|
+
): C {
|
|
97
|
+
if (!componentFallbackWarned.has(componentFn)) {
|
|
98
|
+
componentFallbackWarned.add(componentFn);
|
|
99
|
+
const name = componentFn.name || 'anonymous component';
|
|
100
|
+
console.warn(
|
|
101
|
+
`[timber] cache.component: "${name}" was not transformed at build time — ` +
|
|
102
|
+
`rendering dynamically. Only module-scope declarations ` +
|
|
103
|
+
`(const X = cache.component(...)) are prebuilt.`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
return componentFn;
|
|
107
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level cache handler singleton.
|
|
3
|
+
*
|
|
4
|
+
* Lazily initialized to MemoryCacheHandler on first access. The framework
|
|
5
|
+
* replaces this at boot from timber.config.ts via setCacheHandler().
|
|
6
|
+
*
|
|
7
|
+
* This module avoids importing from ./index to prevent circular dependencies.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Inline the interface to avoid circular import with index.ts
|
|
11
|
+
interface CacheHandlerLike {
|
|
12
|
+
get(key: string): Promise<{ value: unknown; stale: boolean } | null>;
|
|
13
|
+
set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void>;
|
|
14
|
+
invalidate(opts: { key?: string; tag?: string }): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let handler: CacheHandlerLike | null = null;
|
|
18
|
+
|
|
19
|
+
let explicitlyConfigured = false;
|
|
20
|
+
|
|
21
|
+
/** Replace the active cache handler. Called by the framework at boot. */
|
|
22
|
+
export function setCacheHandler(h: CacheHandlerLike): void {
|
|
23
|
+
handler = h;
|
|
24
|
+
explicitlyConfigured = true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Whether the handler was explicitly configured (vs the default in-memory fallback). */
|
|
28
|
+
export function isCacheHandlerConfigured(): boolean {
|
|
29
|
+
return explicitlyConfigured;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the active cache handler. Creates a default MemoryCacheHandler on
|
|
34
|
+
* first access if none has been set via setCacheHandler().
|
|
35
|
+
*/
|
|
36
|
+
export function getCacheHandler(): CacheHandlerLike {
|
|
37
|
+
if (!handler) {
|
|
38
|
+
// Inline a minimal LRU cache to avoid circular dep with index.ts.
|
|
39
|
+
// In production, the framework always calls setCacheHandler() at boot.
|
|
40
|
+
handler = createDefaultHandler();
|
|
41
|
+
}
|
|
42
|
+
return handler;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function createDefaultHandler(): CacheHandlerLike {
|
|
46
|
+
const store = new Map<string, { value: unknown; expiresAt: number; tags: string[] }>();
|
|
47
|
+
const maxEntries = 1000;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
async get(key) {
|
|
51
|
+
const entry = store.get(key);
|
|
52
|
+
if (!entry) return null;
|
|
53
|
+
store.delete(key);
|
|
54
|
+
store.set(key, entry);
|
|
55
|
+
const stale = Date.now() > entry.expiresAt;
|
|
56
|
+
return { value: entry.value, stale };
|
|
57
|
+
},
|
|
58
|
+
async set(key, value, opts) {
|
|
59
|
+
if (store.has(key)) store.delete(key);
|
|
60
|
+
while (store.size >= maxEntries) {
|
|
61
|
+
const oldest = store.keys().next().value;
|
|
62
|
+
if (oldest !== undefined) store.delete(oldest);
|
|
63
|
+
else break;
|
|
64
|
+
}
|
|
65
|
+
store.set(key, { value, expiresAt: Date.now() + opts.ttl * 1000, tags: opts.tags });
|
|
66
|
+
},
|
|
67
|
+
async invalidate(opts) {
|
|
68
|
+
if (opts.key) store.delete(opts.key);
|
|
69
|
+
if (opts.tag) {
|
|
70
|
+
for (const [key, entry] of store) {
|
|
71
|
+
if (entry.tags.includes(opts.tag)) store.delete(key);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
package/src/cache/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @timber-js/app/cache — Caching primitives
|
|
2
2
|
|
|
3
|
+
import { estimateByteSize } from './sizeof.js';
|
|
4
|
+
|
|
3
5
|
export interface CacheHandler {
|
|
4
6
|
get(key: string): Promise<{ value: unknown; stale: boolean } | null>;
|
|
5
7
|
set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void>;
|
|
@@ -12,19 +14,42 @@ export interface CacheOptions<Fn extends (...args: any[]) => any> {
|
|
|
12
14
|
key?: (...args: Parameters<Fn>) => string;
|
|
13
15
|
staleWhileRevalidate?: boolean;
|
|
14
16
|
tags?: string[] | ((...args: Parameters<Fn>) => string[]);
|
|
17
|
+
/** Timeout (ms) for singleflight-coalesced calls. Prevents hung fn() from
|
|
18
|
+
* permanently blocking all future callers for the same cache key. See TIM-518. */
|
|
19
|
+
timeoutMs?: number;
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
export interface MemoryCacheHandlerOptions {
|
|
18
23
|
/** Maximum number of entries. Oldest accessed entries are evicted first. Default: 1000. */
|
|
24
|
+
maxEntries?: number;
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use `maxEntries` instead. Will be removed in a future release.
|
|
27
|
+
* Alias for `maxEntries` — maximum number of entries (not bytes).
|
|
28
|
+
*/
|
|
19
29
|
maxSize?: number;
|
|
30
|
+
/** Maximum total byte budget for all cached values. Oldest entries are evicted when exceeded. Default: no limit. */
|
|
31
|
+
maxBytes?: number;
|
|
32
|
+
/** Maximum byte size for a single cache entry. Entries exceeding this are silently dropped. Default: no limit. */
|
|
33
|
+
maxEntryBytes?: number;
|
|
20
34
|
}
|
|
21
35
|
|
|
22
36
|
export class MemoryCacheHandler implements CacheHandler {
|
|
23
|
-
private store = new Map<
|
|
24
|
-
|
|
37
|
+
private store = new Map<
|
|
38
|
+
string,
|
|
39
|
+
{ value: unknown; expiresAt: number; tags: string[]; byteSize: number }
|
|
40
|
+
>();
|
|
41
|
+
private maxEntries: number;
|
|
42
|
+
private maxBytes: number | undefined;
|
|
43
|
+
private maxEntryBytes: number | undefined;
|
|
44
|
+
private currentBytes = 0;
|
|
45
|
+
private readonly _trackBytes: boolean;
|
|
25
46
|
|
|
26
47
|
constructor(opts?: MemoryCacheHandlerOptions) {
|
|
27
|
-
|
|
48
|
+
// maxEntries takes precedence over deprecated maxSize
|
|
49
|
+
this.maxEntries = opts?.maxEntries ?? opts?.maxSize ?? 1000;
|
|
50
|
+
this.maxBytes = opts?.maxBytes;
|
|
51
|
+
this.maxEntryBytes = opts?.maxEntryBytes;
|
|
52
|
+
this._trackBytes = this.maxBytes !== undefined || this.maxEntryBytes !== undefined;
|
|
28
53
|
}
|
|
29
54
|
|
|
30
55
|
async get(key: string) {
|
|
@@ -40,18 +65,33 @@ export class MemoryCacheHandler implements CacheHandler {
|
|
|
40
65
|
}
|
|
41
66
|
|
|
42
67
|
async set(key: string, value: unknown, opts: { ttl: number; tags: string[] }) {
|
|
43
|
-
|
|
68
|
+
const byteSize = this._trackBytes ? estimateByteSize(value) : 0;
|
|
69
|
+
|
|
70
|
+
// Reject entries exceeding per-entry byte limit
|
|
71
|
+
if (this.maxEntryBytes !== undefined && byteSize > this.maxEntryBytes) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// If key already exists, delete first to refresh insertion order and reclaim bytes
|
|
44
76
|
if (this.store.has(key)) {
|
|
77
|
+
const existing = this.store.get(key)!;
|
|
78
|
+
this.currentBytes -= existing.byteSize;
|
|
45
79
|
this.store.delete(key);
|
|
46
80
|
}
|
|
47
81
|
|
|
48
|
-
// Evict oldest entries (front of Map) if at capacity
|
|
49
|
-
while (this.store.size >= this.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
82
|
+
// Evict oldest entries (front of Map) if at entry count capacity
|
|
83
|
+
while (this.store.size >= this.maxEntries) {
|
|
84
|
+
this.evictOldest();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Evict oldest entries if byte budget would be exceeded
|
|
88
|
+
if (this.maxBytes !== undefined) {
|
|
89
|
+
while (this.currentBytes + byteSize > this.maxBytes && this.store.size > 0) {
|
|
90
|
+
this.evictOldest();
|
|
91
|
+
}
|
|
92
|
+
// If the single entry exceeds the total byte budget, don't store it
|
|
93
|
+
if (this.currentBytes + byteSize > this.maxBytes) {
|
|
94
|
+
return;
|
|
55
95
|
}
|
|
56
96
|
}
|
|
57
97
|
|
|
@@ -59,16 +99,23 @@ export class MemoryCacheHandler implements CacheHandler {
|
|
|
59
99
|
value,
|
|
60
100
|
expiresAt: Date.now() + opts.ttl * 1000,
|
|
61
101
|
tags: opts.tags,
|
|
102
|
+
byteSize,
|
|
62
103
|
});
|
|
104
|
+
this.currentBytes += byteSize;
|
|
63
105
|
}
|
|
64
106
|
|
|
65
107
|
async invalidate(opts: { key?: string; tag?: string }) {
|
|
66
108
|
if (opts.key) {
|
|
67
|
-
this.store.
|
|
109
|
+
const entry = this.store.get(opts.key);
|
|
110
|
+
if (entry) {
|
|
111
|
+
this.currentBytes -= entry.byteSize;
|
|
112
|
+
this.store.delete(opts.key);
|
|
113
|
+
}
|
|
68
114
|
}
|
|
69
115
|
if (opts.tag) {
|
|
70
116
|
for (const [key, entry] of this.store) {
|
|
71
117
|
if (entry.tags.includes(opts.tag)) {
|
|
118
|
+
this.currentBytes -= entry.byteSize;
|
|
72
119
|
this.store.delete(key);
|
|
73
120
|
}
|
|
74
121
|
}
|
|
@@ -79,13 +126,36 @@ export class MemoryCacheHandler implements CacheHandler {
|
|
|
79
126
|
get size(): number {
|
|
80
127
|
return this.store.size;
|
|
81
128
|
}
|
|
129
|
+
|
|
130
|
+
/** Estimated total byte size of all cached values. Only tracked when maxBytes or maxEntryBytes is configured; returns 0 otherwise. */
|
|
131
|
+
get bytes(): number {
|
|
132
|
+
return this.currentBytes;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Evict the oldest entry (front of Map). */
|
|
136
|
+
private evictOldest(): void {
|
|
137
|
+
const oldest = this.store.keys().next().value;
|
|
138
|
+
if (oldest !== undefined) {
|
|
139
|
+
const entry = this.store.get(oldest)!;
|
|
140
|
+
this.currentBytes -= entry.byteSize;
|
|
141
|
+
this.store.delete(oldest);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
82
144
|
}
|
|
83
145
|
|
|
84
146
|
export { RedisCacheHandler } from './redis-handler';
|
|
85
147
|
export type { RedisClient } from './redis-handler';
|
|
86
|
-
export {
|
|
87
|
-
export {
|
|
88
|
-
export
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
export
|
|
148
|
+
export { cache } from './cache-api';
|
|
149
|
+
export { setCacheHandler, getCacheHandler } from './handler-store';
|
|
150
|
+
export { setDefaultSingleflightTimeout } from './timber-cache';
|
|
151
|
+
// NOTE: registerCachedFunction (runtime for 'use cache' directive) removed.
|
|
152
|
+
// Future feature pending design doc. See design/06-caching.md.
|
|
153
|
+
export { estimateByteSize } from './sizeof';
|
|
154
|
+
|
|
155
|
+
// --- Cache Store layering (design/46) ---
|
|
156
|
+
export { TagAwareCacheHandler } from './tag-aware-handler';
|
|
157
|
+
export type { CacheStore } from './store';
|
|
158
|
+
// stableStringify, createSingleflight, and SingleflightTimeoutError are
|
|
159
|
+
// internal utilities used by the cache implementation. They are not
|
|
160
|
+
// re-exported here — import directly from the source files if needed
|
|
161
|
+
// within the package. See TIM-720.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-process invalidation epoch tracking for timber.cache (TIM-1028).
|
|
3
|
+
*
|
|
4
|
+
* handler.set for a cache miss runs after `fn()` resolves. An explicit
|
|
5
|
+
* `cache.invalidate({ tag })` / `revalidateTag` that lands while fn is in
|
|
6
|
+
* flight would otherwise be silently undone — the just-invalidated value
|
|
7
|
+
* re-stored as fresh for the full TTL, resurrecting pre-mutation data.
|
|
8
|
+
*
|
|
9
|
+
* Every invalidation bumps a monotonic epoch and records it against the
|
|
10
|
+
* invalidated key/tag. Before storing a result, the cache wrapper checks
|
|
11
|
+
* whether its key or any of its tags were invalidated after fn started and
|
|
12
|
+
* skips the write if so. Skipping is always safe: the only cost is one
|
|
13
|
+
* extra cache miss on the next call.
|
|
14
|
+
*
|
|
15
|
+
* Scope: per-process, like the singleflight map. An invalidation issued by
|
|
16
|
+
* another instance against a shared handler (Redis/KV) during fn flight is
|
|
17
|
+
* not observable here — closing that window fully would require store-level
|
|
18
|
+
* versioning, which no CacheHandler backend offers.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
let epoch = 0;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Last-invalidated epoch per `key:<k>` / `tag:<t>` entry. Insertion order is
|
|
25
|
+
* epoch order (entries are re-inserted on update), so the oldest entry is
|
|
26
|
+
* always first — pruning evicts lowest epochs.
|
|
27
|
+
*/
|
|
28
|
+
const lastInvalidated = new Map<string, number>();
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Bound on tracked entries so high-cardinality tag invalidation (e.g.
|
|
32
|
+
* per-user tags) cannot grow this map without limit.
|
|
33
|
+
*/
|
|
34
|
+
const MAX_TRACKED_ENTRIES = 10_000;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Highest epoch evicted from the map. Any execution that started at or
|
|
38
|
+
* before this epoch conservatively counts as invalidated — history was
|
|
39
|
+
* truncated, so we can no longer prove it wasn't.
|
|
40
|
+
*/
|
|
41
|
+
let evictedEpochFloor = 0;
|
|
42
|
+
|
|
43
|
+
/** The current epoch. Capture before running fn(), pass to wasInvalidatedSince. */
|
|
44
|
+
export function currentInvalidationEpoch(): number {
|
|
45
|
+
return epoch;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Record an invalidation. Call BEFORE handler.invalidate() so an execution
|
|
50
|
+
* whose set-check races the invalidation errs toward skipping the write.
|
|
51
|
+
*/
|
|
52
|
+
export function recordInvalidation(opts: { key?: string; tag?: string }): void {
|
|
53
|
+
epoch++;
|
|
54
|
+
if (opts.key) track(`key:${opts.key}`);
|
|
55
|
+
if (opts.tag) track(`tag:${opts.tag}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function track(entry: string): void {
|
|
59
|
+
lastInvalidated.delete(entry);
|
|
60
|
+
lastInvalidated.set(entry, epoch);
|
|
61
|
+
while (lastInvalidated.size > MAX_TRACKED_ENTRIES) {
|
|
62
|
+
const oldest = lastInvalidated.entries().next().value;
|
|
63
|
+
if (oldest === undefined) break;
|
|
64
|
+
evictedEpochFloor = Math.max(evictedEpochFloor, oldest[1]);
|
|
65
|
+
lastInvalidated.delete(oldest[0]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Whether the key or any tag was invalidated after `startEpoch` (the epoch
|
|
71
|
+
* captured when fn started executing).
|
|
72
|
+
*/
|
|
73
|
+
export function wasInvalidatedSince(startEpoch: number, key: string, tags: string[]): boolean {
|
|
74
|
+
return lastInvalidationEpochFor(key, tags) > startEpoch;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The highest epoch at which the key or any of the tags was invalidated
|
|
79
|
+
* (0 if never). Used to scope the singleflight key: callers arriving after
|
|
80
|
+
* an invalidation must not coalesce onto a flight that started before it —
|
|
81
|
+
* they would receive the pre-invalidation result the invalidation was
|
|
82
|
+
* issued to discard.
|
|
83
|
+
*/
|
|
84
|
+
export function lastInvalidationEpochFor(key: string, tags: string[]): number {
|
|
85
|
+
let last = evictedEpochFloor;
|
|
86
|
+
const keyEpoch = lastInvalidated.get(`key:${key}`);
|
|
87
|
+
if (keyEpoch !== undefined && keyEpoch > last) last = keyEpoch;
|
|
88
|
+
for (const tag of tags) {
|
|
89
|
+
const tagEpoch = lastInvalidated.get(`tag:${tag}`);
|
|
90
|
+
if (tagEpoch !== undefined && tagEpoch > last) last = tagEpoch;
|
|
91
|
+
}
|
|
92
|
+
return last;
|
|
93
|
+
}
|
|
@@ -1,16 +1,104 @@
|
|
|
1
1
|
import type { CacheHandler } from './index';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Minimal Redis client
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Minimal Redis client contract for `RedisCacheHandler`.
|
|
5
|
+
*
|
|
6
|
+
* This is deliberately NOT the native shape of any client library. ioredis,
|
|
7
|
+
* node-redis v4, and @upstash/redis all disagree on TTL argument shapes
|
|
8
|
+
* (positional `'EX'` vs `{ EX }` vs `{ ex }`), method casing (`sadd` vs
|
|
9
|
+
* `sAdd`), and array handling in `del` — a contract that pattern-matches one
|
|
10
|
+
* client lets another silently drop the expiry (TIM-1030: node-redis ignored
|
|
11
|
+
* the positional `'EX'` and wrote keys with no TTL). Instead, TTL semantics
|
|
12
|
+
* are explicit in the signature and you adapt your client with a thin
|
|
13
|
+
* wrapper, so a mismatch is a type error rather than silent unbounded
|
|
14
|
+
* keyspace growth.
|
|
15
|
+
*
|
|
16
|
+
* @example ioredis
|
|
17
|
+
* ```ts
|
|
18
|
+
* import Redis from 'ioredis';
|
|
19
|
+
* const redis = new Redis(process.env.REDIS_URL);
|
|
20
|
+
* const client: RedisClient = {
|
|
21
|
+
* get: (k) => redis.get(k),
|
|
22
|
+
* set: (k, v, ttl) => redis.set(k, v, 'EX', ttl),
|
|
23
|
+
* expireNX: (k, s) => redis.expire(k, s, 'NX'),
|
|
24
|
+
* expireGT: (k, s) => redis.expire(k, s, 'GT'),
|
|
25
|
+
* del: (k) => redis.del(k),
|
|
26
|
+
* sadd: (k, ...m) => redis.sadd(k, ...m),
|
|
27
|
+
* srem: (k, ...m) => redis.srem(k, ...m),
|
|
28
|
+
* smembers: (k) => redis.smembers(k),
|
|
29
|
+
* ttl: (k) => redis.ttl(k),
|
|
30
|
+
* };
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example node-redis v4
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { createClient } from 'redis';
|
|
36
|
+
* const redis = createClient({ url: process.env.REDIS_URL });
|
|
37
|
+
* await redis.connect();
|
|
38
|
+
* const client: RedisClient = {
|
|
39
|
+
* get: (k) => redis.get(k),
|
|
40
|
+
* set: (k, v, ttl) => redis.set(k, v, { EX: ttl }),
|
|
41
|
+
* expireNX: (k, s) => redis.expire(k, s, 'NX'),
|
|
42
|
+
* expireGT: (k, s) => redis.expire(k, s, 'GT'),
|
|
43
|
+
* del: (k) => redis.del(k),
|
|
44
|
+
* sadd: (k, ...m) => redis.sAdd(k, m),
|
|
45
|
+
* srem: (k, ...m) => redis.sRem(k, m),
|
|
46
|
+
* smembers: (k) => redis.sMembers(k),
|
|
47
|
+
* ttl: (k) => redis.ttl(k),
|
|
48
|
+
* };
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example @upstash/redis
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { Redis } from '@upstash/redis';
|
|
54
|
+
* // automaticDeserialization must be off: the handler stores JSON strings
|
|
55
|
+
* // and parses them itself — auto-parsing would hand back objects.
|
|
56
|
+
* const redis = new Redis({ url, token, automaticDeserialization: false });
|
|
57
|
+
* const client: RedisClient = {
|
|
58
|
+
* get: (k) => redis.get(k),
|
|
59
|
+
* set: (k, v, ttl) => redis.set(k, v, { ex: ttl }),
|
|
60
|
+
* expireNX: (k, s) => redis.expire(k, s, 'NX'),
|
|
61
|
+
* expireGT: (k, s) => redis.expire(k, s, 'GT'),
|
|
62
|
+
* del: (k) => redis.del(k),
|
|
63
|
+
* sadd: (k, ...m) => redis.sadd(k, m[0], ...m.slice(1)),
|
|
64
|
+
* srem: (k, ...m) => redis.srem(k, m[0], ...m.slice(1)),
|
|
65
|
+
* smembers: (k) => redis.smembers(k),
|
|
66
|
+
* ttl: (k) => redis.ttl(k),
|
|
67
|
+
* };
|
|
68
|
+
* ```
|
|
7
69
|
*/
|
|
8
70
|
export interface RedisClient {
|
|
71
|
+
/** `GET key` — the stored string, or null when absent. */
|
|
9
72
|
get(key: string): Promise<string | null>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
73
|
+
/**
|
|
74
|
+
* `SET key value EX ttlSeconds` — store with an expiry. The TTL is a
|
|
75
|
+
* required positional argument so no adapter can forget it.
|
|
76
|
+
*/
|
|
77
|
+
set(key: string, value: string, ttlSeconds: number): Promise<unknown>;
|
|
78
|
+
/**
|
|
79
|
+
* `EXPIRE key seconds NX` — set the TTL only if the key has no existing
|
|
80
|
+
* expiry (Redis 7.0+). Used to set the initial TTL on new tag sets.
|
|
81
|
+
*/
|
|
82
|
+
expireNX(key: string, seconds: number): Promise<unknown>;
|
|
83
|
+
/**
|
|
84
|
+
* `EXPIRE key seconds GT` — update the TTL only if the new value is greater
|
|
85
|
+
* than the current one (Redis 7.0+). Used to extend tag set TTLs without
|
|
86
|
+
* allowing a short-TTL writer to shrink them.
|
|
87
|
+
*/
|
|
88
|
+
expireGT(key: string, seconds: number): Promise<unknown>;
|
|
89
|
+
/** `DEL key` — delete a single key. Multi-key deletes loop per key. */
|
|
90
|
+
del(key: string): Promise<unknown>;
|
|
91
|
+
/** `SADD key member [member ...]` — add members to a set. */
|
|
92
|
+
sadd(key: string, ...members: string[]): Promise<unknown>;
|
|
93
|
+
/** `SREM key member [member ...]` — remove members from a set. */
|
|
94
|
+
srem(key: string, ...members: string[]): Promise<unknown>;
|
|
95
|
+
/** `SMEMBERS key` — all members of a set. */
|
|
13
96
|
smembers(key: string): Promise<string[]>;
|
|
97
|
+
/**
|
|
98
|
+
* `TTL key` — remaining time-to-live in seconds. Returns -2 if the key does
|
|
99
|
+
* not exist, -1 if the key exists but has no expiry.
|
|
100
|
+
*/
|
|
101
|
+
ttl(key: string): Promise<number>;
|
|
14
102
|
}
|
|
15
103
|
|
|
16
104
|
const KEY_PREFIX = 'timber:cache:';
|
|
@@ -23,8 +111,9 @@ const TAG_PREFIX = 'timber:tag:';
|
|
|
23
111
|
* invalidations. Tag-based invalidation uses Redis Sets to track which keys
|
|
24
112
|
* belong to which tags.
|
|
25
113
|
*
|
|
26
|
-
* Bring your own Redis client
|
|
27
|
-
* interface
|
|
114
|
+
* Bring your own Redis client wrapped to the {@link RedisClient} contract —
|
|
115
|
+
* see the adapter examples on the interface for ioredis, node-redis v4, and
|
|
116
|
+
* @upstash/redis.
|
|
28
117
|
*/
|
|
29
118
|
export class RedisCacheHandler implements CacheHandler {
|
|
30
119
|
private client: RedisClient;
|
|
@@ -55,23 +144,41 @@ export class RedisCacheHandler implements CacheHandler {
|
|
|
55
144
|
async set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void> {
|
|
56
145
|
const ck = this.cacheKey(key);
|
|
57
146
|
const expiresAt = Date.now() + opts.ttl * 1000;
|
|
58
|
-
const payload = JSON.stringify({ value, expiresAt });
|
|
147
|
+
const payload = JSON.stringify({ value, expiresAt, tags: opts.tags });
|
|
59
148
|
|
|
60
149
|
// Redis TTL with generous margin beyond the logical TTL to allow SWR reads
|
|
61
150
|
// on stale entries. The logical staleness is determined by expiresAt.
|
|
62
151
|
// We use 2x TTL + 60s as the Redis expiry so stale entries remain
|
|
63
152
|
// available for SWR background refetches.
|
|
64
153
|
const redisTtlSeconds = Math.max(opts.ttl * 2 + 60, 120);
|
|
65
|
-
await this.client.set(ck, payload,
|
|
154
|
+
await this.client.set(ck, payload, redisTtlSeconds);
|
|
66
155
|
|
|
67
|
-
// Track key membership in each tag set
|
|
156
|
+
// Track key membership in each tag set, and expire the set so it doesn't
|
|
157
|
+
// outlive all its members. Only extend the TTL, never shorten — a short-TTL
|
|
158
|
+
// entry must not shrink a tag set that already contains long-TTL entries,
|
|
159
|
+
// otherwise invalidate({tag}) would miss the long-lived entries.
|
|
68
160
|
for (const tag of opts.tags) {
|
|
69
161
|
await this.client.sadd(this.tagKey(tag), key);
|
|
162
|
+
// Two atomic EXPIRE calls cover both the initial-set and extend cases:
|
|
163
|
+
// - NX: sets the TTL only if the key has no expiry (new tag set from SADD)
|
|
164
|
+
// - GT: extends the TTL only if the new value is greater than current
|
|
165
|
+
// Together they close the race where concurrent workers could shrink the
|
|
166
|
+
// tag set lifetime (TIM-1093), while ensuring new tag sets always get an
|
|
167
|
+
// initial expiry (without NX, GT is a no-op on non-volatile keys).
|
|
168
|
+
await this.client.expireNX(this.tagKey(tag), redisTtlSeconds);
|
|
169
|
+
await this.client.expireGT(this.tagKey(tag), redisTtlSeconds);
|
|
70
170
|
}
|
|
71
171
|
}
|
|
72
172
|
|
|
73
173
|
async invalidate(opts: { key?: string; tag?: string }): Promise<void> {
|
|
74
174
|
if (opts.key) {
|
|
175
|
+
const raw = await this.client.get(this.cacheKey(opts.key));
|
|
176
|
+
if (raw !== null) {
|
|
177
|
+
const entry = JSON.parse(raw) as { tags?: string[] };
|
|
178
|
+
if (entry.tags) {
|
|
179
|
+
await Promise.all(entry.tags.map((tag) => this.client.srem(this.tagKey(tag), opts.key!)));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
75
182
|
await this.client.del(this.cacheKey(opts.key));
|
|
76
183
|
}
|
|
77
184
|
|
|
@@ -79,10 +186,10 @@ export class RedisCacheHandler implements CacheHandler {
|
|
|
79
186
|
const tk = this.tagKey(opts.tag);
|
|
80
187
|
const keys = await this.client.smembers(tk);
|
|
81
188
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
189
|
+
// One del per key: the only multi-key shape every client accepts.
|
|
190
|
+
// ioredis takes del(...keys), node-redis takes del(key | key[]), and
|
|
191
|
+
// @upstash/redis takes del(...keys) but breaks on an array argument.
|
|
192
|
+
await Promise.all(keys.map((k) => this.client.del(this.cacheKey(k))));
|
|
86
193
|
|
|
87
194
|
// Clean up the tag set itself
|
|
88
195
|
await this.client.del(tk);
|