@timber-js/app 0.2.0-alpha.7 → 0.2.0-alpha.71

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.
Files changed (500) hide show
  1. package/LICENSE +8 -0
  2. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-BJARkOcu.js} +1 -1
  3. package/dist/_chunks/als-registry-BJARkOcu.js.map +1 -0
  4. package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
  5. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  6. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  7. package/dist/_chunks/define-CGuYoRHU.js +199 -0
  8. package/dist/_chunks/define-CGuYoRHU.js.map +1 -0
  9. package/dist/_chunks/define-Dz1bqwaS.js +106 -0
  10. package/dist/_chunks/define-Dz1bqwaS.js.map +1 -0
  11. package/dist/_chunks/define-cookie-B5mewxwM.js +93 -0
  12. package/dist/_chunks/define-cookie-B5mewxwM.js.map +1 -0
  13. package/dist/_chunks/error-boundary-D9hzsveV.js +216 -0
  14. package/dist/_chunks/error-boundary-D9hzsveV.js.map +1 -0
  15. package/dist/_chunks/{format-DviM89f0.js → format-Rn922VH2.js} +3 -20
  16. package/dist/_chunks/format-Rn922VH2.js.map +1 -0
  17. package/dist/_chunks/{tracing-Cwn7697K.js → handler-store-BVePM7hp.js} +68 -3
  18. package/dist/_chunks/handler-store-BVePM7hp.js.map +1 -0
  19. package/dist/_chunks/{interception-BOoWmLUA.js → interception-CEdHHviP.js} +171 -97
  20. package/dist/_chunks/interception-CEdHHviP.js.map +1 -0
  21. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
  22. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  23. package/dist/_chunks/{request-context-DIkVh_jG.js → request-context-CywiO4jV.js} +181 -69
  24. package/dist/_chunks/request-context-CywiO4jV.js.map +1 -0
  25. package/dist/_chunks/schema-bridge-C4SwjCQD.js +86 -0
  26. package/dist/_chunks/schema-bridge-C4SwjCQD.js.map +1 -0
  27. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  28. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  29. package/dist/_chunks/segment-context-hzuJ048X.js +72 -0
  30. package/dist/_chunks/segment-context-hzuJ048X.js.map +1 -0
  31. package/dist/_chunks/stale-reload-BLUC_Pl_.js +64 -0
  32. package/dist/_chunks/stale-reload-BLUC_Pl_.js.map +1 -0
  33. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-DAhgj8Gx.js} +1 -1
  34. package/dist/_chunks/use-query-states-DAhgj8Gx.js.map +1 -0
  35. package/dist/_chunks/wrappers-LZbghvn0.js +63 -0
  36. package/dist/_chunks/wrappers-LZbghvn0.js.map +1 -0
  37. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  38. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  39. package/dist/adapters/cloudflare-dev.js +73 -0
  40. package/dist/adapters/cloudflare-dev.js.map +1 -0
  41. package/dist/adapters/cloudflare.d.ts +148 -12
  42. package/dist/adapters/cloudflare.d.ts.map +1 -1
  43. package/dist/adapters/cloudflare.js +135 -11
  44. package/dist/adapters/cloudflare.js.map +1 -1
  45. package/dist/adapters/compress-module.d.ts.map +1 -1
  46. package/dist/adapters/nitro.d.ts +17 -1
  47. package/dist/adapters/nitro.d.ts.map +1 -1
  48. package/dist/adapters/nitro.js +56 -13
  49. package/dist/adapters/nitro.js.map +1 -1
  50. package/dist/cache/cache-api.d.ts +24 -0
  51. package/dist/cache/cache-api.d.ts.map +1 -0
  52. package/dist/cache/fast-hash.d.ts +22 -0
  53. package/dist/cache/fast-hash.d.ts.map +1 -0
  54. package/dist/cache/handler-store.d.ts +31 -0
  55. package/dist/cache/handler-store.d.ts.map +1 -0
  56. package/dist/cache/index.d.ts +7 -5
  57. package/dist/cache/index.d.ts.map +1 -1
  58. package/dist/cache/index.js +111 -73
  59. package/dist/cache/index.js.map +1 -1
  60. package/dist/cache/singleflight.d.ts +18 -1
  61. package/dist/cache/singleflight.d.ts.map +1 -1
  62. package/dist/cache/timber-cache.d.ts +1 -1
  63. package/dist/cache/timber-cache.d.ts.map +1 -1
  64. package/dist/client/error-boundary.d.ts +12 -5
  65. package/dist/client/error-boundary.d.ts.map +1 -1
  66. package/dist/client/error-boundary.js +1 -125
  67. package/dist/client/error-reconstituter.d.ts +54 -0
  68. package/dist/client/error-reconstituter.d.ts.map +1 -0
  69. package/dist/client/form.d.ts +2 -2
  70. package/dist/client/form.d.ts.map +1 -1
  71. package/dist/client/history.d.ts +19 -4
  72. package/dist/client/history.d.ts.map +1 -1
  73. package/dist/client/index.d.ts +6 -5
  74. package/dist/client/index.d.ts.map +1 -1
  75. package/dist/client/index.js +537 -166
  76. package/dist/client/index.js.map +1 -1
  77. package/dist/client/link-pending-store.d.ts +78 -0
  78. package/dist/client/link-pending-store.d.ts.map +1 -0
  79. package/dist/client/link.d.ts +90 -32
  80. package/dist/client/link.d.ts.map +1 -1
  81. package/dist/client/nav-link-store.d.ts +36 -0
  82. package/dist/client/nav-link-store.d.ts.map +1 -0
  83. package/dist/client/navigation-api-types.d.ts +90 -0
  84. package/dist/client/navigation-api-types.d.ts.map +1 -0
  85. package/dist/client/navigation-api.d.ts +115 -0
  86. package/dist/client/navigation-api.d.ts.map +1 -0
  87. package/dist/client/navigation-context.d.ts +13 -2
  88. package/dist/client/navigation-context.d.ts.map +1 -1
  89. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  90. package/dist/client/navigation-root.d.ts.map +1 -0
  91. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  92. package/dist/client/router.d.ts +70 -4
  93. package/dist/client/router.d.ts.map +1 -1
  94. package/dist/client/rsc-fetch.d.ts +38 -3
  95. package/dist/client/rsc-fetch.d.ts.map +1 -1
  96. package/dist/client/segment-cache.d.ts +1 -1
  97. package/dist/client/segment-cache.d.ts.map +1 -1
  98. package/dist/client/segment-context.d.ts +1 -1
  99. package/dist/client/segment-context.d.ts.map +1 -1
  100. package/dist/client/segment-merger.d.ts.map +1 -1
  101. package/dist/client/segment-outlet.d.ts +63 -0
  102. package/dist/client/segment-outlet.d.ts.map +1 -0
  103. package/dist/client/ssr-data.d.ts +13 -4
  104. package/dist/client/ssr-data.d.ts.map +1 -1
  105. package/dist/client/stale-reload.d.ts +15 -0
  106. package/dist/client/stale-reload.d.ts.map +1 -1
  107. package/dist/client/top-loader.d.ts +3 -3
  108. package/dist/client/top-loader.d.ts.map +1 -1
  109. package/dist/client/use-params.d.ts +6 -4
  110. package/dist/client/use-params.d.ts.map +1 -1
  111. package/dist/client/use-query-states.d.ts +1 -1
  112. package/dist/client/use-query-states.d.ts.map +1 -1
  113. package/dist/codec.d.ts +23 -0
  114. package/dist/codec.d.ts.map +1 -0
  115. package/dist/codec.js +2 -0
  116. package/dist/cookies/define-cookie.d.ts +35 -14
  117. package/dist/cookies/define-cookie.d.ts.map +1 -1
  118. package/dist/cookies/index.d.ts +2 -0
  119. package/dist/cookies/index.d.ts.map +1 -1
  120. package/dist/cookies/index.js +3 -84
  121. package/dist/fonts/css.d.ts +1 -0
  122. package/dist/fonts/css.d.ts.map +1 -1
  123. package/dist/index.d.ts +154 -38
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +12092 -11916
  126. package/dist/index.js.map +1 -1
  127. package/dist/plugins/adapter-build.d.ts +1 -1
  128. package/dist/plugins/adapter-build.d.ts.map +1 -1
  129. package/dist/plugins/build-manifest.d.ts +2 -2
  130. package/dist/plugins/build-manifest.d.ts.map +1 -1
  131. package/dist/plugins/build-report.d.ts +3 -3
  132. package/dist/plugins/build-report.d.ts.map +1 -1
  133. package/dist/plugins/client-chunks.d.ts +32 -0
  134. package/dist/plugins/client-chunks.d.ts.map +1 -0
  135. package/dist/plugins/content.d.ts +1 -1
  136. package/dist/plugins/content.d.ts.map +1 -1
  137. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  138. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  139. package/dist/plugins/dev-error-overlay.d.ts +26 -1
  140. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  141. package/dist/plugins/dev-logs.d.ts +1 -1
  142. package/dist/plugins/dev-logs.d.ts.map +1 -1
  143. package/dist/plugins/dev-server.d.ts +1 -1
  144. package/dist/plugins/dev-server.d.ts.map +1 -1
  145. package/dist/plugins/entries.d.ts +1 -1
  146. package/dist/plugins/entries.d.ts.map +1 -1
  147. package/dist/plugins/fonts.d.ts +19 -5
  148. package/dist/plugins/fonts.d.ts.map +1 -1
  149. package/dist/plugins/mdx.d.ts +1 -1
  150. package/dist/plugins/mdx.d.ts.map +1 -1
  151. package/dist/plugins/routing.d.ts +1 -1
  152. package/dist/plugins/routing.d.ts.map +1 -1
  153. package/dist/plugins/server-bundle.d.ts.map +1 -1
  154. package/dist/plugins/shims.d.ts +6 -5
  155. package/dist/plugins/shims.d.ts.map +1 -1
  156. package/dist/plugins/static-build.d.ts +1 -1
  157. package/dist/plugins/static-build.d.ts.map +1 -1
  158. package/dist/routing/codegen.d.ts +2 -2
  159. package/dist/routing/codegen.d.ts.map +1 -1
  160. package/dist/routing/index.d.ts +2 -0
  161. package/dist/routing/index.d.ts.map +1 -1
  162. package/dist/routing/index.js +3 -2
  163. package/dist/routing/scanner.d.ts.map +1 -1
  164. package/dist/routing/segment-classify.d.ts +46 -0
  165. package/dist/routing/segment-classify.d.ts.map +1 -0
  166. package/dist/routing/status-file-lint.d.ts +2 -1
  167. package/dist/routing/status-file-lint.d.ts.map +1 -1
  168. package/dist/routing/types.d.ts +16 -4
  169. package/dist/routing/types.d.ts.map +1 -1
  170. package/dist/rsc-runtime/rsc.d.ts +1 -1
  171. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  172. package/dist/rsc-runtime/ssr.d.ts +12 -0
  173. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  174. package/dist/schema-bridge.d.ts +76 -0
  175. package/dist/schema-bridge.d.ts.map +1 -0
  176. package/dist/search-params/define.d.ts +139 -0
  177. package/dist/search-params/define.d.ts.map +1 -0
  178. package/dist/search-params/index.d.ts +4 -6
  179. package/dist/search-params/index.d.ts.map +1 -1
  180. package/dist/search-params/index.js +4 -474
  181. package/dist/search-params/registry.d.ts +1 -1
  182. package/dist/search-params/wrappers.d.ts +53 -0
  183. package/dist/search-params/wrappers.d.ts.map +1 -0
  184. package/dist/segment-params/define.d.ts +78 -0
  185. package/dist/segment-params/define.d.ts.map +1 -0
  186. package/dist/segment-params/index.d.ts +7 -0
  187. package/dist/segment-params/index.d.ts.map +1 -0
  188. package/dist/segment-params/index.js +4 -0
  189. package/dist/server/access-gate.d.ts +4 -0
  190. package/dist/server/access-gate.d.ts.map +1 -1
  191. package/dist/server/action-client.d.ts +12 -1
  192. package/dist/server/action-client.d.ts.map +1 -1
  193. package/dist/server/action-encryption.d.ts +76 -0
  194. package/dist/server/action-encryption.d.ts.map +1 -0
  195. package/dist/server/action-handler.d.ts.map +1 -1
  196. package/dist/server/actions.d.ts +3 -6
  197. package/dist/server/actions.d.ts.map +1 -1
  198. package/dist/server/als-registry.d.ts +32 -4
  199. package/dist/server/als-registry.d.ts.map +1 -1
  200. package/dist/server/build-manifest.d.ts +2 -2
  201. package/dist/server/build-manifest.d.ts.map +1 -1
  202. package/dist/server/debug.d.ts +1 -1
  203. package/dist/server/default-logger.d.ts +22 -0
  204. package/dist/server/default-logger.d.ts.map +1 -0
  205. package/dist/server/deny-page-resolver.d.ts +52 -0
  206. package/dist/server/deny-page-resolver.d.ts.map +1 -0
  207. package/dist/server/deny-renderer.d.ts.map +1 -1
  208. package/dist/server/dev-warnings.d.ts +0 -14
  209. package/dist/server/dev-warnings.d.ts.map +1 -1
  210. package/dist/server/early-hints.d.ts +13 -5
  211. package/dist/server/early-hints.d.ts.map +1 -1
  212. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  213. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  214. package/dist/server/fallback-error.d.ts +4 -3
  215. package/dist/server/fallback-error.d.ts.map +1 -1
  216. package/dist/server/flight-injection-state.d.ts +66 -0
  217. package/dist/server/flight-injection-state.d.ts.map +1 -0
  218. package/dist/server/flight-scripts.d.ts +42 -0
  219. package/dist/server/flight-scripts.d.ts.map +1 -0
  220. package/dist/server/flush.d.ts.map +1 -1
  221. package/dist/server/form-data.d.ts +29 -0
  222. package/dist/server/form-data.d.ts.map +1 -1
  223. package/dist/server/html-injectors.d.ts +51 -11
  224. package/dist/server/html-injectors.d.ts.map +1 -1
  225. package/dist/server/index.d.ts +5 -3
  226. package/dist/server/index.d.ts.map +1 -1
  227. package/dist/server/index.js +2176 -1663
  228. package/dist/server/index.js.map +1 -1
  229. package/dist/server/logger.d.ts +25 -7
  230. package/dist/server/logger.d.ts.map +1 -1
  231. package/dist/server/middleware-runner.d.ts +19 -4
  232. package/dist/server/middleware-runner.d.ts.map +1 -1
  233. package/dist/server/node-stream-transforms.d.ts +113 -0
  234. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  235. package/dist/server/page-deny-boundary.d.ts +31 -0
  236. package/dist/server/page-deny-boundary.d.ts.map +1 -0
  237. package/dist/server/pipeline-interception.d.ts +1 -1
  238. package/dist/server/pipeline-interception.d.ts.map +1 -1
  239. package/dist/server/pipeline-metadata.d.ts +6 -0
  240. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  241. package/dist/server/pipeline.d.ts +32 -10
  242. package/dist/server/pipeline.d.ts.map +1 -1
  243. package/dist/server/primitives.d.ts +30 -3
  244. package/dist/server/primitives.d.ts.map +1 -1
  245. package/dist/server/render-timeout.d.ts +51 -0
  246. package/dist/server/render-timeout.d.ts.map +1 -0
  247. package/dist/server/request-context.d.ts +76 -37
  248. package/dist/server/request-context.d.ts.map +1 -1
  249. package/dist/server/route-element-builder.d.ts +27 -1
  250. package/dist/server/route-element-builder.d.ts.map +1 -1
  251. package/dist/server/route-handler.d.ts.map +1 -1
  252. package/dist/server/route-matcher.d.ts +9 -2
  253. package/dist/server/route-matcher.d.ts.map +1 -1
  254. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  255. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  256. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  257. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  258. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  259. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  260. package/dist/server/rsc-entry/index.d.ts +8 -3
  261. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  262. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  263. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  264. package/dist/server/rsc-entry/rsc-stream.d.ts +10 -1
  265. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  266. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  267. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  268. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  269. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  270. package/dist/server/safe-load.d.ts +46 -0
  271. package/dist/server/safe-load.d.ts.map +1 -0
  272. package/dist/server/sitemap-generator.d.ts +129 -0
  273. package/dist/server/sitemap-generator.d.ts.map +1 -0
  274. package/dist/server/sitemap-handler.d.ts +22 -0
  275. package/dist/server/sitemap-handler.d.ts.map +1 -0
  276. package/dist/server/slot-resolver.d.ts +1 -1
  277. package/dist/server/slot-resolver.d.ts.map +1 -1
  278. package/dist/server/ssr-entry.d.ts +22 -0
  279. package/dist/server/ssr-entry.d.ts.map +1 -1
  280. package/dist/server/ssr-render.d.ts +39 -21
  281. package/dist/server/ssr-render.d.ts.map +1 -1
  282. package/dist/server/ssr-wrappers.d.ts +50 -0
  283. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  284. package/dist/server/status-code-resolver.d.ts +1 -1
  285. package/dist/server/status-code-resolver.d.ts.map +1 -1
  286. package/dist/server/stream-utils.d.ts +36 -0
  287. package/dist/server/stream-utils.d.ts.map +1 -0
  288. package/dist/server/tracing.d.ts +10 -0
  289. package/dist/server/tracing.d.ts.map +1 -1
  290. package/dist/server/tree-builder.d.ts +22 -19
  291. package/dist/server/tree-builder.d.ts.map +1 -1
  292. package/dist/server/types.d.ts +1 -4
  293. package/dist/server/types.d.ts.map +1 -1
  294. package/dist/server/version-skew.d.ts +61 -0
  295. package/dist/server/version-skew.d.ts.map +1 -0
  296. package/dist/server/waituntil-bridge.d.ts.map +1 -1
  297. package/dist/shared/merge-search-params.d.ts +22 -0
  298. package/dist/shared/merge-search-params.d.ts.map +1 -0
  299. package/dist/shims/font-google.d.ts +1 -1
  300. package/dist/shims/font-google.d.ts.map +1 -1
  301. package/dist/shims/font-google.js +42 -0
  302. package/dist/shims/font-google.js.map +1 -0
  303. package/dist/shims/font-local.d.ts +26 -0
  304. package/dist/shims/font-local.d.ts.map +1 -0
  305. package/dist/shims/font-local.js +20 -0
  306. package/dist/shims/font-local.js.map +1 -0
  307. package/dist/shims/navigation-client.d.ts +1 -1
  308. package/dist/shims/navigation-client.d.ts.map +1 -1
  309. package/dist/shims/navigation.d.ts +1 -1
  310. package/dist/shims/navigation.d.ts.map +1 -1
  311. package/dist/utils/directive-parser.d.ts +5 -2
  312. package/dist/utils/directive-parser.d.ts.map +1 -1
  313. package/dist/utils/state-machine.d.ts +80 -0
  314. package/dist/utils/state-machine.d.ts.map +1 -0
  315. package/package.json +37 -17
  316. package/src/adapters/cloudflare-dev.ts +177 -0
  317. package/src/adapters/cloudflare.ts +342 -28
  318. package/src/adapters/compress-module.ts +24 -4
  319. package/src/adapters/nitro.ts +58 -9
  320. package/src/adapters/wrangler.d.ts +7 -0
  321. package/src/cache/cache-api.ts +38 -0
  322. package/src/cache/fast-hash.ts +34 -0
  323. package/src/cache/handler-store.ts +68 -0
  324. package/src/cache/index.ts +9 -5
  325. package/src/cache/singleflight.ts +62 -4
  326. package/src/cache/timber-cache.ts +40 -29
  327. package/src/cli.ts +0 -0
  328. package/src/client/browser-entry.ts +314 -142
  329. package/src/client/error-boundary.tsx +48 -16
  330. package/src/client/error-reconstituter.tsx +65 -0
  331. package/src/client/form.tsx +2 -2
  332. package/src/client/history.ts +26 -4
  333. package/src/client/index.ts +13 -4
  334. package/src/client/link-pending-store.ts +136 -0
  335. package/src/client/link.tsx +346 -105
  336. package/src/client/nav-link-store.ts +47 -0
  337. package/src/client/navigation-api-types.ts +112 -0
  338. package/src/client/navigation-api.ts +332 -0
  339. package/src/client/navigation-context.ts +27 -6
  340. package/src/client/navigation-root.tsx +346 -0
  341. package/src/client/nuqs-adapter.tsx +16 -3
  342. package/src/client/router.ts +302 -77
  343. package/src/client/rsc-fetch.ts +93 -5
  344. package/src/client/segment-cache.ts +1 -1
  345. package/src/client/segment-context.ts +6 -1
  346. package/src/client/segment-merger.ts +2 -8
  347. package/src/client/segment-outlet.tsx +86 -0
  348. package/src/client/ssr-data.ts +13 -5
  349. package/src/client/stale-reload.ts +73 -6
  350. package/src/client/top-loader.tsx +22 -13
  351. package/src/client/use-navigation-pending.ts +1 -1
  352. package/src/client/use-params.ts +7 -5
  353. package/src/client/use-query-states.ts +2 -2
  354. package/src/codec.ts +34 -0
  355. package/src/cookies/define-cookie.ts +72 -21
  356. package/src/cookies/index.ts +7 -0
  357. package/src/fonts/css.ts +2 -1
  358. package/src/index.ts +328 -92
  359. package/src/plugins/adapter-build.ts +8 -2
  360. package/src/plugins/build-manifest.ts +13 -2
  361. package/src/plugins/build-report.ts +3 -3
  362. package/src/plugins/client-chunks.ts +65 -0
  363. package/src/plugins/content.ts +1 -1
  364. package/src/plugins/dev-browser-logs.ts +288 -0
  365. package/src/plugins/dev-error-overlay.ts +70 -1
  366. package/src/plugins/dev-logs.ts +1 -1
  367. package/src/plugins/dev-server.ts +55 -9
  368. package/src/plugins/entries.ts +70 -9
  369. package/src/plugins/fonts.ts +167 -61
  370. package/src/plugins/mdx.ts +1 -1
  371. package/src/plugins/routing.ts +57 -17
  372. package/src/plugins/server-action-exports.ts +1 -1
  373. package/src/plugins/server-bundle.ts +32 -1
  374. package/src/plugins/shims.ts +76 -33
  375. package/src/plugins/static-build.ts +10 -6
  376. package/src/routing/codegen.ts +165 -105
  377. package/src/routing/index.ts +2 -0
  378. package/src/routing/scanner.ts +93 -23
  379. package/src/routing/segment-classify.ts +89 -0
  380. package/src/routing/status-file-lint.ts +3 -2
  381. package/src/routing/types.ts +17 -4
  382. package/src/rsc-runtime/rsc.ts +2 -0
  383. package/src/rsc-runtime/ssr.ts +50 -0
  384. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  385. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  386. package/src/search-params/define.ts +482 -0
  387. package/src/search-params/index.ts +13 -19
  388. package/src/search-params/registry.ts +1 -1
  389. package/src/search-params/wrappers.ts +85 -0
  390. package/src/segment-params/define.ts +279 -0
  391. package/src/segment-params/index.ts +28 -0
  392. package/src/server/access-gate.tsx +70 -29
  393. package/src/server/action-client.ts +28 -3
  394. package/src/server/action-encryption.ts +144 -0
  395. package/src/server/action-handler.ts +20 -3
  396. package/src/server/actions.ts +10 -9
  397. package/src/server/als-registry.ts +32 -4
  398. package/src/server/build-manifest.ts +10 -4
  399. package/src/server/compress.ts +25 -7
  400. package/src/server/debug.ts +1 -1
  401. package/src/server/default-logger.ts +99 -0
  402. package/src/server/deny-page-resolver.ts +154 -0
  403. package/src/server/deny-renderer.ts +24 -38
  404. package/src/server/dev-warnings.ts +2 -28
  405. package/src/server/early-hints.ts +36 -15
  406. package/src/server/error-boundary-wrapper.ts +74 -22
  407. package/src/server/fallback-error.ts +31 -15
  408. package/src/server/flight-injection-state.ts +113 -0
  409. package/src/server/flight-scripts.ts +62 -0
  410. package/src/server/flush.ts +2 -1
  411. package/src/server/form-data.ts +76 -0
  412. package/src/server/html-injectors.ts +277 -117
  413. package/src/server/index.ts +9 -5
  414. package/src/server/logger.ts +44 -36
  415. package/src/server/middleware-runner.ts +31 -4
  416. package/src/server/node-stream-transforms.ts +509 -0
  417. package/src/server/page-deny-boundary.tsx +56 -0
  418. package/src/server/pipeline-interception.ts +17 -16
  419. package/src/server/pipeline-metadata.ts +13 -0
  420. package/src/server/pipeline.ts +195 -51
  421. package/src/server/primitives.ts +47 -5
  422. package/src/server/render-timeout.ts +108 -0
  423. package/src/server/request-context.ts +240 -117
  424. package/src/server/route-element-builder.ts +284 -197
  425. package/src/server/route-handler.ts +24 -4
  426. package/src/server/route-matcher.ts +24 -20
  427. package/src/server/rsc-entry/api-handler.ts +15 -16
  428. package/src/server/rsc-entry/error-renderer.ts +300 -89
  429. package/src/server/rsc-entry/helpers.ts +134 -5
  430. package/src/server/rsc-entry/index.ts +202 -113
  431. package/src/server/rsc-entry/rsc-payload.ts +100 -21
  432. package/src/server/rsc-entry/rsc-stream.ts +74 -18
  433. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  434. package/src/server/rsc-entry/ssr-renderer.ts +173 -40
  435. package/src/server/safe-load.ts +60 -0
  436. package/src/server/sitemap-generator.ts +338 -0
  437. package/src/server/sitemap-handler.ts +126 -0
  438. package/src/server/slot-resolver.ts +243 -228
  439. package/src/server/ssr-entry.ts +211 -32
  440. package/src/server/ssr-render.ts +289 -67
  441. package/src/server/ssr-wrappers.tsx +139 -0
  442. package/src/server/status-code-resolver.ts +1 -1
  443. package/src/server/stream-utils.ts +213 -0
  444. package/src/server/tracing.ts +37 -3
  445. package/src/server/tree-builder.ts +92 -58
  446. package/src/server/types.ts +3 -6
  447. package/src/server/version-skew.ts +104 -0
  448. package/src/server/waituntil-bridge.ts +4 -1
  449. package/src/shared/merge-search-params.ts +55 -0
  450. package/src/shims/font-google.ts +1 -1
  451. package/src/shims/font-local.ts +34 -0
  452. package/src/shims/navigation-client.ts +1 -1
  453. package/src/shims/navigation.ts +2 -1
  454. package/src/utils/directive-parser.ts +5 -2
  455. package/src/utils/state-machine.ts +111 -0
  456. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  457. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  458. package/dist/_chunks/format-DviM89f0.js.map +0 -1
  459. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  460. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  461. package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
  462. package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
  463. package/dist/_chunks/tracing-Cwn7697K.js.map +0 -1
  464. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  465. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  466. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  467. package/dist/cache/register-cached-function.d.ts +0 -17
  468. package/dist/cache/register-cached-function.d.ts.map +0 -1
  469. package/dist/client/error-boundary.js.map +0 -1
  470. package/dist/client/link-status-provider.d.ts +0 -11
  471. package/dist/client/link-status-provider.d.ts.map +0 -1
  472. package/dist/client/transition-root.d.ts.map +0 -1
  473. package/dist/cookies/index.js.map +0 -1
  474. package/dist/plugins/cache-transform.d.ts +0 -36
  475. package/dist/plugins/cache-transform.d.ts.map +0 -1
  476. package/dist/plugins/dynamic-transform.d.ts +0 -72
  477. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  478. package/dist/search-params/analyze.d.ts +0 -54
  479. package/dist/search-params/analyze.d.ts.map +0 -1
  480. package/dist/search-params/builtin-codecs.d.ts +0 -105
  481. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  482. package/dist/search-params/codecs.d.ts +0 -53
  483. package/dist/search-params/codecs.d.ts.map +0 -1
  484. package/dist/search-params/create.d.ts +0 -106
  485. package/dist/search-params/create.d.ts.map +0 -1
  486. package/dist/search-params/index.js.map +0 -1
  487. package/dist/server/prerender.d.ts +0 -77
  488. package/dist/server/prerender.d.ts.map +0 -1
  489. package/dist/server/response-cache.d.ts +0 -53
  490. package/dist/server/response-cache.d.ts.map +0 -1
  491. package/src/cache/register-cached-function.ts +0 -99
  492. package/src/client/link-status-provider.tsx +0 -30
  493. package/src/client/transition-root.tsx +0 -160
  494. package/src/plugins/cache-transform.ts +0 -199
  495. package/src/plugins/dynamic-transform.ts +0 -161
  496. package/src/search-params/analyze.ts +0 -192
  497. package/src/search-params/builtin-codecs.ts +0 -228
  498. package/src/search-params/create.ts +0 -321
  499. package/src/server/prerender.ts +0 -139
  500. package/src/server/response-cache.ts +0 -277
@@ -15,7 +15,7 @@ import type { Plugin } from 'vite';
15
15
  import { resolve, dirname } from 'node:path';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { existsSync } from 'node:fs';
18
- import type { PluginContext } from '#/index.js';
18
+ import type { PluginContext } from '../index.js';
19
19
 
20
20
  const __dirname = dirname(fileURLToPath(import.meta.url));
21
21
 
@@ -34,6 +34,7 @@ const VIRTUAL_IDS = {
34
34
  browserEntry: 'virtual:timber-browser-entry',
35
35
  config: 'virtual:timber-config',
36
36
  instrumentation: 'virtual:timber-instrumentation',
37
+ cacheHandler: 'virtual:timber-cache-handler',
37
38
  } as const;
38
39
 
39
40
  /**
@@ -57,6 +58,9 @@ const RESOLVED_CONFIG_ID = `\0${VIRTUAL_IDS.config}`;
57
58
  /** The \0-prefixed resolved ID for virtual:timber-instrumentation */
58
59
  const RESOLVED_INSTRUMENTATION_ID = `\0${VIRTUAL_IDS.instrumentation}`;
59
60
 
61
+ /** The \0-prefixed resolved ID for virtual:timber-cache-handler */
62
+ const RESOLVED_CACHE_HANDLER_ID = `\0${VIRTUAL_IDS.cacheHandler}`;
63
+
60
64
  /**
61
65
  * Strip the \0 prefix from a module ID.
62
66
  *
@@ -95,11 +99,6 @@ function stripRootPrefix(id: string, root: string): string {
95
99
  * Serializes output mode and feature flags for runtime consumption.
96
100
  */
97
101
  function generateConfigModule(ctx: PluginContext): string {
98
- // Resolve cookie secrets: `secret` shorthand expands to `secrets: [secret]`
99
- const cookieSecrets =
100
- ctx.config.cookies?.secrets ??
101
- (ctx.config.cookies?.secret ? [ctx.config.cookies.secret] : undefined);
102
-
103
102
  const runtimeConfig = {
104
103
  output: ctx.config.output ?? 'server',
105
104
  csrf: ctx.config.csrf ?? true,
@@ -108,11 +107,16 @@ function generateConfigModule(ctx: PluginContext): string {
108
107
  dev: ctx.dev ?? false,
109
108
  slowPhaseMs: ctx.config.dev?.slowPhaseMs ?? 200,
110
109
  slowRequestMs: ctx.config.slowRequestMs ?? 3000,
111
- cookieSecrets,
112
110
  topLoader: ctx.config.topLoader,
113
- responseCache: ctx.config.responseCache,
114
111
  debug: ctx.config.debug ?? false,
115
- fontCssUrl: ctx.fontCssUrl ?? null,
112
+ serverTiming: ctx.config.serverTiming,
113
+ renderTimeoutMs: ctx.config.renderTimeoutMs ?? 30_000,
114
+ // Auto-generated sitemap config — opt-in via timber.config.ts.
115
+ // See design/16-metadata.md §"Auto-generated Sitemap"
116
+ sitemap: ctx.config.sitemap,
117
+ // Per-build deployment ID for version skew detection (TIM-446).
118
+ // Null in dev mode — HMR handles code updates without full reloads.
119
+ deploymentId: ctx.deploymentId ?? null,
116
120
  };
117
121
 
118
122
  return [
@@ -178,6 +182,53 @@ export function generateInstrumentationModule(instrumentationPath: string | null
178
182
  ].join('\n');
179
183
  }
180
184
 
185
+ /**
186
+ * Detect the user's timber.config file at the project root.
187
+ * Returns the absolute path or null if not found.
188
+ */
189
+ function detectConfigFile(root: string): string | null {
190
+ const names = ['timber.config.ts', 'timber.config.js', 'timber.config.mjs'];
191
+ for (const name of names) {
192
+ const candidate = resolve(root, name);
193
+ if (existsSync(candidate)) return candidate;
194
+ }
195
+ return null;
196
+ }
197
+
198
+ /**
199
+ * Generate the virtual:timber-cache-handler module source.
200
+ *
201
+ * When the user's config has a cacheHandler, generates a module that
202
+ * dynamically imports the config file and extracts the cacheHandler.
203
+ * The cacheHandler is a class instance (e.g. RedisCacheHandler) that
204
+ * cannot be JSON-serialized into virtual:timber-config, so it must
205
+ * be loaded at runtime via dynamic import. See TIM-599.
206
+ */
207
+ function generateCacheHandlerModule(configPath: string | null, hasCacheHandler: boolean): string {
208
+ if (configPath && hasCacheHandler) {
209
+ return [
210
+ '// Auto-generated cache handler loader — do not edit.',
211
+ '// Generated by timber-entries plugin.',
212
+ '',
213
+ `export default async function loadCacheHandler() {`,
214
+ ` const mod = await import(${JSON.stringify(configPath)});`,
215
+ ` const config = mod.default ?? mod;`,
216
+ ` return config.cacheHandler ?? null;`,
217
+ `}`,
218
+ ].join('\n');
219
+ }
220
+
221
+ return [
222
+ '// Auto-generated cache handler loader — do not edit.',
223
+ '// Generated by timber-entries plugin.',
224
+ '// No cacheHandler configured in timber.config.',
225
+ '',
226
+ `export default async function loadCacheHandler() {`,
227
+ ` return null;`,
228
+ `}`,
229
+ ].join('\n');
230
+ }
231
+
181
232
  /**
182
233
  * Create the timber-entries Vite plugin.
183
234
  *
@@ -220,6 +271,11 @@ export function timberEntries(ctx: PluginContext): Plugin {
220
271
  return RESOLVED_INSTRUMENTATION_ID;
221
272
  }
222
273
 
274
+ // Check cache handler virtual module
275
+ if (cleanId === VIRTUAL_IDS.cacheHandler) {
276
+ return RESOLVED_CACHE_HANDLER_ID;
277
+ }
278
+
223
279
  return null;
224
280
  },
225
281
 
@@ -237,6 +293,11 @@ export function timberEntries(ctx: PluginContext): Plugin {
237
293
  const instrumentationPath = detectInstrumentationFile(ctx.root);
238
294
  return generateInstrumentationModule(instrumentationPath);
239
295
  }
296
+ if (id === RESOLVED_CACHE_HANDLER_ID) {
297
+ const configPath = detectConfigFile(ctx.root);
298
+ const hasCacheHandler = ctx.config.cacheHandler != null;
299
+ return generateCacheHandlerModule(configPath, hasCacheHandler);
300
+ }
240
301
  return null;
241
302
  },
242
303
 
@@ -17,27 +17,47 @@
17
17
  import type { Plugin, ViteDevServer } from 'vite';
18
18
  import { readFileSync, existsSync } from 'node:fs';
19
19
  import { resolve, normalize } from 'node:path';
20
- import type { PluginContext } from '#/index.js';
21
- import type { ExtractedFont, GoogleFontConfig } from '#/fonts/types.js';
22
- import type { ManifestFontEntry } from '#/server/build-manifest.js';
23
- import { generateVariableClass, generateFontFamilyClass, generateFontFaces } from '#/fonts/css.js';
24
- import { generateFallbackCss, buildFontStack } from '#/fonts/fallbacks.js';
25
- import { processLocalFont, generateLocalFontFaces } from '#/fonts/local.js';
26
- import { inferFontFormat } from '#/fonts/local.js';
27
- import { downloadAndCacheFonts, type CachedFont } from '#/fonts/google.js';
20
+ import type { PluginContext } from '../index.js';
21
+ import type { ExtractedFont, GoogleFontConfig } from '../fonts/types.js';
22
+ import type { ManifestFontEntry } from '../server/build-manifest.js';
23
+ import { generateVariableClass, generateFontFamilyClass, generateFontFaces } from '../fonts/css.js';
24
+ import { generateFallbackCss, buildFontStack } from '../fonts/fallbacks.js';
25
+ import { processLocalFont, generateLocalFontFaces } from '../fonts/local.js';
26
+ import { inferFontFormat } from '../fonts/local.js';
27
+ import {
28
+ downloadAndCacheFonts,
29
+ generateProductionFontFaces,
30
+ resolveDevFontFaces,
31
+ type CachedFont,
32
+ } from '../fonts/google.js';
33
+ import type { FontFaceDescriptor } from '../fonts/types.js';
28
34
  import {
29
35
  extractFontConfigAst,
30
36
  extractLocalFontConfigAst,
31
37
  detectDynamicFontCallAst,
32
- } from '#/fonts/ast.js';
38
+ } from '../fonts/ast.js';
33
39
 
34
40
  const VIRTUAL_GOOGLE = '@timber/fonts/google';
35
41
  const VIRTUAL_LOCAL = '@timber/fonts/local';
36
42
  const RESOLVED_GOOGLE = '\0@timber/fonts/google';
37
43
  const RESOLVED_LOCAL = '\0@timber/fonts/local';
38
44
 
39
- /** URL path where font CSS is served (dev middleware and prod asset). */
40
- const FONT_CSS_PATH = '/_timber/fonts/fonts.css';
45
+ /**
46
+ * Virtual side-effect module that registers font CSS on globalThis.
47
+ *
48
+ * When a file calls localFont() or a Google font function, the transform
49
+ * hook injects `import 'virtual:timber-font-css-register'` into that file.
50
+ * This virtual module sets `globalThis.__timber_font_css` with the combined
51
+ * @font-face CSS. The RSC entry reads it at render time to inline a <style> tag.
52
+ *
53
+ * This approach avoids timing issues because:
54
+ * 1. The font file is in the RSC module graph (imported by layout.tsx)
55
+ * 2. The side-effect import is added to the font file during transform
56
+ * 3. When layout.tsx is loaded, fonts.ts runs → side-effect module runs → globalThis is set
57
+ * 4. RSC entry renders → reads globalThis → inlines <style>
58
+ */
59
+ const VIRTUAL_FONT_CSS_REGISTER = 'virtual:timber-font-css-register';
60
+ const RESOLVED_FONT_CSS_REGISTER = '\0virtual:timber-font-css-register';
41
61
 
42
62
  /**
43
63
  * Registry of fonts extracted during transform.
@@ -120,7 +140,7 @@ export function detectDynamicFontCall(source: string, importedNames: string[]):
120
140
  * but the source code still contains the original import specifier.
121
141
  */
122
142
  const GOOGLE_FONT_IMPORT_RE =
123
- /import\s*\{([^}]+)\}\s*from\s*['"](?:@timber\/fonts\/google|next\/font\/google)['"]/g;
143
+ /import\s*\{([^}]+)\}\s*from\s*['"](?:@timber\/fonts\/google|@timber-js\/app\/fonts\/google|next\/font\/google)['"]/g;
124
144
 
125
145
  /**
126
146
  * Parse import specifiers from a source file that imports from
@@ -248,37 +268,61 @@ function generateLocalVirtualModule(): string {
248
268
  }
249
269
 
250
270
  /**
251
- * Generate the CSS output for all extracted fonts.
271
+ * Generate CSS for a single extracted font.
272
+ *
273
+ * Includes @font-face rules (for local and Google fonts), fallback @font-face,
274
+ * and the scoped class rule.
252
275
  *
253
- * Includes @font-face rules for local fonts, fallback @font-face rules,
254
- * and scoped classes.
276
+ * For Google fonts, pass the resolved FontFaceDescriptor[] from either
277
+ * `generateProductionFontFaces()` (production) or `resolveDevFontFaces()` (dev).
255
278
  */
256
- export function generateAllFontCss(registry: FontRegistry): string {
279
+ export function generateFontCss(font: ExtractedFont, googleFaces?: FontFaceDescriptor[]): string {
257
280
  const cssParts: string[] = [];
258
281
 
259
- for (const font of registry.values()) {
260
- // Generate @font-face rules for local fonts
261
- if (font.provider === 'local' && font.localSources) {
262
- const faces = generateLocalFontFaces(font.family, font.localSources, font.display);
263
- const faceCss = generateFontFaces(faces);
264
- if (faceCss) cssParts.push(faceCss);
265
- }
282
+ if (font.provider === 'local' && font.localSources) {
283
+ const faces = generateLocalFontFaces(font.family, font.localSources, font.display);
284
+ const faceCss = generateFontFaces(faces);
285
+ if (faceCss) cssParts.push(faceCss);
286
+ }
266
287
 
267
- // Generate fallback @font-face if metrics are available
268
- const fallbackCss = generateFallbackCss(font.family);
269
- if (fallbackCss) cssParts.push(fallbackCss);
288
+ if (font.provider === 'google' && googleFaces && googleFaces.length > 0) {
289
+ const faceCss = generateFontFaces(googleFaces);
290
+ if (faceCss) cssParts.push(faceCss);
291
+ }
270
292
 
271
- // Generate scoped class
272
- if (font.variable) {
273
- cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
274
- } else {
275
- cssParts.push(generateFontFamilyClass(font.className, font.fontFamily));
276
- }
293
+ const fallbackCss = generateFallbackCss(font.family);
294
+ if (fallbackCss) cssParts.push(fallbackCss);
295
+
296
+ if (font.variable) {
297
+ cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
298
+ } else {
299
+ cssParts.push(generateFontFamilyClass(font.className, font.fontFamily));
277
300
  }
278
301
 
279
302
  return cssParts.join('\n\n');
280
303
  }
281
304
 
305
+ /**
306
+ * Generate the CSS output for all extracted fonts.
307
+ *
308
+ * Includes @font-face rules for local and Google fonts, fallback @font-face
309
+ * rules, and scoped classes.
310
+ *
311
+ * `googleFontFacesMap` provides pre-resolved FontFaceDescriptor[] for each
312
+ * Google font ID (keyed by ExtractedFont.id).
313
+ */
314
+ export function generateAllFontCss(
315
+ registry: FontRegistry,
316
+ googleFontFacesMap?: Map<string, FontFaceDescriptor[]>
317
+ ): string {
318
+ const cssParts: string[] = [];
319
+ for (const font of registry.values()) {
320
+ const googleFaces = googleFontFacesMap?.get(font.id);
321
+ cssParts.push(generateFontCss(font, googleFaces));
322
+ }
323
+ return cssParts.join('\n\n');
324
+ }
325
+
282
326
  /**
283
327
  * Parse the local name used for the default import of `@timber/fonts/local`.
284
328
  *
@@ -288,7 +332,7 @@ export function generateAllFontCss(registry: FontRegistry): string {
288
332
  */
289
333
  export function parseLocalFontImportName(source: string): string | null {
290
334
  const match = source.match(
291
- /import\s+(\w+)\s+from\s*['"](?:@timber\/fonts\/local|next\/font\/local)['"]/
335
+ /import\s+(\w+)\s+from\s*['"](?:@timber\/fonts\/local|@timber-js\/app\/fonts\/local|next\/font\/local)['"]/
292
336
  );
293
337
  return match ? match[1] : null;
294
338
  }
@@ -353,7 +397,7 @@ function transformLocalFonts(
353
397
 
354
398
  // Remove the import statement
355
399
  transformedCode = transformedCode.replace(
356
- /import\s+\w+\s+from\s*['"](?:@timber\/fonts\/local|next\/font\/local)['"];?\s*\n?/g,
400
+ /import\s+\w+\s+from\s*['"](?:@timber\/fonts\/local|@timber-js\/app\/fonts\/local|next\/font\/local)['"];?\s*\n?/g,
357
401
  ''
358
402
  );
359
403
 
@@ -367,25 +411,79 @@ export function timberFonts(ctx: PluginContext): Plugin {
367
411
  const registry: FontRegistry = new Map();
368
412
  /** Fonts downloaded during buildStart (production only). */
369
413
  let cachedFonts: CachedFont[] = [];
414
+ /**
415
+ * Pre-resolved @font-face descriptors for Google fonts, keyed by font ID.
416
+ * Populated in buildStart (production) or lazily in load (dev).
417
+ */
418
+ const googleFontFacesMap = new Map<string, FontFaceDescriptor[]>();
370
419
 
371
420
  return {
372
421
  name: 'timber-fonts',
373
422
 
374
423
  /**
375
- * Resolve `@timber/fonts/google` and `@timber/fonts/local` to virtual modules.
424
+ * Resolve `@timber/fonts/google`, `@timber/fonts/local`,
425
+ * and `virtual:timber-font-css` virtual modules.
426
+ *
427
+ * Handles \0 prefix and root prefix stripping for RSC/SSR
428
+ * environments where the RSC plugin re-imports virtual modules
429
+ * with additional prefixes.
376
430
  */
377
431
  resolveId(id: string) {
378
- if (id === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
379
- if (id === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
432
+ // Strip \0 prefix (RSC plugin re-imports)
433
+ let cleanId = id.startsWith('\0') ? id.slice(1) : id;
434
+ // Strip root prefix (SSR build entries)
435
+ if (cleanId.startsWith(ctx.root)) {
436
+ const stripped = cleanId.slice(ctx.root.length);
437
+ if (stripped.startsWith('/') || stripped.startsWith('\\')) {
438
+ cleanId = stripped.slice(1);
439
+ } else {
440
+ cleanId = stripped;
441
+ }
442
+ }
443
+
444
+ if (cleanId === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
445
+ if (cleanId === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
446
+ if (cleanId === VIRTUAL_FONT_CSS_REGISTER) return RESOLVED_FONT_CSS_REGISTER;
380
447
  return null;
381
448
  },
382
449
 
383
450
  /**
384
451
  * Return generated source for font virtual modules.
452
+ *
453
+ * `virtual:timber-font-css` exports the combined @font-face CSS
454
+ * as a string. The RSC entry imports it and inlines a <style> tag.
455
+ * Because this is loaded lazily (on first request), the font
456
+ * registry is always populated by the time it's needed.
385
457
  */
386
- load(id: string) {
458
+ async load(id: string) {
387
459
  if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
388
460
  if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
461
+
462
+ if (id === RESOLVED_FONT_CSS_REGISTER) {
463
+ // In dev mode, resolve Google font faces from CDN on demand.
464
+ if (ctx.dev) {
465
+ const googleFonts = [...registry.values()].filter((f) => f.provider === 'google');
466
+ for (const font of googleFonts) {
467
+ if (!googleFontFacesMap.has(font.id)) {
468
+ try {
469
+ const faces = await resolveDevFontFaces(font);
470
+ googleFontFacesMap.set(font.id, faces);
471
+ } catch (e) {
472
+ // In dev mode, fail gracefully — fonts fall back to system fonts.
473
+ const msg = e instanceof Error ? e.message : String(e);
474
+ console.warn(
475
+ `[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}`
476
+ );
477
+ googleFontFacesMap.set(font.id, []);
478
+ }
479
+ }
480
+ }
481
+ }
482
+
483
+ const css = generateAllFontCss(registry, googleFontFacesMap);
484
+ // Side-effect module: sets font CSS on globalThis for the RSC entry to read.
485
+ return `globalThis.__timber_font_css = ${JSON.stringify(css)};`;
486
+ }
389
487
  return null;
390
488
  },
391
489
 
@@ -412,14 +510,8 @@ export function timberFonts(ctx: PluginContext): Plugin {
412
510
  return;
413
511
  }
414
512
 
415
- // Serve generated font CSS
416
- if (requestedFilename === 'fonts.css') {
417
- const css = generateAllFontCss(registry);
418
- res.setHeader('Content-Type', 'text/css');
419
- res.setHeader('Cache-Control', 'no-cache');
420
- res.end(css);
421
- return;
422
- }
513
+ // Font CSS is now injected via Vite's CSS pipeline (virtual:timber-font-css modules).
514
+ // This middleware only serves font binary files (woff2, etc.).
423
515
 
424
516
  // Find the matching font file in the registry
425
517
  for (const font of registry.values()) {
@@ -469,6 +561,22 @@ export function timberFonts(ctx: PluginContext): Plugin {
469
561
  if (googleFonts.length === 0) return;
470
562
 
471
563
  cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
564
+
565
+ // Build a family→CachedFont[] lookup, then generate production @font-face
566
+ // descriptors for each registered Google font.
567
+ const cachedByFamily = new Map<string, CachedFont[]>();
568
+ for (const cf of cachedFonts) {
569
+ const key = cf.face.family.toLowerCase();
570
+ const arr = cachedByFamily.get(key) ?? [];
571
+ arr.push(cf);
572
+ cachedByFamily.set(key, arr);
573
+ }
574
+
575
+ for (const font of googleFonts) {
576
+ const familyCached = cachedByFamily.get(font.family.toLowerCase()) ?? [];
577
+ const faces = generateProductionFontFaces(familyCached, font.display);
578
+ googleFontFacesMap.set(font.id, faces);
579
+ }
472
580
  },
473
581
 
474
582
  /**
@@ -486,9 +594,13 @@ export function timberFonts(ctx: PluginContext): Plugin {
486
594
  if (id.startsWith('\0') || id.includes('node_modules')) return null;
487
595
 
488
596
  const hasGoogleImport =
489
- code.includes('@timber/fonts/google') || code.includes('next/font/google');
597
+ code.includes('@timber/fonts/google') ||
598
+ code.includes('@timber-js/app/fonts/google') ||
599
+ code.includes('next/font/google');
490
600
  const hasLocalImport =
491
- code.includes('@timber/fonts/local') || code.includes('next/font/local');
601
+ code.includes('@timber/fonts/local') ||
602
+ code.includes('@timber-js/app/fonts/local') ||
603
+ code.includes('next/font/local');
492
604
  if (!hasGoogleImport && !hasLocalImport) return null;
493
605
 
494
606
  let transformedCode = code;
@@ -560,7 +672,7 @@ export function timberFonts(ctx: PluginContext): Plugin {
560
672
  }
561
673
 
562
674
  transformedCode = transformedCode.replace(
563
- /import\s*\{[^}]+\}\s*from\s*['"](?:@timber\/fonts\/google|next\/font\/google)['"];?\s*\n?/g,
675
+ /import\s*\{[^}]+\}\s*from\s*['"](?:@timber\/fonts\/google|@timber-js\/app\/fonts\/google|next\/font\/google)['"];?\s*\n?/g,
564
676
  ''
565
677
  );
566
678
  }
@@ -578,9 +690,10 @@ export function timberFonts(ctx: PluginContext): Plugin {
578
690
  }
579
691
 
580
692
  if (transformedCode !== code) {
581
- // Mark that fonts are in use so the RSC entry injects a <link> tag.
582
- if (registry.size > 0 && !ctx.fontCssUrl) {
583
- ctx.fontCssUrl = FONT_CSS_PATH;
693
+ // Inject side-effect import that registers font CSS on globalThis.
694
+ // The RSC entry reads globalThis.__timber_font_css to inline a <style> tag.
695
+ if (registry.size > 0) {
696
+ transformedCode = `import '${VIRTUAL_FONT_CSS_REGISTER}';\n` + transformedCode;
584
697
  }
585
698
  return { code: transformedCode, map: null };
586
699
  }
@@ -627,15 +740,8 @@ export function timberFonts(ctx: PluginContext): Plugin {
627
740
  }
628
741
  }
629
742
 
630
- // Emit the combined font CSS as an asset
631
- const fontCss = generateAllFontCss(registry);
632
- if (fontCss) {
633
- this.emitFile({
634
- type: 'asset',
635
- fileName: '_timber/fonts/fonts.css',
636
- source: fontCss,
637
- });
638
- }
743
+ // Font CSS is emitted by Vite's CSS pipeline via virtual:timber-font-css modules.
744
+ // We only need to emit font binary files and update the build manifest here.
639
745
 
640
746
  if (!ctx.buildManifest) return;
641
747
 
@@ -11,7 +11,7 @@
11
11
  import type { Plugin } from 'vite';
12
12
  import { existsSync } from 'node:fs';
13
13
  import { join } from 'node:path';
14
- import type { PluginContext } from '#/index.js';
14
+ import type { PluginContext } from '../index.js';
15
15
 
16
16
  const MDX_EXTENSIONS = ['mdx', 'md'];
17
17
 
@@ -11,15 +11,15 @@
11
11
  import type { Plugin, ViteDevServer } from 'vite';
12
12
  import { writeFile, mkdir } from 'node:fs/promises';
13
13
  import { join } from 'node:path';
14
- import { scanRoutes } from '#/routing/scanner.js';
15
- import { generateRouteMap } from '#/routing/codegen.js';
16
- import { collectInterceptionRewrites } from '#/routing/interception.js';
14
+ import { scanRoutes } from '../routing/scanner.js';
15
+ import { generateRouteMap } from '../routing/codegen.js';
16
+ import { collectInterceptionRewrites } from '../routing/interception.js';
17
17
  import {
18
18
  lintStatusFileDirectives,
19
19
  formatStatusFileLintWarnings,
20
- } from '#/routing/status-file-lint.js';
21
- import type { RouteTree, SegmentNode, RouteFile } from '#/routing/types.js';
22
- import type { PluginContext } from '#/index.js';
20
+ } from '../routing/status-file-lint.js';
21
+ import type { RouteTree, SegmentNode, RouteFile } from '../routing/types.js';
22
+ import type { PluginContext } from '../index.js';
23
23
 
24
24
  const VIRTUAL_MODULE_ID = 'virtual:timber-route-manifest';
25
25
  const RESOLVED_VIRTUAL_ID = `\0${VIRTUAL_MODULE_ID}`;
@@ -28,7 +28,7 @@ const RESOLVED_VIRTUAL_ID = `\0${VIRTUAL_MODULE_ID}`;
28
28
  * File convention names we track for changes that require manifest regeneration.
29
29
  */
30
30
  const ROUTE_FILE_PATTERNS =
31
- /\/(page|layout|middleware|access|route|error|default|denied|search-params|\d{3}|[45]xx|not-found|forbidden|unauthorized|sitemap|robots|manifest|favicon|icon|opengraph-image|twitter-image|apple-icon)\./;
31
+ /\/(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)\./;
32
32
 
33
33
  /**
34
34
  * Create the timber-routing Vite plugin.
@@ -168,20 +168,49 @@ export function timberRouting(ctx: PluginContext): Plugin {
168
168
  // Watch the app directory
169
169
  devServer.watcher.add(ctx.appDir);
170
170
 
171
- const handleFileChange = (filePath: string) => {
172
- // Only react to route-significant files in the app directory
171
+ /** Snapshot of the last generated manifest, used to detect structural changes. */
172
+ let lastManifest = ctx.routeTree ? generateManifestModule(ctx.routeTree) : '';
173
+
174
+ /**
175
+ * Handle a route-significant file being added or removed.
176
+ * Always triggers a full-reload since the route tree structure changed.
177
+ */
178
+ const handleStructuralChange = (filePath: string) => {
173
179
  if (!filePath.startsWith(ctx.appDir)) return;
174
180
  if (!ROUTE_FILE_PATTERNS.test(filePath)) return;
175
181
 
176
- // Rescan the route tree
177
182
  rescan();
178
-
179
- // Invalidate the virtual module in all environments
183
+ lastManifest = ctx.routeTree ? generateManifestModule(ctx.routeTree) : '';
180
184
  invalidateManifest(devServer);
181
185
  };
182
186
 
183
- devServer.watcher.on('add', handleFileChange);
184
- devServer.watcher.on('unlink', handleFileChange);
187
+ /**
188
+ * Handle a route file's content changing.
189
+ *
190
+ * Most content edits (JSX changes, fixing typos) don't affect route
191
+ * metadata — Vite's React Fast Refresh handles those via normal HMR.
192
+ * Only rescan and full-reload when route metadata actually changed
193
+ * (e.g., searchParams export added/removed, metadata export changed).
194
+ */
195
+ const handleContentChange = (filePath: string) => {
196
+ if (!filePath.startsWith(ctx.appDir)) return;
197
+ if (!ROUTE_FILE_PATTERNS.test(filePath)) return;
198
+
199
+ rescan();
200
+ const newManifest = ctx.routeTree ? generateManifestModule(ctx.routeTree) : '';
201
+ if (newManifest !== lastManifest) {
202
+ lastManifest = newManifest;
203
+ invalidateManifest(devServer);
204
+ }
205
+ // Otherwise: content edit didn't change route metadata — let Vite HMR handle it
206
+ };
207
+
208
+ devServer.watcher.on('add', handleStructuralChange);
209
+ devServer.watcher.on('unlink', handleStructuralChange);
210
+ // Watch content changes to page files — searchParams detection depends
211
+ // on file contents (export const searchParams), not just file presence.
212
+ // But only full-reload when route metadata actually changes.
213
+ devServer.watcher.on('change', handleContentChange);
185
214
  // Also watch renames (which are add+unlink) — handled by the above
186
215
  },
187
216
  };
@@ -301,12 +330,15 @@ function generateManifestModule(tree: RouteTree): string {
301
330
  `${nextIndent}denied: { load: ${v}, filePath: ${JSON.stringify(node.denied.filePath)} },`
302
331
  );
303
332
  }
304
- if (node.searchParams) {
305
- const v = addImport(node.searchParams);
333
+ if (node.params) {
334
+ const v = addImport(node.params);
306
335
  parts.push(
307
- `${nextIndent}searchParams: { load: ${v}, filePath: ${JSON.stringify(node.searchParams.filePath)} },`
336
+ `${nextIndent}params: { load: ${v}, filePath: ${JSON.stringify(node.params.filePath)} },`
308
337
  );
309
338
  }
339
+ // searchParams is now a named export from page.tsx, not a separate file.
340
+ // The page module's searchParams export is loaded via the page's lazy import.
341
+ // Runtime registration happens in the route loader using the page module.
310
342
 
311
343
  // Status-code files
312
344
  if (node.statusFiles && node.statusFiles.size > 0) {
@@ -391,6 +423,13 @@ function generateManifestModule(tree: RouteTree): string {
391
423
  proxyLine = ` proxy: { load: ${v}, filePath: ${JSON.stringify(tree.proxy.filePath)} },`;
392
424
  }
393
425
 
426
+ // Global error page (Tier 2)
427
+ let globalErrorLine = '';
428
+ if (tree.globalError) {
429
+ const v = addImport(tree.globalError);
430
+ globalErrorLine = ` globalError: { load: ${v}, filePath: ${JSON.stringify(tree.globalError.filePath)} },`;
431
+ }
432
+
394
433
  // Interception rewrites — computed at build time from the route tree.
395
434
  // Only interceptedPattern and interceptingPrefix are needed at runtime.
396
435
  const rewrites = collectInterceptionRewrites(tree.root);
@@ -407,6 +446,7 @@ function generateManifestModule(tree: RouteTree): string {
407
446
  '',
408
447
  'const manifest = {',
409
448
  proxyLine,
449
+ globalErrorLine,
410
450
  rewritesLine,
411
451
  ` root: ${rootSerialized},`,
412
452
  '};',
@@ -1,7 +1,7 @@
1
1
  import type { Plugin } from 'vite';
2
2
  import { Parser } from 'acorn';
3
3
  import acornJsx from 'acorn-jsx';
4
- import { detectFileDirective } from '#/utils/directive-parser.js';
4
+ import { detectFileDirective } from '../utils/directive-parser.js';
5
5
 
6
6
  const jsxParser = Parser.extend(acornJsx());
7
7
 
@@ -137,5 +137,36 @@ export function timberServerBundle(): Plugin[] {
137
137
  },
138
138
  };
139
139
 
140
- return [bundlePlugin, esmInitFixPlugin];
140
+ // Fix Rolldown's `createRequire(import.meta.url)` CJS interop shim for
141
+ // Cloudflare Workers. Rolldown emits this for CJS dependencies (e.g.
142
+ // @opentelemetry/context-async-hooks) that use `require()`. On Workers,
143
+ // `import.meta.url` is `undefined` for non-entry modules, causing:
144
+ // TypeError: The argument 'path' must be a file URL object, a file URL
145
+ // string, or an absolute path string. Received 'undefined'
146
+ //
147
+ // The fix: provide a fallback URL when `import.meta.url` is undefined.
148
+ // The actual URL doesn't matter — `createRequire` only needs it for
149
+ // resolving relative paths, but the only `__require()` calls are for
150
+ // Node built-ins (events, async_hooks) which resolve from any base.
151
+ //
152
+ // The top-level `ssr: { target: 'webworker' }` was supposed to prevent
153
+ // this, but it doesn't propagate to custom environments (rsc) in Vite's
154
+ // Environment API. See LOCAL-405.
155
+ const createRequireFixPlugin: Plugin = {
156
+ name: 'timber-create-require-fix',
157
+ applyToEnvironment(environment) {
158
+ return environment.name === 'rsc' || environment.name === 'ssr';
159
+ },
160
+ renderChunk(code) {
161
+ const pattern = 'createRequire(import.meta.url)';
162
+ if (!code.includes(pattern)) return null;
163
+
164
+ return {
165
+ code: code.replace(pattern, 'createRequire(import.meta.url || "file:///app")'),
166
+ map: null,
167
+ };
168
+ },
169
+ };
170
+
171
+ return [bundlePlugin, esmInitFixPlugin, createRequireFixPlugin];
141
172
  }