@timber-js/app 0.2.0-alpha.97 → 0.2.0-alpha.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/actions-CQ8Z8VGL.js +1061 -0
- package/dist/_chunks/actions-CQ8Z8VGL.js.map +1 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js +61 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js.map +1 -0
- package/dist/_chunks/{define-Itxvcd7F.js → define-B-Q_UMOD.js} +19 -23
- package/dist/_chunks/define-B-Q_UMOD.js.map +1 -0
- package/dist/_chunks/{define-C77ScO0m.js → define-CfBPoJb0.js} +24 -7
- package/dist/_chunks/define-CfBPoJb0.js.map +1 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js +194 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js.map +1 -0
- package/dist/_chunks/{format-CYBGxKtc.js → format-Bcn-Iv1x.js} +1 -1
- package/dist/_chunks/{format-CYBGxKtc.js.map → format-Bcn-Iv1x.js.map} +1 -1
- package/dist/_chunks/handler-store-B-lqaGyh.js +54 -0
- package/dist/_chunks/handler-store-B-lqaGyh.js.map +1 -0
- package/dist/_chunks/logger-0m8MsKdc.js +291 -0
- package/dist/_chunks/logger-0m8MsKdc.js.map +1 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js +122 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js.map +1 -0
- package/dist/_chunks/{metadata-routes-DS3eKNmf.js → metadata-routes-BU684ls2.js} +1 -1
- package/dist/_chunks/{metadata-routes-DS3eKNmf.js.map → metadata-routes-BU684ls2.js.map} +1 -1
- package/dist/_chunks/navigation-root-BCYczjml.js +96 -0
- package/dist/_chunks/navigation-root-BCYczjml.js.map +1 -0
- package/dist/_chunks/registry-I2ss-lvy.js +20 -0
- package/dist/_chunks/registry-I2ss-lvy.js.map +1 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js +28 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js.map +1 -0
- package/dist/_chunks/{schema-bridge-C3xl_vfb.js → schema-bridge-Cxu4l-7p.js} +1 -1
- package/dist/_chunks/{schema-bridge-C3xl_vfb.js.map → schema-bridge-Cxu4l-7p.js.map} +1 -1
- package/dist/_chunks/segment-classify-BjfuctV2.js +137 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -0
- package/dist/_chunks/{segment-context-fHFLF1PE.js → segment-context-Dx_OizxD.js} +1 -1
- package/dist/_chunks/{segment-context-fHFLF1PE.js.map → segment-context-Dx_OizxD.js.map} +1 -1
- package/dist/_chunks/{router-ref-C8OCm7g7.js → ssr-data-B4CdH7rE.js} +2 -26
- package/dist/_chunks/ssr-data-B4CdH7rE.js.map +1 -0
- package/dist/_chunks/{stale-reload-BX5gL1r-.js → stale-reload-Bab885FO.js} +1 -1
- package/dist/_chunks/{stale-reload-BX5gL1r-.js.map → stale-reload-Bab885FO.js.map} +1 -1
- package/dist/_chunks/tracing-C8V-YGsP.js +329 -0
- package/dist/_chunks/tracing-C8V-YGsP.js.map +1 -0
- package/dist/_chunks/{use-query-states-BiV5GJgm.js → use-query-states-B2XTqxDR.js} +3 -19
- package/dist/_chunks/use-query-states-B2XTqxDR.js.map +1 -0
- package/dist/_chunks/{use-params-IOPu7E8t.js → use-segment-params-BkpKAQ7D.js} +9 -95
- package/dist/_chunks/use-segment-params-BkpKAQ7D.js.map +1 -0
- package/dist/_chunks/{interception-BbqMCVXa.js → walkers-Tg0Alwcg.js} +66 -87
- package/dist/_chunks/walkers-Tg0Alwcg.js.map +1 -0
- package/dist/_chunks/{dev-warnings-DpGRGoDi.js → warnings-Cg47l5sk.js} +3 -3
- package/dist/_chunks/warnings-Cg47l5sk.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +28 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +8 -28
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +63 -31
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +16 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/cache/index.js +9 -2
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/client/error-boundary.js +2 -1
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/form.d.ts +10 -24
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -5
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +41 -91
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +2 -1
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +81 -7
- package/dist/client/internal.js.map +1 -1
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/state.d.ts +1 -1
- package/dist/client/use-cookie.d.ts +8 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +1 -1
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +1 -1
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +2 -2
- package/dist/config-types.d.ts +28 -0
- package/dist/config-types.d.ts.map +1 -1
- package/dist/cookies/define-cookie.d.ts +87 -35
- 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 +48 -2
- package/dist/cookies/index.js.map +1 -0
- 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 +46 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/{plugins/dev-404-page.d.ts → dev-tools/404-page.d.ts} +9 -19
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/{plugins/dev-browser-logs.d.ts → dev-tools/browser-logs.d.ts} +1 -1
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/{plugins/dev-error-page.d.ts → dev-tools/error-page.d.ts} +2 -2
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/{server/dev-holding-server.d.ts → dev-tools/holding-server.d.ts} +5 -3
- package/dist/dev-tools/holding-server.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/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
- 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} +1 -1
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/{plugins/dev-error-overlay.d.ts → dev-tools/overlay.d.ts} +3 -12
- 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/{plugins/dev-terminal-error.d.ts → dev-tools/terminal.d.ts} +2 -2
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +1 -1
- package/dist/dev-tools/warnings.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +285 -133
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +1 -1
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +6 -4
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/index.d.ts +5 -3
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -3
- package/dist/routing/scanner.d.ts +1 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +37 -8
- package/dist/routing/segment-classify.d.ts.map +1 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +63 -23
- 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/search-params/define.d.ts +25 -7
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.js +5 -3
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/wrappers.d.ts +2 -2
- package/dist/search-params/wrappers.d.ts.map +1 -1
- package/dist/segment-params/define.d.ts +23 -6
- package/dist/segment-params/define.d.ts.map +1 -1
- package/dist/segment-params/index.js +1 -1
- package/dist/server/access-gate.d.ts +4 -3
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts +15 -6
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +5 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +1 -15
- package/dist/server/asset-headers.d.ts.map +1 -1
- 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 +51 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +90 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +212 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +59 -59
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +5 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -149
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +6 -4
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +852 -852
- package/dist/server/internal.js.map +1 -1
- package/dist/server/logger.d.ts +14 -0
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +17 -0
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +46 -49
- package/dist/server/node-stream-transforms.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +26 -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-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +52 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +51 -32
- 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/request-context.d.ts +22 -159
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +20 -47
- 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/helpers.d.ts +1 -1
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- 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/wrap-action-dispatch.d.ts +119 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +16 -11
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +1 -1
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +45 -16
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +48 -0
- 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/shims/headers.d.ts +2 -2
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +3 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +9 -4
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/directive-parser.d.ts +0 -45
- package/dist/utils/directive-parser.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/build-output-helper.ts +77 -0
- package/src/adapters/cloudflare.ts +10 -50
- package/src/adapters/nitro.ts +66 -50
- package/src/adapters/shared.ts +40 -0
- package/src/cache/timber-cache.ts +3 -2
- package/src/client/form.tsx +17 -25
- package/src/client/index.ts +16 -9
- package/src/client/internal.ts +3 -2
- package/src/client/router.ts +1 -1
- package/src/client/rsc-fetch.ts +15 -0
- package/src/client/state.ts +2 -2
- package/src/client/use-cookie.ts +29 -0
- package/src/codec.ts +3 -7
- package/src/config-types.ts +28 -0
- package/src/cookies/define-cookie.ts +271 -78
- package/src/cookies/index.ts +11 -8
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +134 -0
- package/src/{plugins/dev-404-page.ts → dev-tools/404-page.ts} +17 -48
- package/src/{plugins/dev-error-page.ts → dev-tools/error-page.ts} +5 -32
- package/src/{server/dev-holding-server.ts → dev-tools/holding-server.ts} +4 -2
- package/src/dev-tools/index.ts +90 -0
- package/src/dev-tools/instrumentation.ts +176 -0
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +2 -2
- package/src/{plugins/dev-error-overlay.ts → dev-tools/overlay.ts} +5 -23
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/{plugins/dev-terminal-error.ts → dev-tools/terminal.ts} +4 -38
- package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +1 -1
- package/src/index.ts +95 -34
- package/src/plugin-context.ts +1 -1
- package/src/plugins/adapter-build.ts +3 -1
- package/src/plugins/build-report.ts +13 -22
- package/src/plugins/dev-server.ts +3 -3
- package/src/plugins/routing.ts +14 -12
- package/src/plugins/shims.ts +1 -1
- package/src/plugins/static-build.ts +1 -1
- package/src/routing/codegen.ts +1 -1
- package/src/routing/convention-lint.ts +9 -8
- package/src/routing/index.ts +5 -3
- package/src/routing/interception.ts +1 -1
- package/src/routing/scanner.ts +22 -95
- package/src/routing/segment-classify.ts +107 -8
- package/src/routing/status-file-lint.ts +7 -5
- package/src/routing/types.ts +63 -23
- package/src/routing/walkers.ts +90 -0
- package/src/search-params/define.ts +71 -15
- package/src/search-params/wrappers.ts +9 -2
- package/src/segment-params/define.ts +66 -13
- package/src/server/access-gate.tsx +9 -8
- package/src/server/action-handler.ts +34 -38
- package/src/server/als-registry.ts +5 -5
- package/src/server/asset-headers.ts +8 -34
- package/src/server/cookie-context.ts +468 -0
- package/src/server/cookie-parsing.ts +135 -0
- package/src/server/{deny-page-resolver.ts → deny-boundary.ts} +78 -14
- package/src/server/deny-renderer.ts +7 -12
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/fallback-error.ts +2 -2
- package/src/server/html-injector-core.ts +403 -0
- package/src/server/html-injectors.ts +158 -297
- package/src/server/index.ts +13 -14
- package/src/server/internal.ts +10 -3
- package/src/server/logger.ts +23 -0
- package/src/server/middleware-runner.ts +44 -0
- package/src/server/node-stream-transforms.ts +108 -248
- package/src/server/param-coercion.ts +76 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-outcome.ts +167 -0
- package/src/server/pipeline-phases.ts +409 -0
- package/src/server/pipeline.ts +70 -540
- package/src/server/port-resolution.ts +215 -0
- package/src/server/request-context.ts +46 -451
- package/src/server/route-element-builder.ts +8 -4
- package/src/server/route-matcher.ts +28 -60
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +2 -2
- package/src/server/rsc-entry/error-renderer.ts +2 -2
- package/src/server/rsc-entry/helpers.ts +2 -7
- package/src/server/rsc-entry/index.ts +81 -366
- package/src/server/rsc-entry/render-route.ts +304 -0
- package/src/server/rsc-entry/rsc-payload.ts +1 -1
- package/src/server/rsc-entry/ssr-renderer.ts +2 -2
- package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -0
- package/src/server/sitemap-generator.ts +1 -1
- package/src/server/slot-resolver.ts +1 -1
- package/src/server/ssr-entry.ts +1 -1
- package/src/server/state-tree-diff.ts +4 -1
- package/src/server/status-code-resolver.ts +112 -128
- package/src/server/tracing.ts +3 -3
- package/src/server/tree-builder.ts +134 -56
- package/src/server/types.ts +52 -0
- package/src/server/utils/escape-html.ts +20 -0
- package/src/shims/headers.ts +3 -3
- package/src/shims/navigation-client.ts +4 -3
- package/src/shims/navigation.ts +9 -7
- package/src/utils/directive-parser.ts +0 -392
- package/dist/_chunks/actions-DLnUaR65.js +0 -421
- package/dist/_chunks/actions-DLnUaR65.js.map +0 -1
- package/dist/_chunks/als-registry-HS0LGUl2.js +0 -41
- package/dist/_chunks/als-registry-HS0LGUl2.js.map +0 -1
- package/dist/_chunks/debug-ECi_61pb.js +0 -108
- package/dist/_chunks/debug-ECi_61pb.js.map +0 -1
- package/dist/_chunks/define-C77ScO0m.js.map +0 -1
- package/dist/_chunks/define-Itxvcd7F.js.map +0 -1
- package/dist/_chunks/define-cookie-BowvzoP0.js +0 -94
- package/dist/_chunks/define-cookie-BowvzoP0.js.map +0 -1
- package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +0 -1
- package/dist/_chunks/interception-BbqMCVXa.js.map +0 -1
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js +0 -41
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +0 -1
- package/dist/_chunks/request-context-CK5tZqIP.js +0 -478
- package/dist/_chunks/request-context-CK5tZqIP.js.map +0 -1
- package/dist/_chunks/router-ref-C8OCm7g7.js.map +0 -1
- package/dist/_chunks/segment-classify-BDNn6EzD.js +0 -65
- package/dist/_chunks/segment-classify-BDNn6EzD.js.map +0 -1
- package/dist/_chunks/tracing-CCYbKn5n.js +0 -238
- package/dist/_chunks/tracing-CCYbKn5n.js.map +0 -1
- package/dist/_chunks/use-params-IOPu7E8t.js.map +0 -1
- package/dist/_chunks/use-query-states-BiV5GJgm.js.map +0 -1
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/plugins/dev-404-page.d.ts.map +0 -1
- package/dist/plugins/dev-browser-logs.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-error-page.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dev-terminal-error.d.ts.map +0 -1
- package/dist/server/deny-page-resolver.d.ts +0 -52
- package/dist/server/deny-page-resolver.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-holding-server.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.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/page-deny-boundary.d.ts +0 -31
- package/dist/server/page-deny-boundary.d.ts.map +0 -1
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/page-deny-boundary.tsx +0 -56
- /package/src/client/{use-params.ts → use-segment-params.ts} +0 -0
- /package/src/{plugins/dev-browser-logs.ts → dev-tools/browser-logs.ts} +0 -0
- /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Shared build-output helper for adapter buildOutput() methods.
|
|
2
|
+
//
|
|
3
|
+
// Steps 1–5 of every adapter's buildOutput are platform-agnostic:
|
|
4
|
+
// 1. Copy client assets to the public/static directory
|
|
5
|
+
// 2. Write _headers file for static asset cache control
|
|
6
|
+
// 3. Copy RSC + SSR server bundles
|
|
7
|
+
// 4. Write manifest-init module (if present)
|
|
8
|
+
//
|
|
9
|
+
// Only the final steps (entry codegen, platform config) vary per adapter.
|
|
10
|
+
//
|
|
11
|
+
// IMPORTANT: This module must remain a leaf — no imports from ../server/,
|
|
12
|
+
// ../client/, or Vite-dependent code. See adapters/shared.ts header.
|
|
13
|
+
|
|
14
|
+
import { writeFile, mkdir, cp } from 'node:fs/promises';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { generateHeadersFile } from './shared.js';
|
|
17
|
+
import type { TimberConfig } from './types';
|
|
18
|
+
|
|
19
|
+
/** Options for the shared build output steps. */
|
|
20
|
+
export interface BuildOutputBaseOptions {
|
|
21
|
+
/** Resolved timber config. */
|
|
22
|
+
config: TimberConfig;
|
|
23
|
+
/** Root build directory (e.g. `.timber/build`). */
|
|
24
|
+
buildDir: string;
|
|
25
|
+
/** Adapter-specific output directory (e.g. `.timber/build/nitro`). */
|
|
26
|
+
outDir: string;
|
|
27
|
+
/**
|
|
28
|
+
* Name of the public/static directory within outDir.
|
|
29
|
+
* Nitro uses 'public', Cloudflare uses 'static'.
|
|
30
|
+
*/
|
|
31
|
+
publicDirName: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Run the platform-agnostic build output steps shared by all adapters:
|
|
36
|
+
*
|
|
37
|
+
* 1. Create the output directory
|
|
38
|
+
* 2. Copy client assets to the public/static directory
|
|
39
|
+
* 3. Write the `_headers` file for static asset cache control
|
|
40
|
+
* 4. Copy RSC and SSR server bundles into the output directory
|
|
41
|
+
* 5. Write the manifest-init module if present
|
|
42
|
+
*
|
|
43
|
+
* Returns the resolved public directory path for further adapter-specific use.
|
|
44
|
+
*/
|
|
45
|
+
export async function runSharedBuildSteps(opts: BuildOutputBaseOptions): Promise<string> {
|
|
46
|
+
const { config, buildDir, outDir, publicDirName } = opts;
|
|
47
|
+
|
|
48
|
+
// 1. Create the output directory.
|
|
49
|
+
await mkdir(outDir, { recursive: true });
|
|
50
|
+
|
|
51
|
+
// 2. Copy client assets to public/static directory.
|
|
52
|
+
// When client JavaScript is disabled, skip .js files — only CSS,
|
|
53
|
+
// fonts, images, and other static assets are needed.
|
|
54
|
+
const clientDir = join(buildDir, 'client');
|
|
55
|
+
const publicDir = join(outDir, publicDirName);
|
|
56
|
+
await mkdir(publicDir, { recursive: true });
|
|
57
|
+
await cp(clientDir, publicDir, {
|
|
58
|
+
recursive: true,
|
|
59
|
+
filter: config.clientJavascriptDisabled ? (src: string) => !src.endsWith('.js') : undefined,
|
|
60
|
+
}).catch(() => {
|
|
61
|
+
// Client dir may not exist when client JavaScript is disabled
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 3. Write _headers file for static asset cache control.
|
|
65
|
+
await writeFile(join(publicDir, '_headers'), generateHeadersFile());
|
|
66
|
+
|
|
67
|
+
// 4. Copy RSC + SSR server bundles into the output directory.
|
|
68
|
+
await cp(join(buildDir, 'rsc'), join(outDir, 'rsc'), { recursive: true });
|
|
69
|
+
await cp(join(buildDir, 'ssr'), join(outDir, 'ssr'), { recursive: true }).catch(() => {});
|
|
70
|
+
|
|
71
|
+
// 5. Write manifest-init module if present.
|
|
72
|
+
if (config.manifestInit) {
|
|
73
|
+
await writeFile(join(outDir, '_timber-manifest-init.js'), config.manifestInit);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return publicDir;
|
|
77
|
+
}
|
|
@@ -3,28 +3,12 @@
|
|
|
3
3
|
// Primary deployment target. Generates a Workers-compatible entry point
|
|
4
4
|
// and wrangler.jsonc configuration. See design/11-platform.md §"Cloudflare Workers".
|
|
5
5
|
|
|
6
|
-
import { writeFile
|
|
6
|
+
import { writeFile } from 'node:fs/promises';
|
|
7
7
|
import { execFile } from 'node:child_process';
|
|
8
8
|
import { join, relative } from 'node:path';
|
|
9
9
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
10
10
|
import type { TimberPlatformAdapter, TimberConfig } from './types';
|
|
11
|
-
|
|
12
|
-
// Vite startup time, before Vite's module resolver is available, so cross-
|
|
13
|
-
// directory .ts imports don't resolve.
|
|
14
|
-
const IMMUTABLE_CACHE = 'public, max-age=31536000, immutable';
|
|
15
|
-
const STATIC_CACHE = 'public, max-age=3600, must-revalidate';
|
|
16
|
-
|
|
17
|
-
function generateHeadersFile(): string {
|
|
18
|
-
return `# Auto-generated by @timber-js/app — static asset cache headers.
|
|
19
|
-
# See design/25-production-deployments.md §"CDN / Edge Cache"
|
|
20
|
-
|
|
21
|
-
/assets/*
|
|
22
|
-
Cache-Control: ${IMMUTABLE_CACHE}
|
|
23
|
-
|
|
24
|
-
/*
|
|
25
|
-
Cache-Control: ${STATIC_CACHE}
|
|
26
|
-
`;
|
|
27
|
-
}
|
|
11
|
+
import { runSharedBuildSteps } from './build-output-helper.js';
|
|
28
12
|
|
|
29
13
|
// ─── Bindings passthrough ─────────────────────────────────────────────────
|
|
30
14
|
// ALS stores the env object per-request so server components and middleware
|
|
@@ -243,39 +227,15 @@ export function cloudflare(options: CloudflareAdapterOptions = {}): TimberPlatfo
|
|
|
243
227
|
|
|
244
228
|
async buildOutput(config: TimberConfig, buildDir: string) {
|
|
245
229
|
const outDir = join(buildDir, 'cloudflare');
|
|
246
|
-
await mkdir(outDir, { recursive: true });
|
|
247
|
-
|
|
248
|
-
// Copy client assets to static output.
|
|
249
|
-
// When client JavaScript is disabled, skip .js files — only CSS,
|
|
250
|
-
// fonts, images, and other static assets are needed.
|
|
251
|
-
const clientDir = join(buildDir, 'client');
|
|
252
|
-
const staticDir = join(outDir, 'static');
|
|
253
|
-
await mkdir(staticDir, { recursive: true });
|
|
254
|
-
await cp(clientDir, staticDir, {
|
|
255
|
-
recursive: true,
|
|
256
|
-
filter: config.clientJavascriptDisabled ? (src: string) => !src.endsWith('.js') : undefined,
|
|
257
|
-
}).catch(() => {
|
|
258
|
-
// Client dir may not exist when client JavaScript is disabled
|
|
259
|
-
});
|
|
260
230
|
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const ssrDir = join(buildDir, 'ssr');
|
|
270
|
-
await cp(rscDir, join(outDir, 'rsc'), { recursive: true });
|
|
271
|
-
await cp(ssrDir, join(outDir, 'ssr'), { recursive: true });
|
|
272
|
-
|
|
273
|
-
// Write the build manifest init module (if manifest data was produced).
|
|
274
|
-
// This must be imported before the RSC handler so the global is set
|
|
275
|
-
// when virtual:timber-build-manifest evaluates.
|
|
276
|
-
if (config.manifestInit) {
|
|
277
|
-
await writeFile(join(outDir, '_timber-manifest-init.js'), config.manifestInit);
|
|
278
|
-
}
|
|
231
|
+
// Steps 1–5: shared across all adapters (mkdir, copy client/rsc/ssr,
|
|
232
|
+
// write _headers, write manifest-init).
|
|
233
|
+
await runSharedBuildSteps({
|
|
234
|
+
config,
|
|
235
|
+
buildDir,
|
|
236
|
+
outDir,
|
|
237
|
+
publicDirName: 'static',
|
|
238
|
+
});
|
|
279
239
|
|
|
280
240
|
// Compile optional worker handlers (queue, scheduled, etc.)
|
|
281
241
|
// Uses Vite's build API to bundle the TypeScript source into ESM.
|
package/src/adapters/nitro.ts
CHANGED
|
@@ -5,28 +5,13 @@
|
|
|
5
5
|
// compression, graceful shutdown, static file serving, and platform quirks.
|
|
6
6
|
// See design/11-platform.md and design/25-production-deployments.md.
|
|
7
7
|
|
|
8
|
-
import { writeFile, readFile
|
|
8
|
+
import { writeFile, readFile } from 'node:fs/promises';
|
|
9
9
|
import { execFile } from 'node:child_process';
|
|
10
10
|
import { join, relative } from 'node:path';
|
|
11
11
|
import type { TimberPlatformAdapter, TimberConfig } from './types';
|
|
12
12
|
import { generateCompressModule } from './compress-module.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// directory .ts imports don't resolve.
|
|
16
|
-
const IMMUTABLE_CACHE = 'public, max-age=31536000, immutable';
|
|
17
|
-
const STATIC_CACHE = 'public, max-age=3600, must-revalidate';
|
|
18
|
-
|
|
19
|
-
function generateHeadersFile(): string {
|
|
20
|
-
return `# Auto-generated by @timber-js/app — static asset cache headers.
|
|
21
|
-
# See design/25-production-deployments.md §"CDN / Edge Cache"
|
|
22
|
-
|
|
23
|
-
/assets/*
|
|
24
|
-
Cache-Control: ${IMMUTABLE_CACHE}
|
|
25
|
-
|
|
26
|
-
/*
|
|
27
|
-
Cache-Control: ${STATIC_CACHE}
|
|
28
|
-
`;
|
|
29
|
-
}
|
|
13
|
+
import { IMMUTABLE_CACHE } from './shared.js';
|
|
14
|
+
import { runSharedBuildSteps } from './build-output-helper.js';
|
|
30
15
|
|
|
31
16
|
// ─── Presets ─────────────────────────────────────────────────────────────────
|
|
32
17
|
|
|
@@ -202,40 +187,21 @@ export function nitro(options: NitroAdapterOptions = {}): TimberPlatformAdapter
|
|
|
202
187
|
|
|
203
188
|
async buildOutput(config: TimberConfig, buildDir: string) {
|
|
204
189
|
const outDir = join(buildDir, 'nitro');
|
|
205
|
-
await mkdir(outDir, { recursive: true });
|
|
206
|
-
|
|
207
|
-
// Copy client assets to public directory.
|
|
208
|
-
// When client JavaScript is disabled, skip .js files — only CSS,
|
|
209
|
-
// fonts, images, and other static assets are needed.
|
|
210
|
-
const clientDir = join(buildDir, 'client');
|
|
211
|
-
const publicDir = join(outDir, 'public');
|
|
212
|
-
await mkdir(publicDir, { recursive: true });
|
|
213
|
-
await cp(clientDir, publicDir, {
|
|
214
|
-
recursive: true,
|
|
215
|
-
filter: config.clientJavascriptDisabled ? (src: string) => !src.endsWith('.js') : undefined,
|
|
216
|
-
}).catch(() => {
|
|
217
|
-
// Client dir may not exist when client JavaScript is disabled
|
|
218
|
-
});
|
|
219
190
|
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
await
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
191
|
+
// Steps 1–5: shared across all adapters (mkdir, copy client/rsc/ssr,
|
|
192
|
+
// write _headers, write manifest-init).
|
|
193
|
+
await runSharedBuildSteps({
|
|
194
|
+
config,
|
|
195
|
+
buildDir,
|
|
196
|
+
outDir,
|
|
197
|
+
publicDirName: 'public',
|
|
198
|
+
});
|
|
228
199
|
|
|
229
200
|
// Write the compression helper module for runtime use.
|
|
230
201
|
// See design/25-production-deployments.md — self-hosted deployments
|
|
231
202
|
// need application-level compression (Cloudflare handles it at the edge).
|
|
232
203
|
await writeFile(join(outDir, '_compress.mjs'), generateCompressModule());
|
|
233
204
|
|
|
234
|
-
// Copy rsc/ssr build output into the nitro dir so imports stay local
|
|
235
|
-
// during the Nitro bundling step (avoids broken relative paths in output).
|
|
236
|
-
await cp(join(buildDir, 'rsc'), join(outDir, 'rsc'), { recursive: true });
|
|
237
|
-
await cp(join(buildDir, 'ssr'), join(outDir, 'ssr'), { recursive: true }).catch(() => {});
|
|
238
|
-
|
|
239
205
|
// Prepend the manifest assignment directly into the RSC entry so
|
|
240
206
|
// globalThis.__TIMBER_BUILD_MANIFEST__ is set before any module reads it.
|
|
241
207
|
// This must be top-level code, not an import, because rollup tree-shakes
|
|
@@ -486,11 +452,25 @@ const MIME_TYPES = {
|
|
|
486
452
|
};
|
|
487
453
|
|
|
488
454
|
const publicDir = join(__dirname, '${publicDir}');
|
|
489
|
-
|
|
455
|
+
|
|
456
|
+
// Port resolution (TIM-842):
|
|
457
|
+
// - Default to 3000
|
|
458
|
+
// - If PORT env var is set, honor it strictly (fail loudly on conflict)
|
|
459
|
+
// - Otherwise auto-bump from 3000 until a free port is found
|
|
460
|
+
// Mirrors the dev server behavior so timber dev/preview/production all
|
|
461
|
+
// behave the same way around port selection.
|
|
462
|
+
const envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : null;
|
|
463
|
+
const portIsExplicit = envPort != null && Number.isFinite(envPort) && envPort > 0;
|
|
464
|
+
const startPort = portIsExplicit ? envPort : 3000;
|
|
490
465
|
const host = process.env.HOST || process.env.HOSTNAME || 'localhost';
|
|
491
466
|
|
|
467
|
+
// Set after listenWithBump() resolves so request handlers can build
|
|
468
|
+
// absolute URLs from the actual bound port (which may differ from
|
|
469
|
+
// startPort after an auto-bump).
|
|
470
|
+
let boundPort = startPort;
|
|
471
|
+
|
|
492
472
|
const server = createServer(async (req, res) => {
|
|
493
|
-
const url = new URL(req.url || '/', \`http://\${host}:\${
|
|
473
|
+
const url = new URL(req.url || '/', \`http://\${host}:\${boundPort}\`);
|
|
494
474
|
|
|
495
475
|
// Try serving static files from the public directory first.
|
|
496
476
|
const filePath = join(publicDir, url.pathname);
|
|
@@ -631,13 +611,49 @@ const server = createServer(async (req, res) => {
|
|
|
631
611
|
}
|
|
632
612
|
});
|
|
633
613
|
|
|
634
|
-
|
|
614
|
+
function listenWithBump(port, attempt = 0) {
|
|
615
|
+
return new Promise((resolveListen, rejectListen) => {
|
|
616
|
+
const onError = (err) => {
|
|
617
|
+
server.removeListener('listening', onListening);
|
|
618
|
+
if (err && err.code === 'EADDRINUSE' && !portIsExplicit && attempt < 100) {
|
|
619
|
+
if (attempt === 0) {
|
|
620
|
+
console.log(\` [timber] Port \${port} in use, trying \${port + 1}...\`);
|
|
621
|
+
}
|
|
622
|
+
listenWithBump(port + 1, attempt + 1).then(resolveListen, rejectListen);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
rejectListen(err);
|
|
626
|
+
};
|
|
627
|
+
const onListening = () => {
|
|
628
|
+
server.removeListener('error', onError);
|
|
629
|
+
resolveListen(port);
|
|
630
|
+
};
|
|
631
|
+
server.once('error', onError);
|
|
632
|
+
server.once('listening', onListening);
|
|
633
|
+
server.listen(port, host);
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
try {
|
|
638
|
+
boundPort = await listenWithBump(startPort);
|
|
639
|
+
if (boundPort !== startPort) {
|
|
640
|
+
console.log();
|
|
641
|
+
console.log(\` [timber] Port \${startPort} in use, using \${boundPort}\`);
|
|
642
|
+
}
|
|
635
643
|
console.log();
|
|
636
644
|
console.log(' ⚡ timber preview server running at:');
|
|
637
645
|
console.log();
|
|
638
|
-
console.log(\` ➜ http://\${host}:\${
|
|
646
|
+
console.log(\` ➜ http://\${host}:\${boundPort}\`);
|
|
639
647
|
console.log();
|
|
640
|
-
})
|
|
648
|
+
} catch (err) {
|
|
649
|
+
if (err && err.code === 'EADDRINUSE') {
|
|
650
|
+
console.error(\`[timber] Port \${startPort} is already in use. \` +
|
|
651
|
+
'Set PORT to a free port, or unset PORT to auto-pick.');
|
|
652
|
+
} else {
|
|
653
|
+
console.error('[timber] Failed to start preview server:', err);
|
|
654
|
+
}
|
|
655
|
+
process.exit(1);
|
|
656
|
+
}
|
|
641
657
|
`;
|
|
642
658
|
}
|
|
643
659
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Shared adapter utilities — leaf module with zero deps on server/, client/,
|
|
2
|
+
// or any Vite-dependent code.
|
|
3
|
+
//
|
|
4
|
+
// Adapters are loaded by Node at Vite startup time, before Vite's module
|
|
5
|
+
// resolver is available. This module uses only Node built-ins and can be
|
|
6
|
+
// imported by both adapters via a relative path.
|
|
7
|
+
//
|
|
8
|
+
// IMPORTANT: Do NOT add imports from ../server/, ../client/, ../plugins/,
|
|
9
|
+
// or any module that transitively depends on Vite. A test in
|
|
10
|
+
// tests/adapters/shared-no-forbidden-imports.test.ts enforces this.
|
|
11
|
+
|
|
12
|
+
// ─── Static asset cache headers ──────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/** Cache-Control value for hashed (immutable) assets. */
|
|
15
|
+
export const IMMUTABLE_CACHE = 'public, max-age=31536000, immutable';
|
|
16
|
+
|
|
17
|
+
/** Cache-Control value for unhashed static assets. */
|
|
18
|
+
export const STATIC_CACHE = 'public, max-age=3600, must-revalidate';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Generate a `_headers` file for static asset cache control.
|
|
22
|
+
*
|
|
23
|
+
* The `_headers` file is a platform convention supported by Cloudflare Workers
|
|
24
|
+
* Static Assets, Cloudflare Pages, and Netlify. It maps URL patterns to
|
|
25
|
+
* HTTP response headers.
|
|
26
|
+
*
|
|
27
|
+
* Vite places all hashed chunks under `/assets/` — these get immutable caching.
|
|
28
|
+
* Everything else (favicon.ico, robots.txt, etc.) gets a shorter cache.
|
|
29
|
+
*/
|
|
30
|
+
export function generateHeadersFile(): string {
|
|
31
|
+
return `# Auto-generated by @timber-js/app — static asset cache headers.
|
|
32
|
+
# See design/25-production-deployments.md §"CDN / Edge Cache"
|
|
33
|
+
|
|
34
|
+
/assets/*
|
|
35
|
+
Cache-Control: ${IMMUTABLE_CACHE}
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
Cache-Control: ${STATIC_CACHE}
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { CacheHandler, CacheOptions } from './index';
|
|
|
2
2
|
import { stableStringify } from './stable-stringify';
|
|
3
3
|
import { createSingleflight } from './singleflight';
|
|
4
4
|
import { addSpanEventSync } from '../server/tracing.js';
|
|
5
|
+
import { logSwrRefetchFailed } from '../server/logger.js';
|
|
5
6
|
import { fnv1aHash } from './fast-hash.js';
|
|
6
7
|
|
|
7
8
|
const defaultSingleflight = createSingleflight();
|
|
@@ -91,9 +92,9 @@ export function createCache<Fn extends (...args: any[]) => Promise<any>>(
|
|
|
91
92
|
const fresh = await fn(...args);
|
|
92
93
|
const tags = resolveTags(opts, args);
|
|
93
94
|
await handler.set(key, fresh, { ttl: opts.ttl, tags });
|
|
94
|
-
} catch {
|
|
95
|
+
} catch (err) {
|
|
95
96
|
// Failed refetch — stale entry continues to be served.
|
|
96
|
-
|
|
97
|
+
logSwrRefetchFailed({ cacheKey: key, error: err });
|
|
97
98
|
}
|
|
98
99
|
}).catch(() => {
|
|
99
100
|
// Singleflight promise rejection handled — stale continues.
|
package/src/client/form.tsx
CHANGED
|
@@ -27,13 +27,15 @@ export type UseActionStateFn<TData> = (
|
|
|
27
27
|
) => Promise<ActionResult<TData>>;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Return type of useActionState
|
|
31
|
-
* [result, formAction, isPending]
|
|
30
|
+
* Return type of useActionState.
|
|
31
|
+
* [result, formAction, isPending, errors]
|
|
32
|
+
* The 4th element is auto-derived from result via useFormErrors logic.
|
|
32
33
|
*/
|
|
33
34
|
export type UseActionStateReturn<TData> = [
|
|
34
35
|
result: ActionResult<TData> | null,
|
|
35
36
|
formAction: (formData: FormData) => void,
|
|
36
37
|
isPending: boolean,
|
|
38
|
+
errors: FormErrorsResult,
|
|
37
39
|
];
|
|
38
40
|
|
|
39
41
|
// ─── useActionState ──────────────────────────────────────────────────────
|
|
@@ -73,7 +75,13 @@ export function useActionState<TData>(
|
|
|
73
75
|
): UseActionStateReturn<TData> {
|
|
74
76
|
// FormFlashData is structurally compatible with ActionResult at runtime —
|
|
75
77
|
// the cast satisfies React's generic inference which would otherwise widen TData.
|
|
76
|
-
|
|
78
|
+
const [result, formAction, isPending] = reactUseActionState(
|
|
79
|
+
action,
|
|
80
|
+
initialState as ActionResult<TData> | null,
|
|
81
|
+
permalink
|
|
82
|
+
);
|
|
83
|
+
const errors = deriveFormErrors(result);
|
|
84
|
+
return [result, formAction, isPending, errors];
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
// ─── useFormAction ───────────────────────────────────────────────────────
|
|
@@ -114,9 +122,9 @@ export function useFormAction<TData = unknown, TInput = unknown>(
|
|
|
114
122
|
return [execute, isPending];
|
|
115
123
|
}
|
|
116
124
|
|
|
117
|
-
// ───
|
|
125
|
+
// ─── Form error extraction ────────────────────────────────────────────────
|
|
118
126
|
|
|
119
|
-
/** Return type of
|
|
127
|
+
/** Return type of the errors element in useActionState. */
|
|
120
128
|
export interface FormErrorsResult {
|
|
121
129
|
/** Per-field validation errors keyed by field name. */
|
|
122
130
|
fieldErrors: Record<string, string[]>;
|
|
@@ -131,27 +139,11 @@ export interface FormErrorsResult {
|
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* since it's used in render. Accepts the result from `useActionState`
|
|
138
|
-
* or flash data from `getFormFlash()`.
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* ```tsx
|
|
142
|
-
* const [result, action, isPending] = useActionState(createTodo, null)
|
|
143
|
-
* const errors = useFormErrors(result)
|
|
144
|
-
*
|
|
145
|
-
* return (
|
|
146
|
-
* <form action={action}>
|
|
147
|
-
* <input name="title" />
|
|
148
|
-
* {errors.getFieldError('title') && <p>{errors.getFieldError('title')}</p>}
|
|
149
|
-
* {errors.formErrors.map(e => <p key={e}>{e}</p>)}
|
|
150
|
-
* </form>
|
|
151
|
-
* )
|
|
152
|
-
* ```
|
|
142
|
+
* Derive FormErrorsResult from an action result.
|
|
143
|
+
* Used internally by useActionState 4th tuple element.
|
|
144
|
+
* @internal — exported for test access only.
|
|
153
145
|
*/
|
|
154
|
-
export function
|
|
146
|
+
export function deriveFormErrors<TData>(
|
|
155
147
|
result:
|
|
156
148
|
| ActionResult<TData>
|
|
157
149
|
| {
|
package/src/client/index.ts
CHANGED
|
@@ -66,26 +66,33 @@ export type { LinkStatus } from './use-link-status';
|
|
|
66
66
|
export { useRouter } from './use-router';
|
|
67
67
|
export type { AppRouterInstance } from './use-router';
|
|
68
68
|
export { usePathname } from './use-pathname';
|
|
69
|
-
|
|
69
|
+
// useSearchParams removed from public exports — lives in next/navigation shim only.
|
|
70
70
|
export { useSelectedLayoutSegment, useSelectedLayoutSegments } from './use-selected-layout-segment';
|
|
71
71
|
|
|
72
72
|
// Forms
|
|
73
|
-
export { useActionState, useFormAction
|
|
73
|
+
export { useActionState, useFormAction } from './form';
|
|
74
74
|
export type { UseActionStateFn, UseActionStateReturn, FormErrorsResult } from './form';
|
|
75
75
|
|
|
76
|
-
// Params
|
|
77
|
-
|
|
76
|
+
// Params — useSegmentParams lives on defineSegmentParams().useSegmentParams()
|
|
77
|
+
// and in the next/navigation shim for library compat.
|
|
78
78
|
|
|
79
|
-
// Query states
|
|
80
|
-
|
|
79
|
+
// Query states — useQueryStates lives on defineSearchParams().useQueryStates()
|
|
80
|
+
// and is available via direct import for advanced cases.
|
|
81
81
|
|
|
82
|
-
// Cookies
|
|
83
|
-
|
|
82
|
+
// Cookies — useCookie lives on defineCookie().useCookie().
|
|
83
|
+
// Types still exported for advanced use.
|
|
84
84
|
export type { ClientCookieOptions, CookieSetter } from './use-cookie';
|
|
85
85
|
|
|
86
86
|
// Register the client cookie module with defineCookie's lazy reference.
|
|
87
87
|
// This runs at module load time in the client/SSR environment, wiring up
|
|
88
88
|
// the useCookie hook without a top-level import in define-cookie.ts.
|
|
89
89
|
import * as _useCookieMod from './use-cookie.js';
|
|
90
|
-
import { _registerUseCookieModule } from '../cookies/define-cookie.js';
|
|
90
|
+
import { _registerUseCookieModule, _registerFromSchema } from '../cookies/define-cookie.js';
|
|
91
|
+
import { fromSchema } from '../schema-bridge.js';
|
|
91
92
|
_registerUseCookieModule(_useCookieMod);
|
|
93
|
+
_registerFromSchema(fromSchema);
|
|
94
|
+
|
|
95
|
+
// Register the client useSegmentParams hook with defineSegmentParams.
|
|
96
|
+
import { useSegmentParams as _useSegmentParams } from './use-segment-params.js';
|
|
97
|
+
import { _registerUseSegmentParams } from '../segment-params/define.js';
|
|
98
|
+
_registerUseSegmentParams(_useSegmentParams);
|
package/src/client/internal.ts
CHANGED
|
@@ -38,8 +38,9 @@ export type { SegmentNode, StateTree } from './segment-cache.js';
|
|
|
38
38
|
export { HistoryStack } from './history.js';
|
|
39
39
|
export type { HistoryEntry } from './history.js';
|
|
40
40
|
|
|
41
|
-
// ── Params (internal setter)
|
|
42
|
-
export { setCurrentParams } from './use-params.js';
|
|
41
|
+
// ── Params (internal setter + raw hooks) ─────────────────────────────────
|
|
42
|
+
export { setCurrentParams, useSegmentParams } from './use-segment-params.js';
|
|
43
|
+
export { useSearchParams } from './use-search-params.js';
|
|
43
44
|
|
|
44
45
|
// ── Navigation context ───────────────────────────────────────────────────
|
|
45
46
|
export {
|
package/src/client/router.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { SegmentCache, PrefetchCache, buildSegmentTree } from './segment-cache';
|
|
|
5
5
|
import type { SegmentInfo } from './segment-cache';
|
|
6
6
|
import { HistoryStack } from './history';
|
|
7
7
|
import type { HeadElement } from './head';
|
|
8
|
-
import { setCurrentParams } from './use-params.js';
|
|
8
|
+
import { setCurrentParams } from './use-segment-params.js';
|
|
9
9
|
import {
|
|
10
10
|
setNavigationState,
|
|
11
11
|
getNavigationState,
|
package/src/client/rsc-fetch.ts
CHANGED
|
@@ -124,6 +124,17 @@ export function buildRscHeaders(
|
|
|
124
124
|
|
|
125
125
|
// ─── Response Header Extraction ──────────────────────────────────
|
|
126
126
|
|
|
127
|
+
/** Dev-only warning for malformed framework headers. Tree-shaken in production. */
|
|
128
|
+
function warnMalformedHeader(headerName: string, raw: string): void {
|
|
129
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
130
|
+
const preview = raw.length > 200 ? raw.slice(0, 200) + '…' : raw;
|
|
131
|
+
console.warn(
|
|
132
|
+
`[timber] Malformed ${headerName} header \u2014 JSON.parse failed. ` +
|
|
133
|
+
`This indicates a framework bug or header corruption. Raw (first 200 chars): ${preview}`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
127
138
|
/**
|
|
128
139
|
* Extract head elements from the X-Timber-Head response header.
|
|
129
140
|
* Returns null if the header is missing or malformed.
|
|
@@ -134,6 +145,7 @@ export function extractHeadElements(response: Response): HeadElement[] | null {
|
|
|
134
145
|
try {
|
|
135
146
|
return JSON.parse(decodeURIComponent(header));
|
|
136
147
|
} catch {
|
|
148
|
+
warnMalformedHeader('X-Timber-Head', header);
|
|
137
149
|
return null;
|
|
138
150
|
}
|
|
139
151
|
}
|
|
@@ -152,6 +164,7 @@ export function extractSegmentInfo(response: Response): SegmentInfo[] | null {
|
|
|
152
164
|
try {
|
|
153
165
|
return JSON.parse(header);
|
|
154
166
|
} catch {
|
|
167
|
+
warnMalformedHeader('X-Timber-Segments', header);
|
|
155
168
|
return null;
|
|
156
169
|
}
|
|
157
170
|
}
|
|
@@ -171,6 +184,7 @@ export function extractSkippedSegments(response: Response): string[] | null {
|
|
|
171
184
|
const parsed = JSON.parse(header);
|
|
172
185
|
return Array.isArray(parsed) ? parsed : null;
|
|
173
186
|
} catch {
|
|
187
|
+
warnMalformedHeader('X-Timber-Skipped-Segments', header);
|
|
174
188
|
return null;
|
|
175
189
|
}
|
|
176
190
|
}
|
|
@@ -187,6 +201,7 @@ export function extractParams(response: Response): Record<string, string | strin
|
|
|
187
201
|
try {
|
|
188
202
|
return JSON.parse(header);
|
|
189
203
|
} catch {
|
|
204
|
+
warnMalformedHeader('X-Timber-Params', header);
|
|
190
205
|
return null;
|
|
191
206
|
}
|
|
192
207
|
}
|
package/src/client/state.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ALL mutable module-level state that must have singleton semantics across
|
|
5
5
|
* the client bundle lives here. Individual modules (router-ref.ts, ssr-data.ts,
|
|
6
|
-
* use-params.ts, use-search-params.ts, unload-guard.ts) import from this file
|
|
6
|
+
* use-segment-params.ts, use-search-params.ts, unload-guard.ts) import from this file
|
|
7
7
|
* and re-export thin wrapper functions.
|
|
8
8
|
*
|
|
9
9
|
* Why: In Vite dev, a module is instantiated separately if reached via different
|
|
@@ -50,7 +50,7 @@ export function _setCurrentSsrData(data: SsrData | undefined): void {
|
|
|
50
50
|
currentSsrData = data;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
// ─── Route Params (from use-params.ts) ──────────────────────────────────────
|
|
53
|
+
// ─── Route Params (from use-segment-params.ts) ──────────────────────────────────────
|
|
54
54
|
|
|
55
55
|
/** Current route params snapshot — replaced (not mutated) on each navigation. */
|
|
56
56
|
export let currentParams: Record<string, string | string[]> = {};
|
package/src/client/use-cookie.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { useSyncExternalStore } from 'react';
|
|
12
12
|
import { getSsrData } from './ssr-data.js';
|
|
13
|
+
import { assertValidCookieName } from '../cookies/validation.js';
|
|
13
14
|
|
|
14
15
|
// ─── Types ────────────────────────────────────────────────────────────────
|
|
15
16
|
|
|
@@ -68,6 +69,17 @@ function notify(name: string): void {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Notify useCookie subscribers that a cookie value changed.
|
|
74
|
+
* Called by defineCookie's imperative client .set()/.delete() methods
|
|
75
|
+
* so mounted useCookie() consumers re-render.
|
|
76
|
+
*
|
|
77
|
+
* @internal — framework use only
|
|
78
|
+
*/
|
|
79
|
+
export function notifyCookieChange(name: string): void {
|
|
80
|
+
notify(name);
|
|
81
|
+
}
|
|
82
|
+
|
|
71
83
|
// ─── Hook ─────────────────────────────────────────────────────────────────
|
|
72
84
|
|
|
73
85
|
/**
|
|
@@ -103,8 +115,25 @@ export function useCookie(
|
|
|
103
115
|
|
|
104
116
|
const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
105
117
|
|
|
118
|
+
// Validate the name once per hook instance — names are typically
|
|
119
|
+
// stable string literals, so this catches the bug at first render
|
|
120
|
+
// rather than on every write. Throws via `assertValidCookieName` with
|
|
121
|
+
// a precise error if the name violates RFC 7230 token rules.
|
|
122
|
+
assertValidCookieName(name);
|
|
123
|
+
|
|
106
124
|
const setCookie: CookieSetter = (newValue: string, options?: ClientCookieOptions) => {
|
|
125
|
+
if (typeof newValue !== 'string') {
|
|
126
|
+
throw new Error(
|
|
127
|
+
`[timber] useCookie(${JSON.stringify(name)}): value must be a string, got ${typeof newValue}.\n` +
|
|
128
|
+
` To store a JSON-serializable value, use defineCookie + jsonCookieCodec from\n` +
|
|
129
|
+
` '@timber-js/app/cookies' and call its useCookie() hook instead.`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
107
132
|
const merged = { ...defaultOptions, ...options };
|
|
133
|
+
// Auto-encode mirrors the server's `cookies().set()` contract:
|
|
134
|
+
// values are URL-encoded on write, URL-decoded on read, so the
|
|
135
|
+
// logical bytes round-trip losslessly. See design/29-cookies.md
|
|
136
|
+
// §"Encoding Contract".
|
|
108
137
|
document.cookie = `${name}=${encodeURIComponent(newValue)}${serializeOptions(merged)}`;
|
|
109
138
|
notify(name);
|
|
110
139
|
};
|
package/src/codec.ts
CHANGED
|
@@ -39,11 +39,7 @@ export type JsonSerializable =
|
|
|
39
39
|
|
|
40
40
|
// ─── Standard Schema bridge ──────────────────────────────────────────────
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
validateSync,
|
|
46
|
-
isStandardSchema,
|
|
47
|
-
isCodec,
|
|
48
|
-
} from './schema-bridge.js';
|
|
42
|
+
// fromSchema is internal — defineSearchParams and defineCookie auto-detect
|
|
43
|
+
// Standard Schema objects. Users should pass raw schemas directly.
|
|
44
|
+
export { fromArraySchema, validateSync, isStandardSchema, isCodec } from './schema-bridge.js';
|
|
49
45
|
export type { StandardSchemaV1, StandardSchemaResult } from './schema-bridge.js';
|