@timber-js/app 0.2.0-alpha.6 → 0.2.0-alpha.61
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/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-Ba7URUIn.js} +1 -1
- package/dist/_chunks/als-registry-Ba7URUIn.js.map +1 -0
- package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
- package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
- package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
- package/dist/_chunks/define-CT98cU9c.js +121 -0
- package/dist/_chunks/define-CT98cU9c.js.map +1 -0
- package/dist/_chunks/define-TK8C1M3x.js +279 -0
- package/dist/_chunks/define-TK8C1M3x.js.map +1 -0
- package/dist/_chunks/define-cookie-BWr_52kY.js +93 -0
- package/dist/_chunks/define-cookie-BWr_52kY.js.map +1 -0
- package/dist/_chunks/error-boundary-DpZJBCqh.js +211 -0
- package/dist/_chunks/error-boundary-DpZJBCqh.js.map +1 -0
- package/dist/_chunks/{format-DviM89f0.js → format-cX7wzEp2.js} +2 -2
- package/dist/_chunks/{format-DviM89f0.js.map → format-cX7wzEp2.js.map} +1 -1
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-Cey5DCGr.js} +129 -77
- package/dist/_chunks/interception-Cey5DCGr.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-BU684ls2.js} +1 -1
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-BU684ls2.js.map} +1 -1
- package/dist/_chunks/{request-context-DIkVh_jG.js → request-context-rju2rbga.js} +97 -69
- package/dist/_chunks/request-context-rju2rbga.js.map +1 -0
- package/dist/_chunks/segment-context-CyaM1mrD.js +72 -0
- package/dist/_chunks/segment-context-CyaM1mrD.js.map +1 -0
- package/dist/_chunks/stale-reload-BSSym1MJ.js +64 -0
- package/dist/_chunks/stale-reload-BSSym1MJ.js.map +1 -0
- package/dist/_chunks/{tracing-Cwn7697K.js → tracing-VYETCQsg.js} +17 -3
- package/dist/_chunks/{tracing-Cwn7697K.js.map → tracing-VYETCQsg.js.map} +1 -1
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-wEXY2JQB.js} +1 -1
- package/dist/_chunks/use-query-states-wEXY2JQB.js.map +1 -0
- package/dist/_chunks/wrappers-BaG1bnM3.js +63 -0
- package/dist/_chunks/wrappers-BaG1bnM3.js.map +1 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +17 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +56 -13
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/fast-hash.d.ts +22 -0
- package/dist/cache/fast-hash.d.ts.map +1 -0
- package/dist/cache/index.d.ts +5 -2
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +90 -20
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/register-cached-function.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +18 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/timber-cache.d.ts +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +10 -1
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -125
- package/dist/client/error-reconstituter.d.ts +54 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +2 -2
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +433 -252
- package/dist/client/index.js.map +1 -1
- package/dist/client/link-pending-store.d.ts +78 -0
- package/dist/client/link-pending-store.d.ts.map +1 -0
- package/dist/client/link.d.ts +23 -9
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +2 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/router.d.ts +25 -3
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +36 -2
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-merger.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +63 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +1 -1
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/transition-root.d.ts +1 -1
- package/dist/client/transition-root.d.ts.map +1 -1
- package/dist/client/use-params.d.ts +3 -3
- package/dist/client/use-params.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/codec.d.ts +21 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/cookies/define-cookie.d.ts +34 -13
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -83
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/index.d.ts +127 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +665 -242
- package/dist/index.js.map +1 -1
- package/dist/params/define.d.ts +100 -0
- package/dist/params/define.d.ts.map +1 -0
- package/dist/params/index.d.ts +8 -0
- package/dist/params/index.d.ts.map +1 -0
- package/dist/params/index.js +4 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +2 -2
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +3 -3
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +32 -0
- package/dist/plugins/client-chunks.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-browser-logs.d.ts +84 -0
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
- package/dist/plugins/dev-error-overlay.d.ts +26 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/dev-logs.d.ts +1 -1
- package/dist/plugins/dev-logs.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -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 +9 -2
- 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/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 +6 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +1 -1
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/status-file-lint.d.ts +2 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +16 -4
- package/dist/routing/types.d.ts.map +1 -1
- 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/search-params/codecs.d.ts +1 -1
- package/dist/search-params/define.d.ts +159 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -5
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +4 -474
- package/dist/search-params/registry.d.ts +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/server/access-gate.d.ts +4 -0
- package/dist/server/access-gate.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/server/actions.d.ts +1 -1
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +25 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/debug.d.ts +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-renderer.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +4 -0
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +4 -3
- 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/flush.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +51 -11
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +4 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1977 -1648
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.d.ts +25 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +113 -0
- package/dist/server/node-stream-transforms.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.d.ts +20 -6
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +30 -3
- 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/request-context.d.ts +65 -38
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +7 -0
- 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 +9 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +2 -2
- 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 +48 -5
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +8 -3
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +10 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +22 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +39 -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/status-code-resolver.d.ts +1 -1
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +36 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +10 -0
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +20 -13
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -3
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/waituntil-bridge.d.ts.map +1 -1
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.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/navigation-client.d.ts +1 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +1 -1
- 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/package.json +17 -17
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +58 -9
- package/src/cache/fast-hash.ts +34 -0
- package/src/cache/index.ts +5 -2
- package/src/cache/register-cached-function.ts +7 -3
- package/src/cache/singleflight.ts +62 -4
- package/src/cache/timber-cache.ts +40 -29
- package/src/cli.ts +0 -0
- package/src/client/browser-entry.ts +151 -99
- package/src/client/error-boundary.tsx +18 -1
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +2 -2
- package/src/client/index.ts +10 -1
- package/src/client/link-pending-store.ts +136 -0
- package/src/client/link.tsx +137 -22
- package/src/client/navigation-context.ts +6 -5
- package/src/client/router.ts +117 -60
- package/src/client/rsc-fetch.ts +90 -2
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-context.ts +6 -1
- package/src/client/segment-merger.ts +2 -8
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/stale-reload.ts +73 -6
- package/src/client/top-loader.tsx +10 -9
- package/src/client/transition-root.tsx +20 -2
- package/src/client/use-params.ts +4 -4
- package/src/client/use-query-states.ts +2 -2
- package/src/codec.ts +21 -0
- package/src/cookies/define-cookie.ts +71 -20
- package/src/fonts/css.ts +2 -1
- package/src/index.ts +297 -85
- package/src/params/define.ts +327 -0
- package/src/params/index.ts +28 -0
- package/src/plugins/adapter-build.ts +8 -2
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +3 -3
- package/src/plugins/cache-transform.ts +1 -1
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-browser-logs.ts +284 -0
- package/src/plugins/dev-error-overlay.ts +70 -1
- package/src/plugins/dev-logs.ts +1 -1
- package/src/plugins/dev-server.ts +41 -7
- package/src/plugins/entries.ts +6 -8
- package/src/plugins/fonts.ts +102 -55
- package/src/plugins/mdx.ts +1 -1
- package/src/plugins/routing.ts +57 -17
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +69 -31
- package/src/plugins/static-build.ts +10 -6
- package/src/routing/codegen.ts +109 -88
- package/src/routing/scanner.ts +86 -7
- package/src/routing/status-file-lint.ts +3 -2
- package/src/routing/types.ts +17 -4
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/search-params/codecs.ts +1 -1
- package/src/search-params/define.ts +518 -0
- package/src/search-params/index.ts +12 -18
- package/src/search-params/registry.ts +1 -1
- package/src/search-params/wrappers.ts +85 -0
- package/src/server/access-gate.tsx +40 -9
- package/src/server/action-client.ts +8 -2
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +20 -3
- package/src/server/actions.ts +1 -1
- package/src/server/als-registry.ts +25 -4
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/debug.ts +1 -1
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-renderer.ts +5 -3
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +58 -15
- package/src/server/fallback-error.ts +29 -14
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injectors.ts +277 -117
- package/src/server/index.ts +9 -4
- package/src/server/logger.ts +44 -36
- package/src/server/node-stream-transforms.ts +509 -0
- package/src/server/pipeline-interception.ts +1 -1
- package/src/server/pipeline.ts +148 -41
- package/src/server/primitives.ts +47 -5
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +125 -119
- package/src/server/route-element-builder.ts +107 -115
- package/src/server/route-handler.ts +2 -1
- package/src/server/route-matcher.ts +9 -2
- package/src/server/rsc-entry/api-handler.ts +8 -8
- package/src/server/rsc-entry/error-renderer.ts +286 -81
- package/src/server/rsc-entry/helpers.ts +134 -5
- package/src/server/rsc-entry/index.ts +177 -76
- package/src/server/rsc-entry/rsc-payload.ts +91 -18
- package/src/server/rsc-entry/rsc-stream.ts +74 -18
- package/src/server/rsc-entry/ssr-bridge.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +152 -34
- package/src/server/slot-resolver.ts +231 -220
- package/src/server/ssr-entry.ts +211 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/status-code-resolver.ts +1 -1
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +23 -0
- package/src/server/tree-builder.ts +92 -58
- package/src/server/types.ts +1 -3
- package/src/server/version-skew.ts +104 -0
- package/src/server/waituntil-bridge.ts +4 -1
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/navigation-client.ts +1 -1
- package/src/shims/navigation.ts +2 -1
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
- package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
- package/dist/_chunks/ssr-data-MjmprTmO.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/client/error-boundary.js.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/cookies/index.js.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.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/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/search-params/index.js.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/response-cache.d.ts +0 -53
- package/dist/server/response-cache.d.ts.map +0 -1
- package/src/client/link-status-provider.tsx +0 -30
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/prerender.ts +0 -139
- package/src/server/response-cache.ts +0 -277
package/dist/index.js
CHANGED
|
@@ -1,37 +1,16 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import {
|
|
1
|
+
import { r as __toESM, t as __commonJSMin } from "./_chunks/chunk-DYhsFzuS.js";
|
|
2
|
+
import { r as setViteServer, t as formatSize } from "./_chunks/format-cX7wzEp2.js";
|
|
3
|
+
import { i as scanRoutes, n as generateRouteMap, t as collectInterceptionRewrites } from "./_chunks/interception-Cey5DCGr.js";
|
|
3
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
5
|
import { dirname, extname, join, normalize, resolve } from "node:path";
|
|
5
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
|
-
import react from "@vitejs/plugin-react";
|
|
7
|
+
import react, { reactCompilerPreset } from "@vitejs/plugin-react";
|
|
8
|
+
import { constants, createGzip, gzipSync } from "node:zlib";
|
|
9
|
+
import { Readable } from "node:stream";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
8
11
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
10
|
-
import { gzipSync } from "node:zlib";
|
|
12
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
11
13
|
import { performance as performance$1 } from "node:perf_hooks";
|
|
12
|
-
//#region \0rolldown/runtime.js
|
|
13
|
-
var __create = Object.create;
|
|
14
|
-
var __defProp = Object.defineProperty;
|
|
15
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
16
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
17
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
18
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
19
|
-
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
20
|
-
var __copyProps = (to, from, except, desc) => {
|
|
21
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
22
|
-
key = keys[i];
|
|
23
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
24
|
-
get: ((k) => from[k]).bind(null, key),
|
|
25
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return to;
|
|
29
|
-
};
|
|
30
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
31
|
-
value: mod,
|
|
32
|
-
enumerable: true
|
|
33
|
-
}) : target, mod));
|
|
34
|
-
//#endregion
|
|
35
14
|
//#region ../../node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/dist/acorn.mjs
|
|
36
15
|
var astralIdentifierCodes = [
|
|
37
16
|
509,
|
|
@@ -11486,14 +11465,51 @@ function formatTerminalError(error, phase, projectRoot) {
|
|
|
11486
11465
|
return lines.join("\n");
|
|
11487
11466
|
}
|
|
11488
11467
|
/**
|
|
11468
|
+
* Format RSC debug component info into a readable string for the overlay.
|
|
11469
|
+
*
|
|
11470
|
+
* Renders the server component tree that was active when an error occurred,
|
|
11471
|
+
* including component names and source locations from stack frames. This
|
|
11472
|
+
* gives developers visibility into which server components were rendering
|
|
11473
|
+
* without exposing source code.
|
|
11474
|
+
*
|
|
11475
|
+
* Returns an empty string if no components are provided.
|
|
11476
|
+
*/
|
|
11477
|
+
function formatRscDebugContext(components) {
|
|
11478
|
+
if (!components || components.length === 0) return "";
|
|
11479
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11480
|
+
const unique = [];
|
|
11481
|
+
for (const c of components) if (!seen.has(c.name)) {
|
|
11482
|
+
seen.add(c.name);
|
|
11483
|
+
unique.push(c);
|
|
11484
|
+
}
|
|
11485
|
+
const lines = ["Server Component Tree:"];
|
|
11486
|
+
for (let i = 0; i < unique.length; i++) {
|
|
11487
|
+
const c = unique[i];
|
|
11488
|
+
const indent = " ".repeat(i + 1);
|
|
11489
|
+
const envLabel = c.env ? ` [${c.env}]` : "";
|
|
11490
|
+
let locStr = "";
|
|
11491
|
+
if (c.stack && c.stack.length > 0) {
|
|
11492
|
+
const frame = c.stack[0];
|
|
11493
|
+
if (Array.isArray(frame) && frame.length >= 3) locStr = ` (${frame[1]}:${frame[2]})`;
|
|
11494
|
+
}
|
|
11495
|
+
lines.push(`${indent}${c.name}${envLabel}${locStr}`);
|
|
11496
|
+
}
|
|
11497
|
+
return lines.join("\n");
|
|
11498
|
+
}
|
|
11499
|
+
/**
|
|
11489
11500
|
* Send an error to Vite's browser overlay and log it to stderr.
|
|
11490
11501
|
*
|
|
11491
11502
|
* Uses `server.ssrFixStacktrace()` to map stack traces back to source,
|
|
11492
11503
|
* then sends the error via `server.hot.send()` for the browser overlay.
|
|
11493
11504
|
*
|
|
11505
|
+
* When `rscDebugComponents` is provided (dev mode only), the server
|
|
11506
|
+
* component tree context is appended to the error message. This helps
|
|
11507
|
+
* developers identify which server component caused the error without
|
|
11508
|
+
* exposing source code.
|
|
11509
|
+
*
|
|
11494
11510
|
* The dev server remains running — errors are handled, not fatal.
|
|
11495
11511
|
*/
|
|
11496
|
-
function sendErrorToOverlay(server, error, phase, projectRoot) {
|
|
11512
|
+
function sendErrorToOverlay(server, error, phase, projectRoot, rscDebugComponents) {
|
|
11497
11513
|
server.ssrFixStacktrace(error);
|
|
11498
11514
|
const formatted = formatTerminalError(error, phase, projectRoot);
|
|
11499
11515
|
process.stderr.write(`${formatted}\n`);
|
|
@@ -11501,6 +11517,8 @@ function sendErrorToOverlay(server, error, phase, projectRoot) {
|
|
|
11501
11517
|
const componentStack = extractComponentStack(error);
|
|
11502
11518
|
let message = error.message;
|
|
11503
11519
|
if (componentStack) message = `${error.message}\n\nComponent Stack:\n${componentStack.trim()}`;
|
|
11520
|
+
const debugContext = formatRscDebugContext(rscDebugComponents ?? []);
|
|
11521
|
+
if (debugContext) message = `${message}\n\n${debugContext}`;
|
|
11504
11522
|
try {
|
|
11505
11523
|
server.hot.send({
|
|
11506
11524
|
type: "error",
|
|
@@ -11624,12 +11642,16 @@ function compressResponse(request, response) {
|
|
|
11624
11642
|
});
|
|
11625
11643
|
}
|
|
11626
11644
|
/**
|
|
11627
|
-
* Compress a ReadableStream with gzip
|
|
11628
|
-
*
|
|
11645
|
+
* Compress a ReadableStream with gzip, flushing each chunk immediately.
|
|
11646
|
+
*
|
|
11647
|
+
* Uses node:zlib's createGzip with Z_SYNC_FLUSH to ensure each HTML chunk
|
|
11648
|
+
* (shell, Suspense resolution, RSC payload) is delivered to the browser
|
|
11649
|
+
* as soon as it's available — preserving streaming semantics.
|
|
11629
11650
|
*/
|
|
11630
11651
|
function compressWithGzip(body) {
|
|
11631
|
-
const
|
|
11632
|
-
|
|
11652
|
+
const gzip = createGzip({ flush: constants.Z_SYNC_FLUSH });
|
|
11653
|
+
Readable.fromWeb(body).pipe(gzip);
|
|
11654
|
+
return Readable.toWeb(gzip);
|
|
11633
11655
|
}
|
|
11634
11656
|
//#endregion
|
|
11635
11657
|
//#region src/plugins/dev-server.ts
|
|
@@ -11714,8 +11736,8 @@ function createTimberMiddleware(server, projectRoot) {
|
|
|
11714
11736
|
const rscModule = await rscEnv.runner.import(RSC_ENTRY_ID);
|
|
11715
11737
|
handler = rscModule.default;
|
|
11716
11738
|
const setHandler = rscModule.setDevPipelineErrorHandler;
|
|
11717
|
-
if (typeof setHandler === "function") setHandler((error) => {
|
|
11718
|
-
sendErrorToOverlay(server, error, classifyErrorPhase(error, projectRoot), projectRoot);
|
|
11739
|
+
if (typeof setHandler === "function") setHandler((error, _phase, debugComponents) => {
|
|
11740
|
+
sendErrorToOverlay(server, error, classifyErrorPhase(error, projectRoot), projectRoot, debugComponents);
|
|
11719
11741
|
});
|
|
11720
11742
|
} catch (error) {
|
|
11721
11743
|
if (error instanceof Error) sendErrorToOverlay(server, error, "module-transform", projectRoot);
|
|
@@ -11804,15 +11826,24 @@ async function sendWebResponse(nodeRes, webResponse) {
|
|
|
11804
11826
|
}
|
|
11805
11827
|
nodeRes.flushHeaders();
|
|
11806
11828
|
const reader = webResponse.body.getReader();
|
|
11829
|
+
let clientDisconnected = false;
|
|
11830
|
+
const onClose = () => {
|
|
11831
|
+
clientDisconnected = true;
|
|
11832
|
+
reader.cancel("Client disconnected").catch(() => {});
|
|
11833
|
+
};
|
|
11834
|
+
nodeRes.on("close", onClose);
|
|
11807
11835
|
try {
|
|
11808
11836
|
while (true) {
|
|
11809
11837
|
const { done, value } = await reader.read();
|
|
11810
11838
|
if (done) break;
|
|
11811
11839
|
nodeRes.write(value);
|
|
11812
11840
|
}
|
|
11841
|
+
} catch (err) {
|
|
11842
|
+
if (!clientDisconnected) throw err;
|
|
11813
11843
|
} finally {
|
|
11844
|
+
nodeRes.off("close", onClose);
|
|
11814
11845
|
reader.releaseLock();
|
|
11815
|
-
nodeRes.end();
|
|
11846
|
+
if (!nodeRes.writableEnded) nodeRes.end();
|
|
11816
11847
|
}
|
|
11817
11848
|
}
|
|
11818
11849
|
/**
|
|
@@ -11923,7 +11954,6 @@ function stripRootPrefix(id, root) {
|
|
|
11923
11954
|
* Serializes output mode and feature flags for runtime consumption.
|
|
11924
11955
|
*/
|
|
11925
11956
|
function generateConfigModule(ctx) {
|
|
11926
|
-
const cookieSecrets = ctx.config.cookies?.secrets ?? (ctx.config.cookies?.secret ? [ctx.config.cookies.secret] : void 0);
|
|
11927
11957
|
const runtimeConfig = {
|
|
11928
11958
|
output: ctx.config.output ?? "server",
|
|
11929
11959
|
csrf: ctx.config.csrf ?? true,
|
|
@@ -11932,10 +11962,11 @@ function generateConfigModule(ctx) {
|
|
|
11932
11962
|
dev: ctx.dev ?? false,
|
|
11933
11963
|
slowPhaseMs: ctx.config.dev?.slowPhaseMs ?? 200,
|
|
11934
11964
|
slowRequestMs: ctx.config.slowRequestMs ?? 3e3,
|
|
11935
|
-
cookieSecrets,
|
|
11936
11965
|
topLoader: ctx.config.topLoader,
|
|
11937
|
-
|
|
11938
|
-
|
|
11966
|
+
debug: ctx.config.debug ?? false,
|
|
11967
|
+
serverTiming: ctx.config.serverTiming,
|
|
11968
|
+
renderTimeoutMs: ctx.config.renderTimeoutMs ?? 3e4,
|
|
11969
|
+
deploymentId: ctx.deploymentId ?? null
|
|
11939
11970
|
};
|
|
11940
11971
|
return [
|
|
11941
11972
|
"// Auto-generated runtime config — do not edit.",
|
|
@@ -12158,7 +12189,8 @@ var CLIENT_REQUIRED_EXTENSIONS = new Set([
|
|
|
12158
12189
|
* that are missing it.
|
|
12159
12190
|
*
|
|
12160
12191
|
* MDX and JSON status files are excluded — MDX files are server components
|
|
12161
|
-
* by design
|
|
12192
|
+
* by design (pre-rendered as elements via fallbackElement, see TIM-503),
|
|
12193
|
+
* and JSON files are data, not components.
|
|
12162
12194
|
*/
|
|
12163
12195
|
function lintStatusFileDirectives(tree) {
|
|
12164
12196
|
const warnings = [];
|
|
@@ -12203,7 +12235,7 @@ var RESOLVED_VIRTUAL_ID$1 = `\0${VIRTUAL_MODULE_ID$1}`;
|
|
|
12203
12235
|
/**
|
|
12204
12236
|
* File convention names we track for changes that require manifest regeneration.
|
|
12205
12237
|
*/
|
|
12206
|
-
var ROUTE_FILE_PATTERNS = /\/(page|layout|middleware|access|route|error|default|denied|
|
|
12238
|
+
var ROUTE_FILE_PATTERNS = /\/(page|layout|middleware|access|route|error|global-error|default|denied|params|\d{3}|[45]xx|not-found|forbidden|unauthorized|sitemap|robots|manifest|favicon|icon|opengraph-image|twitter-image|apple-icon)\./;
|
|
12207
12239
|
/**
|
|
12208
12240
|
* Create the timber-routing Vite plugin.
|
|
12209
12241
|
*
|
|
@@ -12278,14 +12310,40 @@ function timberRouting(ctx) {
|
|
|
12278
12310
|
configureServer(devServer) {
|
|
12279
12311
|
rescan();
|
|
12280
12312
|
devServer.watcher.add(ctx.appDir);
|
|
12281
|
-
|
|
12313
|
+
/** Snapshot of the last generated manifest, used to detect structural changes. */
|
|
12314
|
+
let lastManifest = ctx.routeTree ? generateManifestModule(ctx.routeTree) : "";
|
|
12315
|
+
/**
|
|
12316
|
+
* Handle a route-significant file being added or removed.
|
|
12317
|
+
* Always triggers a full-reload since the route tree structure changed.
|
|
12318
|
+
*/
|
|
12319
|
+
const handleStructuralChange = (filePath) => {
|
|
12282
12320
|
if (!filePath.startsWith(ctx.appDir)) return;
|
|
12283
12321
|
if (!ROUTE_FILE_PATTERNS.test(filePath)) return;
|
|
12284
12322
|
rescan();
|
|
12323
|
+
lastManifest = ctx.routeTree ? generateManifestModule(ctx.routeTree) : "";
|
|
12285
12324
|
invalidateManifest(devServer);
|
|
12286
12325
|
};
|
|
12287
|
-
|
|
12288
|
-
|
|
12326
|
+
/**
|
|
12327
|
+
* Handle a route file's content changing.
|
|
12328
|
+
*
|
|
12329
|
+
* Most content edits (JSX changes, fixing typos) don't affect route
|
|
12330
|
+
* metadata — Vite's React Fast Refresh handles those via normal HMR.
|
|
12331
|
+
* Only rescan and full-reload when route metadata actually changed
|
|
12332
|
+
* (e.g., searchParams export added/removed, metadata export changed).
|
|
12333
|
+
*/
|
|
12334
|
+
const handleContentChange = (filePath) => {
|
|
12335
|
+
if (!filePath.startsWith(ctx.appDir)) return;
|
|
12336
|
+
if (!ROUTE_FILE_PATTERNS.test(filePath)) return;
|
|
12337
|
+
rescan();
|
|
12338
|
+
const newManifest = ctx.routeTree ? generateManifestModule(ctx.routeTree) : "";
|
|
12339
|
+
if (newManifest !== lastManifest) {
|
|
12340
|
+
lastManifest = newManifest;
|
|
12341
|
+
invalidateManifest(devServer);
|
|
12342
|
+
}
|
|
12343
|
+
};
|
|
12344
|
+
devServer.watcher.on("add", handleStructuralChange);
|
|
12345
|
+
devServer.watcher.on("unlink", handleStructuralChange);
|
|
12346
|
+
devServer.watcher.on("change", handleContentChange);
|
|
12289
12347
|
}
|
|
12290
12348
|
};
|
|
12291
12349
|
}
|
|
@@ -12366,9 +12424,9 @@ function generateManifestModule(tree) {
|
|
|
12366
12424
|
const v = addImport(node.denied);
|
|
12367
12425
|
parts.push(`${nextIndent}denied: { load: ${v}, filePath: ${JSON.stringify(node.denied.filePath)} },`);
|
|
12368
12426
|
}
|
|
12369
|
-
if (node.
|
|
12370
|
-
const v = addImport(node.
|
|
12371
|
-
parts.push(`${nextIndent}
|
|
12427
|
+
if (node.params) {
|
|
12428
|
+
const v = addImport(node.params);
|
|
12429
|
+
parts.push(`${nextIndent}params: { load: ${v}, filePath: ${JSON.stringify(node.params.filePath)} },`);
|
|
12372
12430
|
}
|
|
12373
12431
|
if (node.statusFiles && node.statusFiles.size > 0) {
|
|
12374
12432
|
const statusEntries = [];
|
|
@@ -12416,6 +12474,8 @@ function generateManifestModule(tree) {
|
|
|
12416
12474
|
const rootSerialized = serializeNode(tree.root, " ");
|
|
12417
12475
|
let proxyLine = "";
|
|
12418
12476
|
if (tree.proxy) proxyLine = ` proxy: { load: ${addImport(tree.proxy)}, filePath: ${JSON.stringify(tree.proxy.filePath)} },`;
|
|
12477
|
+
let globalErrorLine = "";
|
|
12478
|
+
if (tree.globalError) globalErrorLine = ` globalError: { load: ${addImport(tree.globalError)}, filePath: ${JSON.stringify(tree.globalError.filePath)} },`;
|
|
12419
12479
|
const rewrites = collectInterceptionRewrites(tree.root);
|
|
12420
12480
|
const rewritesLine = rewrites.length > 0 ? ` interceptionRewrites: ${JSON.stringify(rewrites.map((r) => ({
|
|
12421
12481
|
interceptedPattern: r.interceptedPattern,
|
|
@@ -12429,6 +12489,7 @@ function generateManifestModule(tree) {
|
|
|
12429
12489
|
"",
|
|
12430
12490
|
"const manifest = {",
|
|
12431
12491
|
proxyLine,
|
|
12492
|
+
globalErrorLine,
|
|
12432
12493
|
rewritesLine,
|
|
12433
12494
|
` root: ${rootSerialized},`,
|
|
12434
12495
|
"};",
|
|
@@ -12451,6 +12512,23 @@ var SHIMS_DIR = resolve(PKG_ROOT, "src", "shims");
|
|
|
12451
12512
|
var SERVER_ONLY_VIRTUAL = "\0timber:server-only";
|
|
12452
12513
|
var CLIENT_ONLY_VIRTUAL = "\0timber:client-only";
|
|
12453
12514
|
/**
|
|
12515
|
+
* Map from @timber-js/app/<subpath> to relative src/ file paths.
|
|
12516
|
+
*
|
|
12517
|
+
* Used by the catch-all resolveId rule to remap subpath imports to src/
|
|
12518
|
+
* in server environments. When adding a new subpath export to package.json,
|
|
12519
|
+
* add it here too. See TIM-568.
|
|
12520
|
+
*/
|
|
12521
|
+
var SUBPATH_SRC_MAP = {
|
|
12522
|
+
"cache": "cache/index.ts",
|
|
12523
|
+
"content": "content/index.ts",
|
|
12524
|
+
"cookies": "cookies/index.ts",
|
|
12525
|
+
"params": "params/index.ts",
|
|
12526
|
+
"search-params": "search-params/index.ts",
|
|
12527
|
+
"routing": "routing/index.ts",
|
|
12528
|
+
"adapters/cloudflare": "adapters/cloudflare.ts",
|
|
12529
|
+
"adapters/nitro": "adapters/nitro.ts"
|
|
12530
|
+
};
|
|
12531
|
+
/**
|
|
12454
12532
|
* Map from next/* import specifiers to shim file paths.
|
|
12455
12533
|
*
|
|
12456
12534
|
* The shim map is a separate data structure (not embedded in the plugin)
|
|
@@ -12496,6 +12574,13 @@ function timberShims(_ctx) {
|
|
|
12496
12574
|
}
|
|
12497
12575
|
if (cleanId === "@timber-js/app/client") {
|
|
12498
12576
|
if (this.environment?.name === "ssr") return resolve(PKG_ROOT, "src", "client", "index.ts");
|
|
12577
|
+
return null;
|
|
12578
|
+
}
|
|
12579
|
+
if (cleanId.startsWith("@timber-js/app/") && cleanId !== "@timber-js/app/package.json") {
|
|
12580
|
+
if (this.environment?.name !== "client") {
|
|
12581
|
+
const srcPath = SUBPATH_SRC_MAP[cleanId.slice(15)];
|
|
12582
|
+
if (srcPath) return resolve(PKG_ROOT, "src", srcPath);
|
|
12583
|
+
}
|
|
12499
12584
|
}
|
|
12500
12585
|
return null;
|
|
12501
12586
|
},
|
|
@@ -12576,11 +12661,12 @@ function generateFontFaces(descriptors) {
|
|
|
12576
12661
|
* ```css
|
|
12577
12662
|
* .timber-font-inter {
|
|
12578
12663
|
* --font-sans: 'Inter', 'Inter Fallback', system-ui, sans-serif;
|
|
12664
|
+
* font-family: 'Inter', 'Inter Fallback', system-ui, sans-serif;
|
|
12579
12665
|
* }
|
|
12580
12666
|
* ```
|
|
12581
12667
|
*/
|
|
12582
12668
|
function generateVariableClass(className, variable, fontFamily) {
|
|
12583
|
-
return `.${className} {\n ${variable}: ${fontFamily};\n}`;
|
|
12669
|
+
return `.${className} {\n ${variable}: ${fontFamily};\n font-family: ${fontFamily};\n}`;
|
|
12584
12670
|
}
|
|
12585
12671
|
/**
|
|
12586
12672
|
* Generate a scoped CSS class that applies font-family directly.
|
|
@@ -13357,10 +13443,24 @@ async function isCacheHit(metaPath, dataPath) {
|
|
|
13357
13443
|
//#region src/plugins/fonts.ts
|
|
13358
13444
|
var VIRTUAL_GOOGLE = "@timber/fonts/google";
|
|
13359
13445
|
var VIRTUAL_LOCAL = "@timber/fonts/local";
|
|
13360
|
-
var VIRTUAL_FONT_CSS = "virtual:timber-fonts.css";
|
|
13361
13446
|
var RESOLVED_GOOGLE = "\0@timber/fonts/google";
|
|
13362
13447
|
var RESOLVED_LOCAL = "\0@timber/fonts/local";
|
|
13363
|
-
|
|
13448
|
+
/**
|
|
13449
|
+
* Virtual side-effect module that registers font CSS on globalThis.
|
|
13450
|
+
*
|
|
13451
|
+
* When a file calls localFont() or a Google font function, the transform
|
|
13452
|
+
* hook injects `import 'virtual:timber-font-css-register'` into that file.
|
|
13453
|
+
* This virtual module sets `globalThis.__timber_font_css` with the combined
|
|
13454
|
+
* @font-face CSS. The RSC entry reads it at render time to inline a <style> tag.
|
|
13455
|
+
*
|
|
13456
|
+
* This approach avoids timing issues because:
|
|
13457
|
+
* 1. The font file is in the RSC module graph (imported by layout.tsx)
|
|
13458
|
+
* 2. The side-effect import is added to the font file during transform
|
|
13459
|
+
* 3. When layout.tsx is loaded, fonts.ts runs → side-effect module runs → globalThis is set
|
|
13460
|
+
* 4. RSC entry renders → reads globalThis → inlines <style>
|
|
13461
|
+
*/
|
|
13462
|
+
var VIRTUAL_FONT_CSS_REGISTER = "virtual:timber-font-css-register";
|
|
13463
|
+
var RESOLVED_FONT_CSS_REGISTER = "\0virtual:timber-font-css-register";
|
|
13364
13464
|
/**
|
|
13365
13465
|
* Convert a font family name to a PascalCase export name.
|
|
13366
13466
|
* e.g. "JetBrains Mono" → "JetBrains_Mono"
|
|
@@ -13508,6 +13608,24 @@ function generateLocalVirtualModule() {
|
|
|
13508
13608
|
].join("\n");
|
|
13509
13609
|
}
|
|
13510
13610
|
/**
|
|
13611
|
+
* Generate CSS for a single extracted font.
|
|
13612
|
+
*
|
|
13613
|
+
* Includes @font-face rules (for local fonts), fallback @font-face,
|
|
13614
|
+
* and the scoped class rule.
|
|
13615
|
+
*/
|
|
13616
|
+
function generateFontCss(font) {
|
|
13617
|
+
const cssParts = [];
|
|
13618
|
+
if (font.provider === "local" && font.localSources) {
|
|
13619
|
+
const faceCss = generateFontFaces(generateLocalFontFaces(font.family, font.localSources, font.display));
|
|
13620
|
+
if (faceCss) cssParts.push(faceCss);
|
|
13621
|
+
}
|
|
13622
|
+
const fallbackCss = generateFallbackCss(font.family);
|
|
13623
|
+
if (fallbackCss) cssParts.push(fallbackCss);
|
|
13624
|
+
if (font.variable) cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
|
|
13625
|
+
else cssParts.push(generateFontFamilyClass(font.className, font.fontFamily));
|
|
13626
|
+
return cssParts.join("\n\n");
|
|
13627
|
+
}
|
|
13628
|
+
/**
|
|
13511
13629
|
* Generate the CSS output for all extracted fonts.
|
|
13512
13630
|
*
|
|
13513
13631
|
* Includes @font-face rules for local fonts, fallback @font-face rules,
|
|
@@ -13515,16 +13633,7 @@ function generateLocalVirtualModule() {
|
|
|
13515
13633
|
*/
|
|
13516
13634
|
function generateAllFontCss(registry) {
|
|
13517
13635
|
const cssParts = [];
|
|
13518
|
-
for (const font of registry.values())
|
|
13519
|
-
if (font.provider === "local" && font.localSources) {
|
|
13520
|
-
const faceCss = generateFontFaces(generateLocalFontFaces(font.family, font.localSources, font.display));
|
|
13521
|
-
if (faceCss) cssParts.push(faceCss);
|
|
13522
|
-
}
|
|
13523
|
-
const fallbackCss = generateFallbackCss(font.family);
|
|
13524
|
-
if (fallbackCss) cssParts.push(fallbackCss);
|
|
13525
|
-
if (font.variable) cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
|
|
13526
|
-
else cssParts.push(generateFontFamilyClass(font.className, font.fontFamily));
|
|
13527
|
-
}
|
|
13636
|
+
for (const font of registry.values()) cssParts.push(generateFontCss(font));
|
|
13528
13637
|
return cssParts.join("\n\n");
|
|
13529
13638
|
}
|
|
13530
13639
|
/**
|
|
@@ -13578,15 +13687,24 @@ function timberFonts(ctx) {
|
|
|
13578
13687
|
return {
|
|
13579
13688
|
name: "timber-fonts",
|
|
13580
13689
|
resolveId(id) {
|
|
13581
|
-
|
|
13582
|
-
if (
|
|
13583
|
-
|
|
13690
|
+
let cleanId = id.startsWith("\0") ? id.slice(1) : id;
|
|
13691
|
+
if (cleanId.startsWith(ctx.root)) {
|
|
13692
|
+
const stripped = cleanId.slice(ctx.root.length);
|
|
13693
|
+
if (stripped.startsWith("/") || stripped.startsWith("\\")) cleanId = stripped.slice(1);
|
|
13694
|
+
else cleanId = stripped;
|
|
13695
|
+
}
|
|
13696
|
+
if (cleanId === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
|
|
13697
|
+
if (cleanId === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
|
|
13698
|
+
if (cleanId === VIRTUAL_FONT_CSS_REGISTER) return RESOLVED_FONT_CSS_REGISTER;
|
|
13584
13699
|
return null;
|
|
13585
13700
|
},
|
|
13586
13701
|
load(id) {
|
|
13587
13702
|
if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
|
|
13588
13703
|
if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
|
|
13589
|
-
if (id ===
|
|
13704
|
+
if (id === RESOLVED_FONT_CSS_REGISTER) {
|
|
13705
|
+
const css = generateAllFontCss(registry);
|
|
13706
|
+
return `globalThis.__timber_font_css = ${JSON.stringify(css)};`;
|
|
13707
|
+
}
|
|
13590
13708
|
return null;
|
|
13591
13709
|
},
|
|
13592
13710
|
configureServer(server) {
|
|
@@ -13682,7 +13800,7 @@ function timberFonts(ctx) {
|
|
|
13682
13800
|
}
|
|
13683
13801
|
if (hasLocalImport) transformedCode = transformLocalFonts(transformedCode, code, id, registry, this.error.bind(this));
|
|
13684
13802
|
if (transformedCode !== code) {
|
|
13685
|
-
transformedCode = `import '${
|
|
13803
|
+
if (registry.size > 0) transformedCode = `import '${VIRTUAL_FONT_CSS_REGISTER}';\n` + transformedCode;
|
|
13686
13804
|
return {
|
|
13687
13805
|
code: transformedCode,
|
|
13688
13806
|
map: null
|
|
@@ -13713,12 +13831,6 @@ function timberFonts(ctx) {
|
|
|
13713
13831
|
});
|
|
13714
13832
|
}
|
|
13715
13833
|
}
|
|
13716
|
-
const fontCss = generateAllFontCss(registry);
|
|
13717
|
-
if (fontCss) this.emitFile({
|
|
13718
|
-
type: "asset",
|
|
13719
|
-
fileName: "_timber/fonts/fonts.css",
|
|
13720
|
-
source: fontCss
|
|
13721
|
-
});
|
|
13722
13834
|
if (!ctx.buildManifest) return;
|
|
13723
13835
|
const cachedByFamily = /* @__PURE__ */ new Map();
|
|
13724
13836
|
for (const cf of cachedFonts) {
|
|
@@ -13845,16 +13957,14 @@ function validateStaticMode(code, fileId, options) {
|
|
|
13845
13957
|
* - transform: Validates source files for static mode violations
|
|
13846
13958
|
*/
|
|
13847
13959
|
function timberStaticBuild(ctx) {
|
|
13848
|
-
const isStatic = ctx.config.output === "static";
|
|
13849
|
-
const clientJavascriptDisabled = ctx.clientJavascript.disabled;
|
|
13850
13960
|
return {
|
|
13851
13961
|
name: "timber-static-build",
|
|
13852
13962
|
transform(code, id) {
|
|
13853
|
-
if (!
|
|
13963
|
+
if (!(ctx.config.output === "static")) return null;
|
|
13854
13964
|
if (id.includes("node_modules")) return null;
|
|
13855
13965
|
if (!id.includes("/app/") && !id.startsWith("app/")) return null;
|
|
13856
13966
|
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
13857
|
-
const errors = validateStaticMode(code, id, { clientJavascriptDisabled });
|
|
13967
|
+
const errors = validateStaticMode(code, id, { clientJavascriptDisabled: ctx.clientJavascript.disabled });
|
|
13858
13968
|
if (errors.length > 0) {
|
|
13859
13969
|
const messages = errors.map((e) => `[timber] Static mode error in ${e.file}${e.line ? `:${e.line}` : ""}: ${e.message}`);
|
|
13860
13970
|
this.error(messages.join("\n\n"));
|
|
@@ -13864,95 +13974,6 @@ function timberStaticBuild(ctx) {
|
|
|
13864
13974
|
};
|
|
13865
13975
|
}
|
|
13866
13976
|
//#endregion
|
|
13867
|
-
//#region src/plugins/dynamic-transform.ts
|
|
13868
|
-
/**
|
|
13869
|
-
* Quick check: does this source file contain 'use dynamic' anywhere?
|
|
13870
|
-
* Used as a fast bail-out before doing expensive AST parsing.
|
|
13871
|
-
*/
|
|
13872
|
-
function containsUseDynamic(code) {
|
|
13873
|
-
return containsDirective(code, "use dynamic");
|
|
13874
|
-
}
|
|
13875
|
-
/**
|
|
13876
|
-
* Find function declarations/expressions containing 'use dynamic' and
|
|
13877
|
-
* transform them into markDynamic() calls.
|
|
13878
|
-
*
|
|
13879
|
-
* Input:
|
|
13880
|
-
* ```tsx
|
|
13881
|
-
* export default async function AddToCartButton({ productId }) {
|
|
13882
|
-
* 'use dynamic'
|
|
13883
|
-
* const user = await getUser()
|
|
13884
|
-
* return <button>Add to cart</button>
|
|
13885
|
-
* }
|
|
13886
|
-
* ```
|
|
13887
|
-
*
|
|
13888
|
-
* Output:
|
|
13889
|
-
* ```tsx
|
|
13890
|
-
* import { markDynamic as __markDynamic } from '@timber-js/app/runtime';
|
|
13891
|
-
* export default async function AddToCartButton({ productId }) {
|
|
13892
|
-
* __markDynamic();
|
|
13893
|
-
* const user = await getUser()
|
|
13894
|
-
* return <button>Add to cart</button>
|
|
13895
|
-
* }
|
|
13896
|
-
* ```
|
|
13897
|
-
*
|
|
13898
|
-
* The markDynamic() call registers the component boundary as dynamic
|
|
13899
|
-
* at render time. The pre-render pass uses this to know which subtrees
|
|
13900
|
-
* to skip and leave as holes for per-request rendering.
|
|
13901
|
-
*/
|
|
13902
|
-
function transformUseDynamic(code) {
|
|
13903
|
-
if (!containsUseDynamic(code)) return null;
|
|
13904
|
-
const functions = findFunctionsWithDirective(code, "use dynamic");
|
|
13905
|
-
if (functions.length === 0) return null;
|
|
13906
|
-
let result = code;
|
|
13907
|
-
for (const fn of functions) {
|
|
13908
|
-
const cleanBody = fn.bodyContent.replace(/['"]use dynamic['"];?/, "__markDynamic();");
|
|
13909
|
-
result = result.slice(0, fn.bodyStart) + cleanBody + result.slice(fn.bodyEnd);
|
|
13910
|
-
}
|
|
13911
|
-
result = `import { markDynamic as __markDynamic } from '@timber-js/app/runtime';\n` + result;
|
|
13912
|
-
return {
|
|
13913
|
-
code: result,
|
|
13914
|
-
map: null
|
|
13915
|
-
};
|
|
13916
|
-
}
|
|
13917
|
-
/**
|
|
13918
|
-
* In `output: 'static'` mode, `'use dynamic'` is a build error.
|
|
13919
|
-
* Static mode renders everything at build time — there is no per-request
|
|
13920
|
-
* rendering to opt into.
|
|
13921
|
-
*/
|
|
13922
|
-
function validateNoDynamicInStaticMode(code) {
|
|
13923
|
-
if (!containsUseDynamic(code)) return null;
|
|
13924
|
-
const functions = findFunctionsWithDirective(code, "use dynamic");
|
|
13925
|
-
if (functions.length === 0) return null;
|
|
13926
|
-
return {
|
|
13927
|
-
message: "'use dynamic' cannot be used in static mode (output: 'static'). Static mode renders all content at build time — there is no per-request rendering. Remove the directive or switch to output: 'server'.",
|
|
13928
|
-
line: functions[functions.length - 1].directiveLine
|
|
13929
|
-
};
|
|
13930
|
-
}
|
|
13931
|
-
/**
|
|
13932
|
-
* Create the timber-dynamic-transform Vite plugin.
|
|
13933
|
-
*
|
|
13934
|
-
* In server mode: transforms 'use dynamic' into markDynamic() calls.
|
|
13935
|
-
* In static mode: rejects 'use dynamic' as a build error.
|
|
13936
|
-
*/
|
|
13937
|
-
function timberDynamicTransform(ctx) {
|
|
13938
|
-
const isStatic = ctx.config.output === "static";
|
|
13939
|
-
return {
|
|
13940
|
-
name: "timber-dynamic-transform",
|
|
13941
|
-
transform(code, id) {
|
|
13942
|
-
if (id.includes("node_modules")) return null;
|
|
13943
|
-
if (!id.includes("/app/") && !id.startsWith("app/")) return null;
|
|
13944
|
-
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
13945
|
-
if (!containsUseDynamic(code)) return null;
|
|
13946
|
-
if (isStatic) {
|
|
13947
|
-
const error = validateNoDynamicInStaticMode(code);
|
|
13948
|
-
if (error) this.error(`[timber] Static mode error in ${id}${error.line ? `:${error.line}` : ""}: ${error.message}`);
|
|
13949
|
-
return null;
|
|
13950
|
-
}
|
|
13951
|
-
return transformUseDynamic(code);
|
|
13952
|
-
}
|
|
13953
|
-
};
|
|
13954
|
-
}
|
|
13955
|
-
//#endregion
|
|
13956
13977
|
//#region src/plugins/server-action-exports.ts
|
|
13957
13978
|
var jsxParser = Parser.extend((0, import_acorn_jsx.default)());
|
|
13958
13979
|
/**
|
|
@@ -14092,6 +14113,23 @@ function rewriteServerActionExportsFallback(code) {
|
|
|
14092
14113
|
}
|
|
14093
14114
|
//#endregion
|
|
14094
14115
|
//#region src/plugins/build-manifest.ts
|
|
14116
|
+
/**
|
|
14117
|
+
* timber-build-manifest — Vite sub-plugin for build asset manifest generation.
|
|
14118
|
+
*
|
|
14119
|
+
* Provides `virtual:timber-build-manifest` which exports a BuildManifest
|
|
14120
|
+
* mapping route segment file paths to their CSS, JS, and modulepreload
|
|
14121
|
+
* output chunks.
|
|
14122
|
+
*
|
|
14123
|
+
* - Dev mode: exports an empty manifest (Vite HMR handles CSS/JS).
|
|
14124
|
+
* - Build mode: virtual module reads from globalThis.__TIMBER_BUILD_MANIFEST__
|
|
14125
|
+
* at runtime. The actual manifest data is injected by the adapter via a
|
|
14126
|
+
* _timber-manifest-init.js module that runs before the RSC handler.
|
|
14127
|
+
*
|
|
14128
|
+
* The generateBundle hook (client env only) extracts CSS/JS/modulepreload
|
|
14129
|
+
* data from the Rollup bundle and populates ctx.buildManifest.
|
|
14130
|
+
*
|
|
14131
|
+
* Design docs: 18-build-system.md §"Build Manifest", 02-rendering-pipeline.md §"Early Hints"
|
|
14132
|
+
*/
|
|
14095
14133
|
var VIRTUAL_MODULE_ID = "virtual:timber-build-manifest";
|
|
14096
14134
|
var RESOLVED_VIRTUAL_ID = `\0${VIRTUAL_MODULE_ID}`;
|
|
14097
14135
|
/**
|
|
@@ -14167,6 +14205,7 @@ function timberBuildManifest(ctx) {
|
|
|
14167
14205
|
configResolved(config) {
|
|
14168
14206
|
resolvedBase = config.base;
|
|
14169
14207
|
isDev = config.command === "serve";
|
|
14208
|
+
if (!isDev && !ctx.deploymentId) ctx.deploymentId = randomUUID().replace(/-/g, "").slice(0, 16);
|
|
14170
14209
|
},
|
|
14171
14210
|
resolveId(id) {
|
|
14172
14211
|
const cleanId = id.startsWith("\0") ? id.slice(1) : id;
|
|
@@ -14372,6 +14411,179 @@ function timberDevLogs(_ctx) {
|
|
|
14372
14411
|
};
|
|
14373
14412
|
}
|
|
14374
14413
|
//#endregion
|
|
14414
|
+
//#region src/plugins/dev-browser-logs.ts
|
|
14415
|
+
/** Max message size in bytes before truncation. */
|
|
14416
|
+
var MAX_MESSAGE_BYTES = 2048;
|
|
14417
|
+
/** HMR event name for browser→server log forwarding. */
|
|
14418
|
+
var HMR_EVENT = "timber:browser-log";
|
|
14419
|
+
/** ANSI color codes for terminal output. */
|
|
14420
|
+
var COLORS = {
|
|
14421
|
+
red: "\x1B[31m",
|
|
14422
|
+
yellow: "\x1B[33m",
|
|
14423
|
+
blue: "\x1B[34m",
|
|
14424
|
+
dim: "\x1B[2m",
|
|
14425
|
+
reset: "\x1B[0m"
|
|
14426
|
+
};
|
|
14427
|
+
/** Level severity ordering for threshold comparison. */
|
|
14428
|
+
var LEVEL_SEVERITY = {
|
|
14429
|
+
none: 0,
|
|
14430
|
+
info: 1,
|
|
14431
|
+
warn: 2,
|
|
14432
|
+
error: 3
|
|
14433
|
+
};
|
|
14434
|
+
/**
|
|
14435
|
+
* Format a browser log payload for server terminal output.
|
|
14436
|
+
*
|
|
14437
|
+
* Produces color-coded output like:
|
|
14438
|
+
* [browser:error] Uncaught TypeError: x is not a function
|
|
14439
|
+
* at App (app.tsx:10:5)
|
|
14440
|
+
* [browser:warn] Deprecation warning (app/page.tsx:42:12)
|
|
14441
|
+
*/
|
|
14442
|
+
function formatBrowserLog(payload) {
|
|
14443
|
+
const { level, message, stack, source } = payload;
|
|
14444
|
+
let output = `${`${level === "error" ? COLORS.red : level === "warn" ? COLORS.yellow : COLORS.blue}[browser:${level}]${COLORS.reset}`} ${message}${source ? ` ${COLORS.dim}(${source})${COLORS.reset}` : ""}`;
|
|
14445
|
+
if (stack) {
|
|
14446
|
+
const indented = stack.split("\n").map((line) => ` ${COLORS.dim}${line}${COLORS.reset}`).join("\n");
|
|
14447
|
+
output += `\n${indented}`;
|
|
14448
|
+
}
|
|
14449
|
+
return output;
|
|
14450
|
+
}
|
|
14451
|
+
/**
|
|
14452
|
+
* Check if a log at `level` should be forwarded given the configured threshold.
|
|
14453
|
+
*
|
|
14454
|
+
* The threshold acts as a minimum severity:
|
|
14455
|
+
* - 'error' → only errors
|
|
14456
|
+
* - 'warn' → errors + warnings
|
|
14457
|
+
* - 'info' → errors + warnings + info
|
|
14458
|
+
* - 'none' → nothing
|
|
14459
|
+
*/
|
|
14460
|
+
function shouldForwardLevel(level, threshold) {
|
|
14461
|
+
if (threshold === "none") return false;
|
|
14462
|
+
return LEVEL_SEVERITY[level] >= LEVEL_SEVERITY[threshold];
|
|
14463
|
+
}
|
|
14464
|
+
/**
|
|
14465
|
+
* Truncate a message to `maxBytes` to avoid flooding the terminal.
|
|
14466
|
+
* Appends a suffix indicating how many bytes were dropped.
|
|
14467
|
+
*/
|
|
14468
|
+
function truncateMessage(message, maxBytes) {
|
|
14469
|
+
if (message.length <= maxBytes) return message;
|
|
14470
|
+
return `${message.slice(0, maxBytes)}… [truncated ${message.length - maxBytes} bytes]`;
|
|
14471
|
+
}
|
|
14472
|
+
/**
|
|
14473
|
+
* Generate the inline script injected into the browser in dev mode.
|
|
14474
|
+
*
|
|
14475
|
+
* This script:
|
|
14476
|
+
* 1. Saves references to the original console methods
|
|
14477
|
+
* 2. Wraps `console.error`, `console.warn`, `console.info`
|
|
14478
|
+
* 3. Calls the original first (browser devtools still work)
|
|
14479
|
+
* 4. Serializes and forwards via `import.meta.hot.send()`
|
|
14480
|
+
* 5. Truncates messages to MAX_MESSAGE_BYTES
|
|
14481
|
+
*
|
|
14482
|
+
* The script is minimal and self-contained — no imports, no dependencies.
|
|
14483
|
+
*/
|
|
14484
|
+
function generateClientScript(threshold) {
|
|
14485
|
+
if (threshold === "none") return "";
|
|
14486
|
+
const levels = [
|
|
14487
|
+
"error",
|
|
14488
|
+
"warn",
|
|
14489
|
+
"info"
|
|
14490
|
+
].filter((l) => shouldForwardLevel(l, threshold));
|
|
14491
|
+
if (levels.length === 0) return "";
|
|
14492
|
+
return `
|
|
14493
|
+
(function() {
|
|
14494
|
+
if (!import.meta.hot) return;
|
|
14495
|
+
var MAX_BYTES = ${MAX_MESSAGE_BYTES};
|
|
14496
|
+
var levels = ${JSON.stringify(levels)};
|
|
14497
|
+
var originals = {};
|
|
14498
|
+
|
|
14499
|
+
function serialize(arg) {
|
|
14500
|
+
if (arg === null) return 'null';
|
|
14501
|
+
if (arg === undefined) return 'undefined';
|
|
14502
|
+
if (arg instanceof Error) return arg.stack || arg.message || String(arg);
|
|
14503
|
+
if (typeof arg === 'object') {
|
|
14504
|
+
try { return JSON.stringify(arg); } catch(e) { return String(arg); }
|
|
14505
|
+
}
|
|
14506
|
+
return String(arg);
|
|
14507
|
+
}
|
|
14508
|
+
|
|
14509
|
+
function truncate(s) {
|
|
14510
|
+
if (s.length <= MAX_BYTES) return s;
|
|
14511
|
+
return s.slice(0, MAX_BYTES) + '... [truncated ' + (s.length - MAX_BYTES) + ' bytes]';
|
|
14512
|
+
}
|
|
14513
|
+
|
|
14514
|
+
levels.forEach(function(level) {
|
|
14515
|
+
originals[level] = console[level];
|
|
14516
|
+
console[level] = function() {
|
|
14517
|
+
originals[level].apply(console, arguments);
|
|
14518
|
+
try {
|
|
14519
|
+
var args = Array.prototype.slice.call(arguments);
|
|
14520
|
+
var firstArg = args[0];
|
|
14521
|
+
var stack = null;
|
|
14522
|
+
var source = null;
|
|
14523
|
+
|
|
14524
|
+
if (firstArg instanceof Error) {
|
|
14525
|
+
stack = firstArg.stack || null;
|
|
14526
|
+
source = null;
|
|
14527
|
+
}
|
|
14528
|
+
|
|
14529
|
+
var message = args.map(serialize).join(' ');
|
|
14530
|
+
message = truncate(message);
|
|
14531
|
+
|
|
14532
|
+
import.meta.hot.send('${HMR_EVENT}', {
|
|
14533
|
+
level: level,
|
|
14534
|
+
message: message,
|
|
14535
|
+
stack: stack,
|
|
14536
|
+
source: source,
|
|
14537
|
+
timestamp: Date.now()
|
|
14538
|
+
});
|
|
14539
|
+
} catch(e) {
|
|
14540
|
+
// Never let log forwarding break the page
|
|
14541
|
+
}
|
|
14542
|
+
};
|
|
14543
|
+
});
|
|
14544
|
+
})();
|
|
14545
|
+
`.trim();
|
|
14546
|
+
}
|
|
14547
|
+
/**
|
|
14548
|
+
* Create the timber-dev-browser-logs Vite plugin.
|
|
14549
|
+
*
|
|
14550
|
+
* - `configureServer`: Listens for HMR messages and prints them to the terminal
|
|
14551
|
+
* - `transformIndexHtml`: Injects the client-side interception script
|
|
14552
|
+
*
|
|
14553
|
+
* Only active during `vite dev` (apply: 'serve').
|
|
14554
|
+
*/
|
|
14555
|
+
function timberDevBrowserLogs(ctx) {
|
|
14556
|
+
return {
|
|
14557
|
+
name: "timber-dev-browser-logs",
|
|
14558
|
+
apply: "serve",
|
|
14559
|
+
configureServer(server) {
|
|
14560
|
+
const threshold = ctx.config.devBrowserLogs ?? "warn";
|
|
14561
|
+
if (threshold === "none") return;
|
|
14562
|
+
const script = generateClientScript(threshold);
|
|
14563
|
+
if (script) globalThis.__timber_dev_browser_log_script = `<script type="module">${script}<\/script>`;
|
|
14564
|
+
server.hot.on(HMR_EVENT, (payload) => {
|
|
14565
|
+
try {
|
|
14566
|
+
if (!shouldForwardLevel(payload.level, threshold)) return;
|
|
14567
|
+
payload.message = truncateMessage(payload.message, MAX_MESSAGE_BYTES);
|
|
14568
|
+
const formatted = formatBrowserLog(payload);
|
|
14569
|
+
if (payload.level === "error") process.stderr.write(formatted + "\n");
|
|
14570
|
+
else process.stdout.write(formatted + "\n");
|
|
14571
|
+
} catch {}
|
|
14572
|
+
});
|
|
14573
|
+
},
|
|
14574
|
+
transformIndexHtml() {
|
|
14575
|
+
const script = generateClientScript(ctx.config.devBrowserLogs ?? "warn");
|
|
14576
|
+
if (!script) return [];
|
|
14577
|
+
return [{
|
|
14578
|
+
tag: "script",
|
|
14579
|
+
attrs: { type: "module" },
|
|
14580
|
+
children: script,
|
|
14581
|
+
injectTo: "head"
|
|
14582
|
+
}];
|
|
14583
|
+
}
|
|
14584
|
+
};
|
|
14585
|
+
}
|
|
14586
|
+
//#endregion
|
|
14375
14587
|
//#region src/plugins/react-prod.ts
|
|
14376
14588
|
/**
|
|
14377
14589
|
* Redirect React's CJS development bundles to production bundles.
|
|
@@ -14437,55 +14649,115 @@ function timberChunks() {
|
|
|
14437
14649
|
return { name: "timber-chunks" };
|
|
14438
14650
|
}
|
|
14439
14651
|
//#endregion
|
|
14652
|
+
//#region src/plugins/client-chunks.ts
|
|
14653
|
+
/**
|
|
14654
|
+
* Client chunk grouping strategy for @vitejs/plugin-rsc.
|
|
14655
|
+
*
|
|
14656
|
+
* Groups client reference modules by layout boundary to balance route-scoped
|
|
14657
|
+
* code splitting with HTTP request count. A constant group name would collapse
|
|
14658
|
+
* all routes into one chunk (every page downloads every client component).
|
|
14659
|
+
* Per-serverChunk grouping creates many sub-500B files. Layout-boundary
|
|
14660
|
+
* grouping is the middle ground.
|
|
14661
|
+
*
|
|
14662
|
+
* See design/27-chunking-strategy.md, TIM-440, TIM-499.
|
|
14663
|
+
*/
|
|
14664
|
+
/**
|
|
14665
|
+
* Derive a chunk group name for a client reference module.
|
|
14666
|
+
*
|
|
14667
|
+
* Groups by the first non-group route segment under appDir so that all
|
|
14668
|
+
* client components belonging to the same layout boundary land in one
|
|
14669
|
+
* chunk. For example:
|
|
14670
|
+
* - `facade:app/dashboard/settings/page.tsx` → `"client-dashboard"`
|
|
14671
|
+
* - `facade:app/(group-a)/group-page-a/page.tsx` → `"client-group-page-a"`
|
|
14672
|
+
* - `facade:app/layout.tsx` (root layout) → `"client-shared"`
|
|
14673
|
+
* - `shared:...` (shared across chunks) → `"client-shared"`
|
|
14674
|
+
*
|
|
14675
|
+
* This balances route-scoped code splitting with HTTP request count:
|
|
14676
|
+
* fewer chunks than per-serverChunk, but still avoids downloading every
|
|
14677
|
+
* client component on every page.
|
|
14678
|
+
*/
|
|
14679
|
+
function clientChunkGroup(meta, appDir) {
|
|
14680
|
+
const { normalizedId, serverChunk } = meta;
|
|
14681
|
+
if (serverChunk.startsWith("shared:")) return "client-shared";
|
|
14682
|
+
const relPath = normalizedId.replace(/\\/g, "/");
|
|
14683
|
+
const appDirName = appDir.replace(/\\/g, "/").split("/").pop() || "app";
|
|
14684
|
+
const appIdx = relPath.indexOf(appDirName + "/");
|
|
14685
|
+
if (appIdx === -1) return "client-shared";
|
|
14686
|
+
const segments = relPath.slice(appIdx + appDirName.length + 1).split("/");
|
|
14687
|
+
for (const seg of segments) {
|
|
14688
|
+
if (seg.includes(".")) break;
|
|
14689
|
+
if (seg.startsWith("(") && seg.endsWith(")")) continue;
|
|
14690
|
+
return `client-${seg}`;
|
|
14691
|
+
}
|
|
14692
|
+
return "client-shared";
|
|
14693
|
+
}
|
|
14694
|
+
//#endregion
|
|
14440
14695
|
//#region src/plugins/server-bundle.ts
|
|
14441
14696
|
function timberServerBundle() {
|
|
14442
|
-
return [
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
14463
|
-
|
|
14697
|
+
return [
|
|
14698
|
+
{
|
|
14699
|
+
name: "timber-server-bundle",
|
|
14700
|
+
config(_cfg, { command }) {
|
|
14701
|
+
if (command === "serve") return { environments: {
|
|
14702
|
+
rsc: { resolve: { noExternal: ["server-only", "client-only"] } },
|
|
14703
|
+
ssr: { resolve: { noExternal: [
|
|
14704
|
+
"server-only",
|
|
14705
|
+
"client-only",
|
|
14706
|
+
"nuqs"
|
|
14707
|
+
] } }
|
|
14708
|
+
} };
|
|
14709
|
+
const serverDefine = { "process.env.NODE_ENV": JSON.stringify("production") };
|
|
14710
|
+
return {
|
|
14711
|
+
ssr: { target: "webworker" },
|
|
14712
|
+
environments: {
|
|
14713
|
+
rsc: {
|
|
14714
|
+
resolve: { noExternal: true },
|
|
14715
|
+
define: serverDefine
|
|
14716
|
+
},
|
|
14717
|
+
ssr: {
|
|
14718
|
+
resolve: { noExternal: true },
|
|
14719
|
+
define: serverDefine
|
|
14720
|
+
}
|
|
14464
14721
|
}
|
|
14465
|
-
}
|
|
14466
|
-
}
|
|
14467
|
-
}
|
|
14468
|
-
}, {
|
|
14469
|
-
name: "timber-esm-init-fix",
|
|
14470
|
-
applyToEnvironment(environment) {
|
|
14471
|
-
return environment.name === "rsc" || environment.name === "ssr";
|
|
14722
|
+
};
|
|
14723
|
+
}
|
|
14472
14724
|
},
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
"
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14483
|
-
|
|
14484
|
-
|
|
14485
|
-
|
|
14486
|
-
|
|
14725
|
+
{
|
|
14726
|
+
name: "timber-esm-init-fix",
|
|
14727
|
+
applyToEnvironment(environment) {
|
|
14728
|
+
return environment.name === "rsc" || environment.name === "ssr";
|
|
14729
|
+
},
|
|
14730
|
+
renderChunk(code) {
|
|
14731
|
+
const lazy = "var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);";
|
|
14732
|
+
if (!code.includes(lazy)) return null;
|
|
14733
|
+
const eager = [
|
|
14734
|
+
"var __esmMin = (fn, res) => {",
|
|
14735
|
+
" var l = () => { if (fn) { var f = fn; try { res = f(); fn = 0; } catch(e) {} } return res; };",
|
|
14736
|
+
" l();",
|
|
14737
|
+
" return l;",
|
|
14738
|
+
"};"
|
|
14739
|
+
].join(" ");
|
|
14740
|
+
return {
|
|
14741
|
+
code: code.replace(lazy, eager),
|
|
14742
|
+
map: null
|
|
14743
|
+
};
|
|
14744
|
+
}
|
|
14745
|
+
},
|
|
14746
|
+
{
|
|
14747
|
+
name: "timber-create-require-fix",
|
|
14748
|
+
applyToEnvironment(environment) {
|
|
14749
|
+
return environment.name === "rsc" || environment.name === "ssr";
|
|
14750
|
+
},
|
|
14751
|
+
renderChunk(code) {
|
|
14752
|
+
const pattern = "createRequire(import.meta.url)";
|
|
14753
|
+
if (!code.includes(pattern)) return null;
|
|
14754
|
+
return {
|
|
14755
|
+
code: code.replace(pattern, "createRequire(import.meta.url || \"file:///app\")"),
|
|
14756
|
+
map: null
|
|
14757
|
+
};
|
|
14758
|
+
}
|
|
14487
14759
|
}
|
|
14488
|
-
|
|
14760
|
+
];
|
|
14489
14761
|
}
|
|
14490
14762
|
//#endregion
|
|
14491
14763
|
//#region src/plugins/adapter-build.ts
|
|
@@ -14507,6 +14779,7 @@ function timberAdapterBuild(ctx) {
|
|
|
14507
14779
|
modulepreload: {}
|
|
14508
14780
|
} : ctx.buildManifest;
|
|
14509
14781
|
manifestInit = `globalThis.__TIMBER_BUILD_MANIFEST__ = ${JSON.stringify(manifest)};\n`;
|
|
14782
|
+
if (ctx.deploymentId) manifestInit += `globalThis.__TIMBER_DEPLOYMENT_ID__ = ${JSON.stringify(ctx.deploymentId)};\n`;
|
|
14510
14783
|
}
|
|
14511
14784
|
if (ctx.clientJavascript.disabled) await stripJsFromRscAssetsManifests(buildDir);
|
|
14512
14785
|
const adapterConfig = {
|
|
@@ -14863,6 +15136,65 @@ function createNoopTimer() {
|
|
|
14863
15136
|
};
|
|
14864
15137
|
}
|
|
14865
15138
|
//#endregion
|
|
15139
|
+
//#region src/server/action-encryption.ts
|
|
15140
|
+
/**
|
|
15141
|
+
* Regex for safe `defineEncryptionKey` expressions.
|
|
15142
|
+
*
|
|
15143
|
+
* The RSC plugin inlines this expression verbatim into generated JavaScript.
|
|
15144
|
+
* We restrict it to `process.env.<UPPER_SNAKE_CASE>` to prevent code injection.
|
|
15145
|
+
* See "Known Security Considerations" at the top of this file.
|
|
15146
|
+
*/
|
|
15147
|
+
var SAFE_KEY_EXPR = /^process\.env\.[A-Z_][A-Z0-9_]*$/;
|
|
15148
|
+
/**
|
|
15149
|
+
* Build the `defineEncryptionKey` expression for the RSC plugin.
|
|
15150
|
+
*
|
|
15151
|
+
* The RSC plugin accepts a JavaScript expression string that will be
|
|
15152
|
+
* inlined into the encryption runtime module. At runtime, this expression
|
|
15153
|
+
* must evaluate to the base64-encoded encryption key.
|
|
15154
|
+
*
|
|
15155
|
+
* Priority:
|
|
15156
|
+
* 1. `TIMBER_ACTIONS_ENCRYPTION_KEY` env var (for cross-build key sharing
|
|
15157
|
+
* in rolling/blue-green deployments)
|
|
15158
|
+
* 2. Auto-generated at build time (RSC plugin default — embedded in bundle,
|
|
15159
|
+
* consistent across all instances of the same build)
|
|
15160
|
+
*
|
|
15161
|
+
* For env var keys, we generate a runtime expression that reads the env var.
|
|
15162
|
+
* For auto-generated keys, we return undefined and let the RSC plugin handle it.
|
|
15163
|
+
*/
|
|
15164
|
+
function resolveEncryptionKeyExpression() {
|
|
15165
|
+
const envKey = process.env.TIMBER_ACTIONS_ENCRYPTION_KEY;
|
|
15166
|
+
if (envKey) {
|
|
15167
|
+
validateKeyFormat(envKey);
|
|
15168
|
+
const expr = "process.env.TIMBER_ACTIONS_ENCRYPTION_KEY";
|
|
15169
|
+
if (!SAFE_KEY_EXPR.test(expr)) throw new Error(`Unsafe encryption key expression: ${expr}`);
|
|
15170
|
+
return expr;
|
|
15171
|
+
}
|
|
15172
|
+
}
|
|
15173
|
+
/**
|
|
15174
|
+
* Determine whether action encryption should be enabled.
|
|
15175
|
+
*
|
|
15176
|
+
* Encryption is always enabled in production. In dev mode, it's enabled
|
|
15177
|
+
* by default but can be disabled via config for debugging.
|
|
15178
|
+
*/
|
|
15179
|
+
function shouldEnableEncryption(isDev, config) {
|
|
15180
|
+
if (!isDev) return true;
|
|
15181
|
+
if (config?.disableInDev) return false;
|
|
15182
|
+
return true;
|
|
15183
|
+
}
|
|
15184
|
+
/**
|
|
15185
|
+
* Validate that a key string is a valid base64-encoded 256-bit key.
|
|
15186
|
+
* Throws a descriptive error if the key is malformed.
|
|
15187
|
+
*/
|
|
15188
|
+
function validateKeyFormat(key) {
|
|
15189
|
+
try {
|
|
15190
|
+
const bytes = atob(key).length;
|
|
15191
|
+
if (bytes !== 32) throw new Error(`TIMBER_ACTIONS_ENCRYPTION_KEY must be a base64-encoded 256-bit (32-byte) key. Got ${bytes} bytes. Generate one with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"`);
|
|
15192
|
+
} catch (error) {
|
|
15193
|
+
if (error instanceof Error && error.message.includes("TIMBER_ACTIONS_ENCRYPTION_KEY")) throw error;
|
|
15194
|
+
throw new Error("TIMBER_ACTIONS_ENCRYPTION_KEY is not valid base64. Generate a key with: node -e \"console.log(require('crypto').randomBytes(32).toString('base64'))\"");
|
|
15195
|
+
}
|
|
15196
|
+
}
|
|
15197
|
+
//#endregion
|
|
14866
15198
|
//#region src/index.ts
|
|
14867
15199
|
/**
|
|
14868
15200
|
* Resolve `clientJavascript` into a fully resolved config.
|
|
@@ -14905,10 +15237,7 @@ function resolveAppDir(root, configAppDir) {
|
|
|
14905
15237
|
}
|
|
14906
15238
|
function createPluginContext(config, root) {
|
|
14907
15239
|
const projectRoot = root ?? process.cwd();
|
|
14908
|
-
const resolvedConfig = {
|
|
14909
|
-
output: "server",
|
|
14910
|
-
...config
|
|
14911
|
-
};
|
|
15240
|
+
const resolvedConfig = { ...config };
|
|
14912
15241
|
return {
|
|
14913
15242
|
config: resolvedConfig,
|
|
14914
15243
|
clientJavascript: resolveClientJavascript(resolvedConfig),
|
|
@@ -14917,22 +15246,28 @@ function createPluginContext(config, root) {
|
|
|
14917
15246
|
root: projectRoot,
|
|
14918
15247
|
dev: false,
|
|
14919
15248
|
buildManifest: null,
|
|
15249
|
+
deploymentId: null,
|
|
14920
15250
|
timer: createStartupTimer()
|
|
14921
15251
|
};
|
|
14922
15252
|
}
|
|
14923
15253
|
/**
|
|
14924
15254
|
* Load timber.config.ts (or .js, .mjs) from the project root.
|
|
14925
15255
|
* Returns the config object or null if no config file is found.
|
|
15256
|
+
*
|
|
15257
|
+
* Uses require() which works for ESM modules on Node 22.12+.
|
|
15258
|
+
* This keeps timber() synchronous — no async config loading needed.
|
|
14926
15259
|
*/
|
|
14927
|
-
|
|
14928
|
-
|
|
15260
|
+
function loadTimberConfigFile(root) {
|
|
15261
|
+
const configNames = [
|
|
14929
15262
|
"timber.config.ts",
|
|
14930
15263
|
"timber.config.js",
|
|
14931
15264
|
"timber.config.mjs"
|
|
14932
|
-
]
|
|
15265
|
+
];
|
|
15266
|
+
const req = createRequire(join(root, "package.json"));
|
|
15267
|
+
for (const name of configNames) {
|
|
14933
15268
|
const configPath = join(root, name);
|
|
14934
15269
|
if (existsSync(configPath)) {
|
|
14935
|
-
const mod =
|
|
15270
|
+
const mod = req(configPath);
|
|
14936
15271
|
return mod.default ?? mod;
|
|
14937
15272
|
}
|
|
14938
15273
|
}
|
|
@@ -14947,10 +15282,7 @@ async function loadTimberConfigFile(root) {
|
|
|
14947
15282
|
*/
|
|
14948
15283
|
function warnConfigConflicts(inline, fileConfig) {
|
|
14949
15284
|
const conflicts = [];
|
|
14950
|
-
for (const key of Object.keys(fileConfig))
|
|
14951
|
-
if (key === "output") continue;
|
|
14952
|
-
if (key in inline && inline[key] !== void 0) conflicts.push(key);
|
|
14953
|
-
}
|
|
15285
|
+
for (const key of Object.keys(fileConfig)) if (key in inline && inline[key] !== void 0) conflicts.push(key);
|
|
14954
15286
|
if (conflicts.length > 0) console.warn(`[timber] Config conflict: ${conflicts.map((k) => `"${k}"`).join(", ")} set in both vite.config.ts (inline) and timber.config.ts. Move all config to timber.config.ts to avoid confusion. The inline value from vite.config.ts will be used.`);
|
|
14955
15287
|
return conflicts;
|
|
14956
15288
|
}
|
|
@@ -14978,21 +15310,92 @@ function mergeFileConfig(ctx, fileConfig) {
|
|
|
14978
15310
|
} } : {}
|
|
14979
15311
|
};
|
|
14980
15312
|
}
|
|
15313
|
+
/**
|
|
15314
|
+
* Resolve the React Compiler plugin via @rolldown/plugin-babel.
|
|
15315
|
+
*
|
|
15316
|
+
* Uses the `reactCompilerPreset` from @vitejs/plugin-react, which:
|
|
15317
|
+
* - Uses Babel ONLY for the compiler pass (OXC handles JSX)
|
|
15318
|
+
* - Automatically scopes to client environment via applyToEnvironmentHook
|
|
15319
|
+
* - Uses react/compiler-runtime built into React 19
|
|
15320
|
+
*
|
|
15321
|
+
* @rolldown/plugin-babel and babel-plugin-react-compiler are optional peer deps.
|
|
15322
|
+
* If either is missing, require() fails with a clear error message.
|
|
15323
|
+
*/
|
|
15324
|
+
function resolveReactCompilerPlugin(config, req) {
|
|
15325
|
+
let babel;
|
|
15326
|
+
try {
|
|
15327
|
+
babel = req("@rolldown/plugin-babel");
|
|
15328
|
+
} catch {
|
|
15329
|
+
throw new Error("[timber] reactCompiler requires @rolldown/plugin-babel. Install it: pnpm add -D @rolldown/plugin-babel babel-plugin-react-compiler");
|
|
15330
|
+
}
|
|
15331
|
+
const options = typeof config === "object" ? config : {};
|
|
15332
|
+
return (babel.default ?? babel)({ presets: [reactCompilerPreset(options)] });
|
|
15333
|
+
}
|
|
15334
|
+
/**
|
|
15335
|
+
* Build the options object for @vitejs/plugin-rsc.
|
|
15336
|
+
*
|
|
15337
|
+
* Uses a getter for `enableActionEncryption` so the RSC plugin reads
|
|
15338
|
+
* the value lazily — after ctx.dev is set in configResolved. This lets
|
|
15339
|
+
* `actionEncryption.disableInDev` work correctly even though the RSC
|
|
15340
|
+
* plugin is created before Vite resolves the command.
|
|
15341
|
+
*/
|
|
15342
|
+
function createRscOptions(ctx, encryptionKeyExpr) {
|
|
15343
|
+
const options = {
|
|
15344
|
+
serverHandler: false,
|
|
15345
|
+
customClientEntry: true,
|
|
15346
|
+
entries: {
|
|
15347
|
+
rsc: "virtual:timber-rsc-entry",
|
|
15348
|
+
ssr: "virtual:timber-ssr-entry",
|
|
15349
|
+
client: "virtual:timber-browser-entry"
|
|
15350
|
+
},
|
|
15351
|
+
clientChunks: (meta) => clientChunkGroup(meta, ctx.appDir)
|
|
15352
|
+
};
|
|
15353
|
+
Object.defineProperty(options, "enableActionEncryption", {
|
|
15354
|
+
get() {
|
|
15355
|
+
return shouldEnableEncryption(ctx.dev, ctx.config.actionEncryption);
|
|
15356
|
+
},
|
|
15357
|
+
enumerable: true
|
|
15358
|
+
});
|
|
15359
|
+
if (encryptionKeyExpr) options.defineEncryptionKey = encryptionKeyExpr;
|
|
15360
|
+
return options;
|
|
15361
|
+
}
|
|
14981
15362
|
function timberCache(_ctx) {
|
|
14982
15363
|
return cacheTransformPlugin();
|
|
14983
15364
|
}
|
|
15365
|
+
/**
|
|
15366
|
+
* Create the timber Vite plugin array.
|
|
15367
|
+
*
|
|
15368
|
+
* Loads timber.config.ts and all dependencies synchronously before
|
|
15369
|
+
* constructing the plugin array. This ensures ALL plugins — including
|
|
15370
|
+
* the RSC plugin and React Compiler — see the fully merged config
|
|
15371
|
+
* (inline + file-based). No async, no deferred config, no stale reads.
|
|
15372
|
+
*
|
|
15373
|
+
* Requires Node >= 22.12 for synchronous require() of ESM modules
|
|
15374
|
+
* (@vitejs/plugin-rsc is ESM-only).
|
|
15375
|
+
*
|
|
15376
|
+
* Previous versions used async loading and deferred config merging,
|
|
15377
|
+
* causing file-based config for reactCompiler, actionEncryption, and
|
|
15378
|
+
* output mode to be silently ignored. See TIM-451.
|
|
15379
|
+
*/
|
|
14984
15380
|
function timber(config) {
|
|
14985
15381
|
const ctx = createPluginContext(config);
|
|
15382
|
+
const consumerRequire = createRequire(join(process.cwd(), "package.json"));
|
|
15383
|
+
ctx.timer.start("rsc-plugin-import");
|
|
15384
|
+
const rscMod = consumerRequire("@vitejs/plugin-rsc");
|
|
15385
|
+
const vitePluginRsc = rscMod.default ?? rscMod;
|
|
15386
|
+
ctx.timer.end("rsc-plugin-import");
|
|
15387
|
+
const encryptionKeyExpr = resolveEncryptionKeyExpression();
|
|
14986
15388
|
const rootSync = {
|
|
14987
15389
|
name: "timber-root-sync",
|
|
14988
|
-
|
|
14989
|
-
const
|
|
15390
|
+
config(userConfig, { command }) {
|
|
15391
|
+
const viteRoot = resolve(userConfig.root ?? process.cwd());
|
|
14990
15392
|
ctx.timer.start("config-load");
|
|
14991
|
-
const fileConfig =
|
|
15393
|
+
const fileConfig = loadTimberConfigFile(viteRoot);
|
|
14992
15394
|
if (fileConfig) {
|
|
14993
15395
|
mergeFileConfig(ctx, fileConfig);
|
|
14994
15396
|
ctx.clientJavascript = resolveClientJavascript(ctx.config);
|
|
14995
15397
|
}
|
|
15398
|
+
ctx.config.output ??= "server";
|
|
14996
15399
|
ctx.timer.end("config-load");
|
|
14997
15400
|
if (command === "build") return { oxc: { jsx: { development: false } } };
|
|
14998
15401
|
},
|
|
@@ -15004,33 +15407,31 @@ function timber(config) {
|
|
|
15004
15407
|
else ctx.timer.start("dev-server-setup");
|
|
15005
15408
|
}
|
|
15006
15409
|
};
|
|
15007
|
-
const
|
|
15008
|
-
|
|
15009
|
-
const
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
}
|
|
15019
|
-
});
|
|
15020
|
-
});
|
|
15410
|
+
const reactCompilerPlugins = [];
|
|
15411
|
+
if (config?.reactCompiler) reactCompilerPlugins.push(resolveReactCompilerPlugin(config.reactCompiler, consumerRequire));
|
|
15412
|
+
const lazyReactCompiler = {
|
|
15413
|
+
name: "timber-react-compiler",
|
|
15414
|
+
configResolved() {
|
|
15415
|
+
if (config?.reactCompiler || !ctx.config.reactCompiler) return;
|
|
15416
|
+
const resolved = resolveReactCompilerPlugin(ctx.config.reactCompiler, consumerRequire);
|
|
15417
|
+
for (const key of Object.keys(resolved)) if (key !== "name") lazyReactCompiler[key] = resolved[key];
|
|
15418
|
+
}
|
|
15419
|
+
};
|
|
15420
|
+
// @vitejs/plugin-rsc handles:
|
|
15021
15421
|
return [
|
|
15022
15422
|
rootSync,
|
|
15023
15423
|
timberReactProd(),
|
|
15024
15424
|
react(),
|
|
15425
|
+
...reactCompilerPlugins,
|
|
15426
|
+
lazyReactCompiler,
|
|
15025
15427
|
timberServerActionExports(),
|
|
15026
|
-
|
|
15428
|
+
vitePluginRsc(createRscOptions(ctx, encryptionKeyExpr)),
|
|
15027
15429
|
timberShims(ctx),
|
|
15028
15430
|
timberRouting(ctx),
|
|
15029
15431
|
timberEntries(ctx),
|
|
15030
15432
|
timberBuildManifest(ctx),
|
|
15031
15433
|
timberCache(ctx),
|
|
15032
15434
|
timberStaticBuild(ctx),
|
|
15033
|
-
timberDynamicTransform(ctx),
|
|
15034
15435
|
timberFonts(ctx),
|
|
15035
15436
|
timberMdx(ctx),
|
|
15036
15437
|
timberContent(ctx),
|
|
@@ -15039,10 +15440,32 @@ function timber(config) {
|
|
|
15039
15440
|
timberBuildReport(ctx),
|
|
15040
15441
|
timberAdapterBuild(ctx),
|
|
15041
15442
|
timberDevLogs(ctx),
|
|
15443
|
+
timberDevBrowserLogs(ctx),
|
|
15042
15444
|
timberDevServer(ctx)
|
|
15043
15445
|
];
|
|
15044
15446
|
}
|
|
15447
|
+
/**
|
|
15448
|
+
* Type-safe helper for timber.config.ts files.
|
|
15449
|
+
*
|
|
15450
|
+
* A pass-through identity function that provides autocomplete and
|
|
15451
|
+
* type checking for timber configuration. No runtime validation —
|
|
15452
|
+
* purely a DX convenience (same pattern as Vite's defineConfig).
|
|
15453
|
+
*
|
|
15454
|
+
* @example
|
|
15455
|
+
* ```ts
|
|
15456
|
+
* // timber.config.ts
|
|
15457
|
+
* import { defineConfig } from '@timber-js/app';
|
|
15458
|
+
*
|
|
15459
|
+
* export default defineConfig({
|
|
15460
|
+
* output: 'server',
|
|
15461
|
+
* pageExtensions: ['tsx', 'ts', 'mdx'],
|
|
15462
|
+
* });
|
|
15463
|
+
* ```
|
|
15464
|
+
*/
|
|
15465
|
+
function defineConfig(config) {
|
|
15466
|
+
return config;
|
|
15467
|
+
}
|
|
15045
15468
|
//#endregion
|
|
15046
|
-
export { timber as default, timber, resolveAppDir, resolveClientJavascript, warnConfigConflicts };
|
|
15469
|
+
export { timber as default, timber, defineConfig, loadTimberConfigFile, resolveAppDir, resolveClientJavascript, warnConfigConflicts };
|
|
15047
15470
|
|
|
15048
15471
|
//# sourceMappingURL=index.js.map
|