@timber-js/app 0.2.0-alpha.2 → 0.2.0-alpha.200

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 (1329) hide show
  1. package/LICENSE +8 -0
  2. package/agent-skill.md +346 -0
  3. package/dist/_chunks/actions-d1hCqnU3.js +345 -0
  4. package/dist/_chunks/actions-d1hCqnU3.js.map +1 -0
  5. package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
  6. package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
  7. package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
  8. package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
  9. package/dist/_chunks/base-path-DaQrzbez.js +80 -0
  10. package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
  11. package/dist/_chunks/build-manifest-DTmSGLRz.js +135 -0
  12. package/dist/_chunks/build-manifest-DTmSGLRz.js.map +1 -0
  13. package/dist/_chunks/build-output-helper-9dqCv1pZ.js +370 -0
  14. package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +1 -0
  15. package/dist/_chunks/cache-api-ByagcC-J.js +1149 -0
  16. package/dist/_chunks/cache-api-ByagcC-J.js.map +1 -0
  17. package/dist/_chunks/canonicalize-CgHoscYO.js +66 -0
  18. package/dist/_chunks/canonicalize-CgHoscYO.js.map +1 -0
  19. package/dist/_chunks/chains-Bpb0W4ax.js +412 -0
  20. package/dist/_chunks/chains-Bpb0W4ax.js.map +1 -0
  21. package/dist/_chunks/cli-check-D6VolrDV.js +293 -0
  22. package/dist/_chunks/cli-check-D6VolrDV.js.map +1 -0
  23. package/dist/_chunks/cli-schema-sync-D6rO-VcS.js +299 -0
  24. package/dist/_chunks/cli-schema-sync-D6rO-VcS.js.map +1 -0
  25. package/dist/_chunks/cloudflare-BFb__LYG.js +1290 -0
  26. package/dist/_chunks/cloudflare-BFb__LYG.js.map +1 -0
  27. package/dist/_chunks/codec-registry-oOUxugz3.js +21 -0
  28. package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -0
  29. package/dist/_chunks/convention-lint-fRkwVwEH.js +893 -0
  30. package/dist/_chunks/convention-lint-fRkwVwEH.js.map +1 -0
  31. package/dist/_chunks/dist-DtrJyBbw.js +386 -0
  32. package/dist/_chunks/dist-DtrJyBbw.js.map +1 -0
  33. package/dist/_chunks/error-boundary-BfPHZjm0.js +1050 -0
  34. package/dist/_chunks/error-boundary-BfPHZjm0.js.map +1 -0
  35. package/dist/_chunks/fast-hash-C-tVYrLb.js +41 -0
  36. package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
  37. package/dist/_chunks/file-cache-Dw6BJPG7.js +458 -0
  38. package/dist/_chunks/file-cache-Dw6BJPG7.js.map +1 -0
  39. package/dist/_chunks/format-BKclgVbk.js +14 -0
  40. package/dist/_chunks/format-BKclgVbk.js.map +1 -0
  41. package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
  42. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
  43. package/dist/_chunks/graph-cache-CP4GEmf9.js +304 -0
  44. package/dist/_chunks/graph-cache-CP4GEmf9.js.map +1 -0
  45. package/dist/_chunks/href-validation-BIrxavIy.js +213 -0
  46. package/dist/_chunks/href-validation-BIrxavIy.js.map +1 -0
  47. package/dist/_chunks/json-lossy-check-ClNvBM_3.js +63 -0
  48. package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +1 -0
  49. package/dist/_chunks/live-graph-D_2D32Ad.js +150 -0
  50. package/dist/_chunks/live-graph-D_2D32Ad.js.map +1 -0
  51. package/dist/_chunks/logger-uLBuGKDI.js +1484 -0
  52. package/dist/_chunks/logger-uLBuGKDI.js.map +1 -0
  53. package/dist/_chunks/navigation-context-D0TU0Jog.js +135 -0
  54. package/dist/_chunks/navigation-context-D0TU0Jog.js.map +1 -0
  55. package/dist/_chunks/navigation-root-mHSK9psY.js +126 -0
  56. package/dist/_chunks/navigation-root-mHSK9psY.js.map +1 -0
  57. package/dist/_chunks/param-value-C8TNYchQ.js +66 -0
  58. package/dist/_chunks/param-value-C8TNYchQ.js.map +1 -0
  59. package/dist/_chunks/plugin-context-8idfR3UZ.js +321 -0
  60. package/dist/_chunks/plugin-context-8idfR3UZ.js.map +1 -0
  61. package/dist/_chunks/poison-rules-DoEhbqaY.js +110 -0
  62. package/dist/_chunks/poison-rules-DoEhbqaY.js.map +1 -0
  63. package/dist/_chunks/poison-scan-Bm9Yyqk9.js +101 -0
  64. package/dist/_chunks/poison-scan-Bm9Yyqk9.js.map +1 -0
  65. package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
  66. package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
  67. package/dist/_chunks/resolve-schema-CBR6Lm4i.js +50 -0
  68. package/dist/_chunks/resolve-schema-CBR6Lm4i.js.map +1 -0
  69. package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  70. package/dist/_chunks/rsc-cache-key-ClUiXQnK.js +243 -0
  71. package/dist/_chunks/rsc-cache-key-ClUiXQnK.js.map +1 -0
  72. package/dist/_chunks/rsc-media-type-DDc7duTD.js +61 -0
  73. package/dist/_chunks/rsc-media-type-DDc7duTD.js.map +1 -0
  74. package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
  75. package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
  76. package/dist/_chunks/scan-BoP17W3w.js +140 -0
  77. package/dist/_chunks/scan-BoP17W3w.js.map +1 -0
  78. package/dist/_chunks/scanner-AiazgH_f.js +1771 -0
  79. package/dist/_chunks/scanner-AiazgH_f.js.map +1 -0
  80. package/dist/_chunks/schema-bridge-C83xa9lT.js +199 -0
  81. package/dist/_chunks/schema-bridge-C83xa9lT.js.map +1 -0
  82. package/dist/_chunks/segment-classify-C539Pa2O.js +197 -0
  83. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
  84. package/dist/_chunks/segment-context-D9_89u34.js +34 -0
  85. package/dist/_chunks/segment-context-D9_89u34.js.map +1 -0
  86. package/dist/_chunks/segment-keys-lqtdookO.js +256 -0
  87. package/dist/_chunks/segment-keys-lqtdookO.js.map +1 -0
  88. package/dist/_chunks/singleflight-2lUWfcAk.js +54 -0
  89. package/dist/_chunks/singleflight-2lUWfcAk.js.map +1 -0
  90. package/dist/_chunks/sizeof-lXffQ1Vr.js +35 -0
  91. package/dist/_chunks/sizeof-lXffQ1Vr.js.map +1 -0
  92. package/dist/_chunks/{ssr-data-DLnbYpj1.js → ssr-data-D6T6Y3ef.js} +3 -31
  93. package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +1 -0
  94. package/dist/_chunks/state-FippDgxN.js +52 -0
  95. package/dist/_chunks/state-FippDgxN.js.map +1 -0
  96. package/dist/_chunks/status-page-marker-DwQBrLBz.js +496 -0
  97. package/dist/_chunks/status-page-marker-DwQBrLBz.js.map +1 -0
  98. package/dist/_chunks/use-query-states-I3JMng6J.js +226 -0
  99. package/dist/_chunks/use-query-states-I3JMng6J.js.map +1 -0
  100. package/dist/_chunks/walkers-B6XUtmqK.js +144 -0
  101. package/dist/_chunks/walkers-B6XUtmqK.js.map +1 -0
  102. package/dist/adapters/build-output-helper.d.ts +72 -0
  103. package/dist/adapters/build-output-helper.d.ts.map +1 -0
  104. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  105. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  106. package/dist/adapters/cloudflare-dev.js +74 -0
  107. package/dist/adapters/cloudflare-dev.js.map +1 -0
  108. package/dist/adapters/cloudflare-kv-cache.d.ts +65 -0
  109. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  110. package/dist/adapters/cloudflare-kv-cache.js +123 -0
  111. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  112. package/dist/adapters/cloudflare.d.ts +200 -22
  113. package/dist/adapters/cloudflare.d.ts.map +1 -1
  114. package/dist/adapters/cloudflare.js +2 -188
  115. package/dist/adapters/compress-module.d.ts +17 -4
  116. package/dist/adapters/compress-module.d.ts.map +1 -1
  117. package/dist/adapters/fs-identity.d.ts +64 -0
  118. package/dist/adapters/fs-identity.d.ts.map +1 -0
  119. package/dist/adapters/nitro-presets.d.ts +37 -0
  120. package/dist/adapters/nitro-presets.d.ts.map +1 -0
  121. package/dist/adapters/nitro-preview.d.ts +32 -0
  122. package/dist/adapters/nitro-preview.d.ts.map +1 -0
  123. package/dist/adapters/nitro.d.ts +82 -37
  124. package/dist/adapters/nitro.d.ts.map +1 -1
  125. package/dist/adapters/nitro.js +457 -288
  126. package/dist/adapters/nitro.js.map +1 -1
  127. package/dist/adapters/shared.d.ts +62 -0
  128. package/dist/adapters/shared.d.ts.map +1 -0
  129. package/dist/adapters/types.d.ts +28 -6
  130. package/dist/adapters/types.d.ts.map +1 -1
  131. package/dist/analyze/chains.d.ts +124 -0
  132. package/dist/analyze/chains.d.ts.map +1 -0
  133. package/dist/analyze/classify.d.ts +150 -0
  134. package/dist/analyze/classify.d.ts.map +1 -0
  135. package/dist/analyze/crawl-entry.d.ts +17 -0
  136. package/dist/analyze/crawl-entry.d.ts.map +1 -0
  137. package/dist/analyze/crawl-entry.js +313 -0
  138. package/dist/analyze/crawl-entry.js.map +1 -0
  139. package/dist/analyze/crawl.d.ts +134 -0
  140. package/dist/analyze/crawl.d.ts.map +1 -0
  141. package/dist/analyze/graph-cache.d.ts +104 -0
  142. package/dist/analyze/graph-cache.d.ts.map +1 -0
  143. package/dist/analyze/graph-command.d.ts +43 -0
  144. package/dist/analyze/graph-command.d.ts.map +1 -0
  145. package/dist/analyze/graph-command.js +472 -0
  146. package/dist/analyze/graph-command.js.map +1 -0
  147. package/dist/analyze/live-graph.d.ts +81 -0
  148. package/dist/analyze/live-graph.d.ts.map +1 -0
  149. package/dist/analyze/poison-rules.d.ts +72 -0
  150. package/dist/analyze/poison-rules.d.ts.map +1 -0
  151. package/dist/analyze/poison-scan.d.ts +48 -0
  152. package/dist/analyze/poison-scan.d.ts.map +1 -0
  153. package/dist/analyze/scan.d.ts +73 -0
  154. package/dist/analyze/scan.d.ts.map +1 -0
  155. package/dist/cache/cache-api.d.ts +48 -0
  156. package/dist/cache/cache-api.d.ts.map +1 -0
  157. package/dist/cache/fast-hash.d.ts +27 -0
  158. package/dist/cache/fast-hash.d.ts.map +1 -0
  159. package/dist/cache/handler-store.d.ts +33 -0
  160. package/dist/cache/handler-store.d.ts.map +1 -0
  161. package/dist/cache/index.d.ts +32 -9
  162. package/dist/cache/index.d.ts.map +1 -1
  163. package/dist/cache/index.js +3 -284
  164. package/dist/cache/invalidation-epoch.d.ts +43 -0
  165. package/dist/cache/invalidation-epoch.d.ts.map +1 -0
  166. package/dist/cache/json-lossy-check.d.ts +11 -0
  167. package/dist/cache/json-lossy-check.d.ts.map +1 -0
  168. package/dist/cache/redis-handler.d.ts +141 -9
  169. package/dist/cache/redis-handler.d.ts.map +1 -1
  170. package/dist/cache/singleflight.d.ts +21 -2
  171. package/dist/cache/singleflight.d.ts.map +1 -1
  172. package/dist/cache/sizeof.d.ts +22 -0
  173. package/dist/cache/sizeof.d.ts.map +1 -0
  174. package/dist/cache/stable-stringify.d.ts +9 -0
  175. package/dist/cache/stable-stringify.d.ts.map +1 -1
  176. package/dist/cache/store.d.ts +53 -0
  177. package/dist/cache/store.d.ts.map +1 -0
  178. package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
  179. package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
  180. package/dist/cache/stores/cloudflare-kv.js +29 -0
  181. package/dist/cache/stores/cloudflare-kv.js.map +1 -0
  182. package/dist/cache/stores/memory.d.ts +42 -0
  183. package/dist/cache/stores/memory.d.ts.map +1 -0
  184. package/dist/cache/stores/memory.js +90 -0
  185. package/dist/cache/stores/memory.js.map +1 -0
  186. package/dist/cache/stores/redis.d.ts +69 -0
  187. package/dist/cache/stores/redis.d.ts.map +1 -0
  188. package/dist/cache/stores/redis.js +35 -0
  189. package/dist/cache/stores/redis.js.map +1 -0
  190. package/dist/cache/stores/vercel.d.ts +36 -0
  191. package/dist/cache/stores/vercel.d.ts.map +1 -0
  192. package/dist/cache/stores/vercel.js +33 -0
  193. package/dist/cache/stores/vercel.js.map +1 -0
  194. package/dist/cache/tag-aware-handler.d.ts +52 -0
  195. package/dist/cache/tag-aware-handler.d.ts.map +1 -0
  196. package/dist/cache/timber-cache.d.ts +21 -11
  197. package/dist/cache/timber-cache.d.ts.map +1 -1
  198. package/dist/cdn/cloudflare-purge.d.ts +23 -0
  199. package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
  200. package/dist/cdn/cloudflare-purge.js +30 -0
  201. package/dist/cdn/cloudflare-purge.js.map +1 -0
  202. package/dist/cdn/fastly-purge.d.ts +25 -0
  203. package/dist/cdn/fastly-purge.d.ts.map +1 -0
  204. package/dist/cdn/fastly-purge.js +33 -0
  205. package/dist/cdn/fastly-purge.js.map +1 -0
  206. package/dist/cdn/headers.d.ts +97 -0
  207. package/dist/cdn/headers.d.ts.map +1 -0
  208. package/dist/cdn/index.d.ts +5 -0
  209. package/dist/cdn/index.d.ts.map +1 -0
  210. package/dist/cdn/index.js +94 -0
  211. package/dist/cdn/index.js.map +1 -0
  212. package/dist/cdn/purge-store.d.ts +23 -0
  213. package/dist/cdn/purge-store.d.ts.map +1 -0
  214. package/dist/cdn/workers-cache-purge.d.ts +20 -0
  215. package/dist/cdn/workers-cache-purge.d.ts.map +1 -0
  216. package/dist/cdn/workers-cache-purge.js +35 -0
  217. package/dist/cdn/workers-cache-purge.js.map +1 -0
  218. package/dist/cli-check.d.ts +163 -0
  219. package/dist/cli-check.d.ts.map +1 -0
  220. package/dist/cli-schema-sync.d.ts +59 -0
  221. package/dist/cli-schema-sync.d.ts.map +1 -0
  222. package/dist/cli.d.ts +75 -8
  223. package/dist/cli.d.ts.map +1 -1
  224. package/dist/cli.js +175 -47
  225. package/dist/cli.js.map +1 -1
  226. package/dist/client/browser-dev.d.ts +37 -1
  227. package/dist/client/browser-dev.d.ts.map +1 -1
  228. package/dist/client/browser-entry/action-dispatch.d.ts +19 -0
  229. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  230. package/dist/client/browser-entry/action-queue.d.ts +44 -0
  231. package/dist/client/browser-entry/action-queue.d.ts.map +1 -0
  232. package/dist/client/browser-entry/hmr.d.ts +21 -0
  233. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  234. package/dist/client/browser-entry/hydrate.d.ts +63 -0
  235. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  236. package/dist/client/browser-entry/index.d.ts +30 -0
  237. package/dist/client/browser-entry/index.d.ts.map +1 -0
  238. package/dist/client/browser-entry/post-hydration.d.ts +29 -0
  239. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  240. package/dist/client/browser-entry/router-init.d.ts +46 -0
  241. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  242. package/dist/client/browser-entry/rsc-stream.d.ts +32 -0
  243. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  244. package/dist/client/browser-entry/scroll.d.ts +28 -0
  245. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  246. package/dist/client/deny-last-resort.d.ts +29 -0
  247. package/dist/client/deny-last-resort.d.ts.map +1 -0
  248. package/dist/client/error-boundary.d.ts +66 -6
  249. package/dist/client/error-boundary.d.ts.map +1 -1
  250. package/dist/client/error-boundary.js +2 -126
  251. package/dist/client/error-reconstituter.d.ts +61 -0
  252. package/dist/client/error-reconstituter.d.ts.map +1 -0
  253. package/dist/client/form.d.ts +16 -27
  254. package/dist/client/form.d.ts.map +1 -1
  255. package/dist/client/global-context.d.ts +15 -0
  256. package/dist/client/global-context.d.ts.map +1 -0
  257. package/dist/client/history.d.ts +50 -9
  258. package/dist/client/history.d.ts.map +1 -1
  259. package/dist/client/index.d.ts +20 -33
  260. package/dist/client/index.d.ts.map +1 -1
  261. package/dist/client/index.js +323 -1148
  262. package/dist/client/index.js.map +1 -1
  263. package/dist/client/internal.d.ts +20 -0
  264. package/dist/client/internal.d.ts.map +1 -0
  265. package/dist/client/internal.js +818 -0
  266. package/dist/client/internal.js.map +1 -0
  267. package/dist/client/link.d.ts +63 -60
  268. package/dist/client/link.d.ts.map +1 -1
  269. package/dist/client/location-search.d.ts +12 -0
  270. package/dist/client/location-search.d.ts.map +1 -0
  271. package/dist/client/navigation-api.d.ts +121 -0
  272. package/dist/client/navigation-api.d.ts.map +1 -0
  273. package/dist/client/navigation-commit.d.ts +98 -0
  274. package/dist/client/navigation-commit.d.ts.map +1 -0
  275. package/dist/client/navigation-context.d.ts +51 -31
  276. package/dist/client/navigation-context.d.ts.map +1 -1
  277. package/dist/client/navigation-root.d.ts +98 -0
  278. package/dist/client/navigation-root.d.ts.map +1 -0
  279. package/dist/client/navigation-transition.d.ts +187 -0
  280. package/dist/client/navigation-transition.d.ts.map +1 -0
  281. package/dist/client/nuqs-adapter.d.ts +1 -1
  282. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  283. package/dist/client/params-context.d.ts +81 -0
  284. package/dist/client/params-context.d.ts.map +1 -0
  285. package/dist/client/react-root.d.ts +44 -0
  286. package/dist/client/react-root.d.ts.map +1 -0
  287. package/dist/client/router-effects.d.ts +130 -0
  288. package/dist/client/router-effects.d.ts.map +1 -0
  289. package/dist/client/router-lifecycle.d.ts +98 -0
  290. package/dist/client/router-lifecycle.d.ts.map +1 -0
  291. package/dist/client/router-pipeline.d.ts +87 -0
  292. package/dist/client/router-pipeline.d.ts.map +1 -0
  293. package/dist/client/router-ref.d.ts +2 -2
  294. package/dist/client/router-ref.d.ts.map +1 -1
  295. package/dist/client/router-skew.d.ts +21 -0
  296. package/dist/client/router-skew.d.ts.map +1 -0
  297. package/dist/client/router-types.d.ts +272 -0
  298. package/dist/client/router-types.d.ts.map +1 -0
  299. package/dist/client/router.d.ts +1 -97
  300. package/dist/client/router.d.ts.map +1 -1
  301. package/dist/client/rsc-fetch.d.ts +104 -26
  302. package/dist/client/rsc-fetch.d.ts.map +1 -1
  303. package/dist/client/segment-cache.d.ts +161 -25
  304. package/dist/client/segment-cache.d.ts.map +1 -1
  305. package/dist/client/segment-context.d.ts +1 -1
  306. package/dist/client/segment-context.d.ts.map +1 -1
  307. package/dist/client/segment-outlet.d.ts +68 -0
  308. package/dist/client/segment-outlet.d.ts.map +1 -0
  309. package/dist/client/segment-update-context.d.ts +15 -0
  310. package/dist/client/segment-update-context.d.ts.map +1 -0
  311. package/dist/client/shallow-url.d.ts +10 -0
  312. package/dist/client/shallow-url.d.ts.map +1 -0
  313. package/dist/client/slot-content-cache-context.d.ts +35 -0
  314. package/dist/client/slot-content-cache-context.d.ts.map +1 -0
  315. package/dist/client/slot-context.d.ts +31 -0
  316. package/dist/client/slot-context.d.ts.map +1 -0
  317. package/dist/client/slot-outlet.d.ts +16 -0
  318. package/dist/client/slot-outlet.d.ts.map +1 -0
  319. package/dist/client/slot-provider.d.ts +25 -0
  320. package/dist/client/slot-provider.d.ts.map +1 -0
  321. package/dist/client/ssr-data.d.ts +29 -7
  322. package/dist/client/ssr-data.d.ts.map +1 -1
  323. package/dist/client/stale-client.d.ts +69 -0
  324. package/dist/client/stale-client.d.ts.map +1 -0
  325. package/dist/client/state.d.ts +19 -8
  326. package/dist/client/state.d.ts.map +1 -1
  327. package/dist/client/status-page-marker.d.ts +25 -0
  328. package/dist/client/status-page-marker.d.ts.map +1 -0
  329. package/dist/client/top-loader.d.ts +7 -6
  330. package/dist/client/top-loader.d.ts.map +1 -1
  331. package/dist/client/unload-guard.d.ts +5 -0
  332. package/dist/client/unload-guard.d.ts.map +1 -1
  333. package/dist/client/use-cookie.d.ts +12 -0
  334. package/dist/client/use-cookie.d.ts.map +1 -1
  335. package/dist/client/use-link-status.d.ts +5 -5
  336. package/dist/client/use-link-status.d.ts.map +1 -1
  337. package/dist/client/use-pathname.d.ts +13 -11
  338. package/dist/client/use-pathname.d.ts.map +1 -1
  339. package/dist/client/use-pending-navigation.d.ts +23 -0
  340. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  341. package/dist/client/use-query-states.d.ts +10 -4
  342. package/dist/client/use-query-states.d.ts.map +1 -1
  343. package/dist/client/use-router.d.ts +2 -2
  344. package/dist/client/use-router.d.ts.map +1 -1
  345. package/dist/client/use-search-params.d.ts +15 -8
  346. package/dist/client/use-search-params.d.ts.map +1 -1
  347. package/dist/client/use-segment-params.d.ts +55 -0
  348. package/dist/client/use-segment-params.d.ts.map +1 -0
  349. package/dist/codec.d.ts +69 -0
  350. package/dist/codec.d.ts.map +1 -0
  351. package/dist/codec.js +76 -0
  352. package/dist/codec.js.map +1 -0
  353. package/dist/config-types.d.ts +322 -0
  354. package/dist/config-types.d.ts.map +1 -0
  355. package/dist/config-validation.d.ts +51 -0
  356. package/dist/config-validation.d.ts.map +1 -0
  357. package/dist/cookies/define-cookie.d.ts +58 -25
  358. package/dist/cookies/define-cookie.d.ts.map +1 -1
  359. package/dist/cookies/index.d.ts +3 -2
  360. package/dist/cookies/index.d.ts.map +1 -1
  361. package/dist/cookies/index.js +256 -36
  362. package/dist/cookies/index.js.map +1 -1
  363. package/dist/cookies/json-cookie.d.ts +64 -0
  364. package/dist/cookies/json-cookie.d.ts.map +1 -0
  365. package/dist/cookies/validation.d.ts +34 -0
  366. package/dist/cookies/validation.d.ts.map +1 -0
  367. package/dist/dev-tools/404-page.d.ts +50 -0
  368. package/dist/dev-tools/404-page.d.ts.map +1 -0
  369. package/dist/dev-tools/browser-logs.d.ts +40 -0
  370. package/dist/dev-tools/browser-logs.d.ts.map +1 -0
  371. package/dist/dev-tools/dev-page-shell.d.ts +78 -0
  372. package/dist/dev-tools/dev-page-shell.d.ts.map +1 -0
  373. package/dist/dev-tools/error-page.d.ts +32 -0
  374. package/dist/dev-tools/error-page.d.ts.map +1 -0
  375. package/dist/dev-tools/holding-server.d.ts +46 -0
  376. package/dist/dev-tools/holding-server.d.ts.map +1 -0
  377. package/dist/dev-tools/hydration-overlay.d.ts +11 -0
  378. package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
  379. package/dist/dev-tools/index.d.ts +31 -0
  380. package/dist/dev-tools/index.d.ts.map +1 -0
  381. package/dist/dev-tools/instrumentation.d.ts +59 -0
  382. package/dist/dev-tools/instrumentation.d.ts.map +1 -0
  383. package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
  384. package/dist/dev-tools/logger.d.ts.map +1 -0
  385. package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +17 -3
  386. package/dist/dev-tools/logs.d.ts.map +1 -0
  387. package/dist/dev-tools/overlay.d.ts +91 -0
  388. package/dist/dev-tools/overlay.d.ts.map +1 -0
  389. package/dist/dev-tools/stack-classifier.d.ts +34 -0
  390. package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
  391. package/dist/dev-tools/terminal.d.ts +28 -0
  392. package/dist/dev-tools/terminal.d.ts.map +1 -0
  393. package/dist/fonts/ast-walk.d.ts +68 -0
  394. package/dist/fonts/ast-walk.d.ts.map +1 -0
  395. package/dist/fonts/ast.d.ts +112 -8
  396. package/dist/fonts/ast.d.ts.map +1 -1
  397. package/dist/fonts/bundle.d.ts +50 -0
  398. package/dist/fonts/bundle.d.ts.map +1 -0
  399. package/dist/fonts/css.d.ts +2 -1
  400. package/dist/fonts/css.d.ts.map +1 -1
  401. package/dist/fonts/dev-middleware.d.ts +22 -0
  402. package/dist/fonts/dev-middleware.d.ts.map +1 -0
  403. package/dist/fonts/fallbacks.d.ts +0 -7
  404. package/dist/fonts/fallbacks.d.ts.map +1 -1
  405. package/dist/fonts/google.d.ts +5 -3
  406. package/dist/fonts/google.d.ts.map +1 -1
  407. package/dist/fonts/local.d.ts +6 -4
  408. package/dist/fonts/local.d.ts.map +1 -1
  409. package/dist/fonts/paths.d.ts +43 -0
  410. package/dist/fonts/paths.d.ts.map +1 -0
  411. package/dist/fonts/pipeline.d.ts +177 -0
  412. package/dist/fonts/pipeline.d.ts.map +1 -0
  413. package/dist/fonts/transform.d.ts +82 -0
  414. package/dist/fonts/transform.d.ts.map +1 -0
  415. package/dist/fonts/types.d.ts +47 -1
  416. package/dist/fonts/types.d.ts.map +1 -1
  417. package/dist/fonts/virtual-modules.d.ts +77 -0
  418. package/dist/fonts/virtual-modules.d.ts.map +1 -0
  419. package/dist/index.d.ts +35 -153
  420. package/dist/index.d.ts.map +1 -1
  421. package/dist/index.js +10488 -13975
  422. package/dist/index.js.map +1 -1
  423. package/dist/params/codec-registry.d.ts +26 -0
  424. package/dist/params/codec-registry.d.ts.map +1 -0
  425. package/dist/params/define-schema.d.ts +81 -0
  426. package/dist/params/define-schema.d.ts.map +1 -0
  427. package/dist/params/index.d.ts +5 -0
  428. package/dist/params/index.d.ts.map +1 -0
  429. package/dist/params/index.js +34 -0
  430. package/dist/params/index.js.map +1 -0
  431. package/dist/params/resolve-schema.d.ts +34 -0
  432. package/dist/params/resolve-schema.d.ts.map +1 -0
  433. package/dist/plugin-context.d.ts +276 -0
  434. package/dist/plugin-context.d.ts.map +1 -0
  435. package/dist/plugins/adapter-build.d.ts +21 -1
  436. package/dist/plugins/adapter-build.d.ts.map +1 -1
  437. package/dist/plugins/build-manifest.d.ts +7 -3
  438. package/dist/plugins/build-manifest.d.ts.map +1 -1
  439. package/dist/plugins/build-report.d.ts +54 -7
  440. package/dist/plugins/build-report.d.ts.map +1 -1
  441. package/dist/plugins/cache.d.ts +64 -0
  442. package/dist/plugins/cache.d.ts.map +1 -0
  443. package/dist/plugins/callsite-ast.d.ts +117 -0
  444. package/dist/plugins/callsite-ast.d.ts.map +1 -0
  445. package/dist/plugins/callsite-jsx.d.ts +35 -0
  446. package/dist/plugins/callsite-jsx.d.ts.map +1 -0
  447. package/dist/plugins/chunks.d.ts +11 -4
  448. package/dist/plugins/chunks.d.ts.map +1 -1
  449. package/dist/plugins/client-chunks.d.ts +40 -0
  450. package/dist/plugins/client-chunks.d.ts.map +1 -0
  451. package/dist/plugins/cloudflare-wasm.d.ts +21 -0
  452. package/dist/plugins/cloudflare-wasm.d.ts.map +1 -0
  453. package/dist/plugins/content.d.ts +1 -1
  454. package/dist/plugins/content.d.ts.map +1 -1
  455. package/dist/plugins/dev-discovery.d.ts +123 -0
  456. package/dist/plugins/dev-discovery.d.ts.map +1 -0
  457. package/dist/plugins/dev-server.d.ts +17 -1
  458. package/dist/plugins/dev-server.d.ts.map +1 -1
  459. package/dist/plugins/entries.d.ts +32 -1
  460. package/dist/plugins/entries.d.ts.map +1 -1
  461. package/dist/plugins/fonts.d.ts +16 -65
  462. package/dist/plugins/fonts.d.ts.map +1 -1
  463. package/dist/plugins/graph-endpoint.d.ts +112 -0
  464. package/dist/plugins/graph-endpoint.d.ts.map +1 -0
  465. package/dist/plugins/mdx.d.ts +24 -5
  466. package/dist/plugins/mdx.d.ts.map +1 -1
  467. package/dist/plugins/prebuilt-capture.d.ts +60 -0
  468. package/dist/plugins/prebuilt-capture.d.ts.map +1 -0
  469. package/dist/plugins/prebuilt-options-analysis.d.ts +40 -0
  470. package/dist/plugins/prebuilt-options-analysis.d.ts.map +1 -0
  471. package/dist/plugins/prebuilt.d.ts +82 -0
  472. package/dist/plugins/prebuilt.d.ts.map +1 -0
  473. package/dist/plugins/prerender-sugar.d.ts +39 -0
  474. package/dist/plugins/prerender-sugar.d.ts.map +1 -0
  475. package/dist/plugins/request-dep/analysis.d.ts +106 -0
  476. package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
  477. package/dist/plugins/request-dep/index.d.ts +75 -0
  478. package/dist/plugins/request-dep/index.d.ts.map +1 -0
  479. package/dist/plugins/request-dep/origin.d.ts +61 -0
  480. package/dist/plugins/request-dep/origin.d.ts.map +1 -0
  481. package/dist/plugins/routing.d.ts +1 -1
  482. package/dist/plugins/routing.d.ts.map +1 -1
  483. package/dist/plugins/server-bundle.d.ts.map +1 -1
  484. package/dist/plugins/shims.d.ts +29 -5
  485. package/dist/plugins/shims.d.ts.map +1 -1
  486. package/dist/plugins/static-build.d.ts +218 -21
  487. package/dist/plugins/static-build.d.ts.map +1 -1
  488. package/dist/routing/codegen-shared.d.ts +26 -0
  489. package/dist/routing/codegen-shared.d.ts.map +1 -0
  490. package/dist/routing/codegen-types.d.ts +61 -0
  491. package/dist/routing/codegen-types.d.ts.map +1 -0
  492. package/dist/routing/codegen-write.d.ts +51 -0
  493. package/dist/routing/codegen-write.d.ts.map +1 -0
  494. package/dist/routing/codegen.d.ts +8 -3
  495. package/dist/routing/codegen.d.ts.map +1 -1
  496. package/dist/routing/collision-probe.d.ts +104 -0
  497. package/dist/routing/collision-probe.d.ts.map +1 -0
  498. package/dist/routing/collision-spaces.d.ts +26 -0
  499. package/dist/routing/collision-spaces.d.ts.map +1 -0
  500. package/dist/routing/convention-lint.d.ts +55 -0
  501. package/dist/routing/convention-lint.d.ts.map +1 -0
  502. package/dist/routing/export-detect.d.ts +72 -0
  503. package/dist/routing/export-detect.d.ts.map +1 -0
  504. package/dist/routing/file-cache.d.ts +8 -0
  505. package/dist/routing/file-cache.d.ts.map +1 -0
  506. package/dist/routing/index.d.ts +13 -7
  507. package/dist/routing/index.d.ts.map +1 -1
  508. package/dist/routing/index.js +5 -2
  509. package/dist/routing/interception-overlap.d.ts +35 -0
  510. package/dist/routing/interception-overlap.d.ts.map +1 -0
  511. package/dist/routing/interception.d.ts +234 -10
  512. package/dist/routing/interception.d.ts.map +1 -1
  513. package/dist/routing/link-codegen.d.ts +105 -0
  514. package/dist/routing/link-codegen.d.ts.map +1 -0
  515. package/dist/routing/manifest-codegen.d.ts +26 -0
  516. package/dist/routing/manifest-codegen.d.ts.map +1 -0
  517. package/dist/routing/scanner.d.ts +14 -10
  518. package/dist/routing/scanner.d.ts.map +1 -1
  519. package/dist/routing/schema-validation.d.ts +35 -0
  520. package/dist/routing/schema-validation.d.ts.map +1 -0
  521. package/dist/routing/segment-classify.d.ts +114 -0
  522. package/dist/routing/segment-classify.d.ts.map +1 -0
  523. package/dist/routing/segment-codegen.d.ts +38 -0
  524. package/dist/routing/segment-codegen.d.ts.map +1 -0
  525. package/dist/routing/segment-keys.d.ts +118 -0
  526. package/dist/routing/segment-keys.d.ts.map +1 -0
  527. package/dist/routing/slot-placement.d.ts +48 -0
  528. package/dist/routing/slot-placement.d.ts.map +1 -0
  529. package/dist/routing/types.d.ts +74 -26
  530. package/dist/routing/types.d.ts.map +1 -1
  531. package/dist/routing/walkers.d.ts +57 -0
  532. package/dist/routing/walkers.d.ts.map +1 -0
  533. package/dist/rsc-runtime/rsc.d.ts +1 -1
  534. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  535. package/dist/rsc-runtime/ssr.d.ts +14 -0
  536. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  537. package/dist/rsc-runtime/transforms.d.ts +13 -0
  538. package/dist/rsc-runtime/transforms.d.ts.map +1 -0
  539. package/dist/schema-bridge.d.ts +145 -0
  540. package/dist/schema-bridge.d.ts.map +1 -0
  541. package/dist/search-params/define.d.ts +262 -0
  542. package/dist/search-params/define.d.ts.map +1 -0
  543. package/dist/search-params/index.d.ts +3 -7
  544. package/dist/search-params/index.d.ts.map +1 -1
  545. package/dist/search-params/index.js +179 -360
  546. package/dist/search-params/index.js.map +1 -1
  547. package/dist/search-params/parse-total.d.ts +81 -0
  548. package/dist/search-params/parse-total.d.ts.map +1 -0
  549. package/dist/search-params/serialize-equal.d.ts +9 -0
  550. package/dist/search-params/serialize-equal.d.ts.map +1 -0
  551. package/dist/search-params/wrappers.d.ts +76 -0
  552. package/dist/search-params/wrappers.d.ts.map +1 -0
  553. package/dist/server/access-gate.d.ts +98 -10
  554. package/dist/server/access-gate.d.ts.map +1 -1
  555. package/dist/server/action-client.d.ts +42 -7
  556. package/dist/server/action-client.d.ts.map +1 -1
  557. package/dist/server/action-encryption.d.ts +76 -0
  558. package/dist/server/action-encryption.d.ts.map +1 -0
  559. package/dist/server/action-handler.d.ts +39 -5
  560. package/dist/server/action-handler.d.ts.map +1 -1
  561. package/dist/server/actions.d.ts +29 -35
  562. package/dist/server/actions.d.ts.map +1 -1
  563. package/dist/server/als-registry.d.ts +117 -13
  564. package/dist/server/als-registry.d.ts.map +1 -1
  565. package/dist/server/asset-headers.d.ts +8 -18
  566. package/dist/server/asset-headers.d.ts.map +1 -1
  567. package/dist/server/body-limits.d.ts.map +1 -1
  568. package/dist/server/build-manifest.d.ts +25 -30
  569. package/dist/server/build-manifest.d.ts.map +1 -1
  570. package/dist/server/canonicalize.d.ts +10 -0
  571. package/dist/server/canonicalize.d.ts.map +1 -1
  572. package/dist/server/chain-url-parts.d.ts +82 -0
  573. package/dist/server/chain-url-parts.d.ts.map +1 -0
  574. package/dist/server/children-interception.d.ts +49 -0
  575. package/dist/server/children-interception.d.ts.map +1 -0
  576. package/dist/server/coalesce-tick.d.ts +40 -0
  577. package/dist/server/coalesce-tick.d.ts.map +1 -0
  578. package/dist/server/compress.d.ts.map +1 -1
  579. package/dist/server/cookie-context.d.ts +170 -0
  580. package/dist/server/cookie-context.d.ts.map +1 -0
  581. package/dist/server/cookie-parsing.d.ts +65 -0
  582. package/dist/server/cookie-parsing.d.ts.map +1 -0
  583. package/dist/server/csp-nonce.d.ts +45 -0
  584. package/dist/server/csp-nonce.d.ts.map +1 -0
  585. package/dist/server/csrf.d.ts +3 -2
  586. package/dist/server/csrf.d.ts.map +1 -1
  587. package/dist/server/debug.d.ts +82 -0
  588. package/dist/server/debug.d.ts.map +1 -0
  589. package/dist/server/default-logger.d.ts +22 -0
  590. package/dist/server/default-logger.d.ts.map +1 -0
  591. package/dist/server/default-status-page.d.ts +45 -0
  592. package/dist/server/default-status-page.d.ts.map +1 -0
  593. package/dist/server/deny-boundary.d.ts +253 -0
  594. package/dist/server/deny-boundary.d.ts.map +1 -0
  595. package/dist/server/deny-renderer.d.ts +20 -9
  596. package/dist/server/deny-renderer.d.ts.map +1 -1
  597. package/dist/server/dev-source-map.d.ts +22 -0
  598. package/dist/server/dev-source-map.d.ts.map +1 -0
  599. package/dist/server/early-hints-sender.d.ts.map +1 -1
  600. package/dist/server/early-hints.d.ts +14 -12
  601. package/dist/server/early-hints.d.ts.map +1 -1
  602. package/dist/server/error-boundary-wrapper.d.ts +101 -10
  603. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  604. package/dist/server/error-response-headers.d.ts +3 -0
  605. package/dist/server/error-response-headers.d.ts.map +1 -0
  606. package/dist/server/fallback-error.d.ts +12 -7
  607. package/dist/server/fallback-error.d.ts.map +1 -1
  608. package/dist/server/flight-injection-state.d.ts +66 -0
  609. package/dist/server/flight-injection-state.d.ts.map +1 -0
  610. package/dist/server/flight-scripts.d.ts +45 -0
  611. package/dist/server/flight-scripts.d.ts.map +1 -0
  612. package/dist/server/form-data.d.ts +41 -0
  613. package/dist/server/form-data.d.ts.map +1 -1
  614. package/dist/server/form-flash.d.ts +1 -1
  615. package/dist/server/head-response.d.ts +35 -0
  616. package/dist/server/head-response.d.ts.map +1 -0
  617. package/dist/server/html-injector-core.d.ts +257 -0
  618. package/dist/server/html-injector-core.d.ts.map +1 -0
  619. package/dist/server/html-injectors.d.ts +84 -42
  620. package/dist/server/html-injectors.d.ts.map +1 -1
  621. package/dist/server/index.d.ts +18 -54
  622. package/dist/server/index.d.ts.map +1 -1
  623. package/dist/server/index.js +212 -2930
  624. package/dist/server/index.js.map +1 -1
  625. package/dist/server/instrumentation.d.ts +1 -1
  626. package/dist/server/internal.d.ts +50 -0
  627. package/dist/server/internal.d.ts.map +1 -0
  628. package/dist/server/internal.js +4034 -0
  629. package/dist/server/internal.js.map +1 -0
  630. package/dist/server/logger.d.ts +39 -7
  631. package/dist/server/logger.d.ts.map +1 -1
  632. package/dist/server/metadata-collector.d.ts +71 -0
  633. package/dist/server/metadata-collector.d.ts.map +1 -0
  634. package/dist/server/metadata-platform.d.ts +2 -2
  635. package/dist/server/metadata-render.d.ts +2 -2
  636. package/dist/server/metadata-render.d.ts.map +1 -1
  637. package/dist/server/metadata-routes.d.ts +60 -11
  638. package/dist/server/metadata-routes.d.ts.map +1 -1
  639. package/dist/server/metadata-social.d.ts +2 -2
  640. package/dist/server/metadata.d.ts +10 -2
  641. package/dist/server/metadata.d.ts.map +1 -1
  642. package/dist/server/middleware-runner.d.ts +20 -5
  643. package/dist/server/middleware-runner.d.ts.map +1 -1
  644. package/dist/server/node-stream-transforms.d.ts +105 -0
  645. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  646. package/dist/server/nuqs-ssr-provider.d.ts +7 -3
  647. package/dist/server/nuqs-ssr-provider.d.ts.map +1 -1
  648. package/dist/server/param-coercion.d.ts +78 -0
  649. package/dist/server/param-coercion.d.ts.map +1 -0
  650. package/dist/server/pipeline-helpers.d.ts +77 -0
  651. package/dist/server/pipeline-helpers.d.ts.map +1 -0
  652. package/dist/server/pipeline-interception.d.ts +59 -9
  653. package/dist/server/pipeline-interception.d.ts.map +1 -1
  654. package/dist/server/pipeline-metadata.d.ts +7 -1
  655. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  656. package/dist/server/pipeline-outcome.d.ts +49 -0
  657. package/dist/server/pipeline-outcome.d.ts.map +1 -0
  658. package/dist/server/pipeline-phases.d.ts +70 -0
  659. package/dist/server/pipeline-phases.d.ts.map +1 -0
  660. package/dist/server/pipeline.d.ts +160 -24
  661. package/dist/server/pipeline.d.ts.map +1 -1
  662. package/dist/server/port-resolution.d.ts +31 -0
  663. package/dist/server/port-resolution.d.ts.map +1 -0
  664. package/dist/server/prebuilt/cache-key.d.ts +63 -0
  665. package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
  666. package/dist/server/prebuilt/capture-state.d.ts +57 -0
  667. package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
  668. package/dist/server/prebuilt/key-discipline.d.ts +52 -0
  669. package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
  670. package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
  671. package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
  672. package/dist/server/prebuilt/overlay.d.ts +100 -0
  673. package/dist/server/prebuilt/overlay.d.ts.map +1 -0
  674. package/dist/server/prebuilt/payload-source.d.ts +79 -0
  675. package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
  676. package/dist/server/prebuilt/slots.d.ts +99 -0
  677. package/dist/server/prebuilt/slots.d.ts.map +1 -0
  678. package/dist/server/prebuilt/synthetic-store.d.ts +67 -0
  679. package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
  680. package/dist/server/prebuilt-builder.d.ts +121 -0
  681. package/dist/server/prebuilt-builder.d.ts.map +1 -0
  682. package/dist/server/prebuilt-runtime.d.ts +111 -0
  683. package/dist/server/prebuilt-runtime.d.ts.map +1 -0
  684. package/dist/server/primitives.d.ts +129 -45
  685. package/dist/server/primitives.d.ts.map +1 -1
  686. package/dist/server/publish-params.d.ts +33 -0
  687. package/dist/server/publish-params.d.ts.map +1 -0
  688. package/dist/server/render-timeout.d.ts +51 -0
  689. package/dist/server/render-timeout.d.ts.map +1 -0
  690. package/dist/server/render-utils.d.ts +26 -0
  691. package/dist/server/render-utils.d.ts.map +1 -0
  692. package/dist/server/request-context.d.ts +111 -107
  693. package/dist/server/request-context.d.ts.map +1 -1
  694. package/dist/server/request-dep.d.ts +15 -0
  695. package/dist/server/request-dep.d.ts.map +1 -0
  696. package/dist/server/response-cache-policy.d.ts +3 -0
  697. package/dist/server/response-cache-policy.d.ts.map +1 -0
  698. package/dist/server/route-element-builder.d.ts +57 -30
  699. package/dist/server/route-element-builder.d.ts.map +1 -1
  700. package/dist/server/route-element-helpers.d.ts +12 -0
  701. package/dist/server/route-element-helpers.d.ts.map +1 -0
  702. package/dist/server/route-handler.d.ts +1 -1
  703. package/dist/server/route-handler.d.ts.map +1 -1
  704. package/dist/server/route-matcher.d.ts +40 -38
  705. package/dist/server/route-matcher.d.ts.map +1 -1
  706. package/dist/server/route-module-loader.d.ts +37 -0
  707. package/dist/server/route-module-loader.d.ts.map +1 -0
  708. package/dist/server/rsc-cache-key-guard.d.ts +78 -0
  709. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
  710. package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
  711. package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
  712. package/dist/server/rsc-entry/api-handler.d.ts +12 -3
  713. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  714. package/dist/server/rsc-entry/deny-fallback.d.ts +29 -0
  715. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
  716. package/dist/server/rsc-entry/error-renderer.d.ts +38 -13
  717. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  718. package/dist/server/rsc-entry/helpers.d.ts +59 -42
  719. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  720. package/dist/server/rsc-entry/index.d.ts +40 -6
  721. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  722. package/dist/server/rsc-entry/render-route.d.ts +51 -0
  723. package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
  724. package/dist/server/rsc-entry/revalidate-renderer.d.ts +108 -0
  725. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
  726. package/dist/server/rsc-entry/rsc-payload.d.ts +26 -6
  727. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  728. package/dist/server/rsc-entry/rsc-stream.d.ts +39 -3
  729. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  730. package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
  731. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  732. package/dist/server/rsc-entry/ssr-renderer.d.ts +37 -5
  733. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  734. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +89 -0
  735. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
  736. package/dist/server/rsc-error-envelope.d.ts +11 -0
  737. package/dist/server/rsc-error-envelope.d.ts.map +1 -0
  738. package/dist/server/rsc-prop-warnings.d.ts.map +1 -1
  739. package/dist/server/safe-load.d.ts +46 -0
  740. package/dist/server/safe-load.d.ts.map +1 -0
  741. package/dist/server/sensitive-fields.d.ts +74 -0
  742. package/dist/server/sensitive-fields.d.ts.map +1 -0
  743. package/dist/server/sitemap-generator.d.ts +130 -0
  744. package/dist/server/sitemap-generator.d.ts.map +1 -0
  745. package/dist/server/sitemap-handler.d.ts +22 -0
  746. package/dist/server/sitemap-handler.d.ts.map +1 -0
  747. package/dist/server/skippable-prefix.d.ts +29 -0
  748. package/dist/server/skippable-prefix.d.ts.map +1 -0
  749. package/dist/server/slot-interception.d.ts +80 -0
  750. package/dist/server/slot-interception.d.ts.map +1 -0
  751. package/dist/server/slot-resolver.d.ts +137 -7
  752. package/dist/server/slot-resolver.d.ts.map +1 -1
  753. package/dist/server/slot-subtree-contain.d.ts +54 -0
  754. package/dist/server/slot-subtree-contain.d.ts.map +1 -0
  755. package/dist/server/ssr-bridge-types.d.ts +160 -0
  756. package/dist/server/ssr-bridge-types.d.ts.map +1 -0
  757. package/dist/server/ssr-entry.d.ts +1 -43
  758. package/dist/server/ssr-entry.d.ts.map +1 -1
  759. package/dist/server/ssr-render.d.ts +69 -22
  760. package/dist/server/ssr-render.d.ts.map +1 -1
  761. package/dist/server/ssr-wrappers.d.ts +93 -0
  762. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  763. package/dist/server/state-tree-diff.d.ts +44 -9
  764. package/dist/server/state-tree-diff.d.ts.map +1 -1
  765. package/dist/server/static-generator.d.ts +112 -0
  766. package/dist/server/static-generator.d.ts.map +1 -0
  767. package/dist/server/static-not-found.d.ts +52 -0
  768. package/dist/server/static-not-found.d.ts.map +1 -0
  769. package/dist/server/status-code-resolver.d.ts +26 -15
  770. package/dist/server/status-code-resolver.d.ts.map +1 -1
  771. package/dist/server/stream-utils.d.ts +47 -0
  772. package/dist/server/stream-utils.d.ts.map +1 -0
  773. package/dist/server/tracing.d.ts +56 -11
  774. package/dist/server/tracing.d.ts.map +1 -1
  775. package/dist/server/tree-match.d.ts +49 -0
  776. package/dist/server/tree-match.d.ts.map +1 -0
  777. package/dist/server/types.d.ts +88 -7
  778. package/dist/server/types.d.ts.map +1 -1
  779. package/dist/server/utils/element-type.d.ts +50 -0
  780. package/dist/server/utils/element-type.d.ts.map +1 -0
  781. package/dist/server/utils/escape-html.d.ts +14 -0
  782. package/dist/server/utils/escape-html.d.ts.map +1 -0
  783. package/dist/server/utils/mdx-file.d.ts +17 -0
  784. package/dist/server/utils/mdx-file.d.ts.map +1 -0
  785. package/dist/server/version-skew.d.ts +61 -0
  786. package/dist/server/version-skew.d.ts.map +1 -0
  787. package/dist/server/waituntil-bridge.d.ts.map +1 -1
  788. package/dist/server/workers-cache-bridge.d.ts +26 -0
  789. package/dist/server/workers-cache-bridge.d.ts.map +1 -0
  790. package/dist/shared/als-slots.d.ts +42 -0
  791. package/dist/shared/als-slots.d.ts.map +1 -0
  792. package/dist/shared/base-path.d.ts +56 -0
  793. package/dist/shared/base-path.d.ts.map +1 -0
  794. package/dist/shared/href-validation.d.ts +49 -0
  795. package/dist/shared/href-validation.d.ts.map +1 -0
  796. package/dist/shared/merge-search-params.d.ts +22 -0
  797. package/dist/shared/merge-search-params.d.ts.map +1 -0
  798. package/dist/shared/param-value.d.ts +104 -0
  799. package/dist/shared/param-value.d.ts.map +1 -0
  800. package/dist/shared/payload-root.d.ts +109 -0
  801. package/dist/shared/payload-root.d.ts.map +1 -0
  802. package/dist/shared/redirect-type.d.ts +17 -0
  803. package/dist/shared/redirect-type.d.ts.map +1 -0
  804. package/dist/shared/rsc-cache-key.d.ts +163 -0
  805. package/dist/shared/rsc-cache-key.d.ts.map +1 -0
  806. package/dist/shared/rsc-error-envelope.d.ts +16 -0
  807. package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
  808. package/dist/shared/rsc-manifest.d.ts +28 -0
  809. package/dist/shared/rsc-manifest.d.ts.map +1 -0
  810. package/dist/shared/rsc-media-type.d.ts +52 -0
  811. package/dist/shared/rsc-media-type.d.ts.map +1 -0
  812. package/dist/shared/rsc-payload-path.d.ts +42 -0
  813. package/dist/shared/rsc-payload-path.d.ts.map +1 -0
  814. package/dist/shared/segment-info.d.ts +66 -0
  815. package/dist/shared/segment-info.d.ts.map +1 -0
  816. package/dist/shared/slot-params.d.ts +52 -0
  817. package/dist/shared/slot-params.d.ts.map +1 -0
  818. package/dist/shared/static-platform-files.d.ts +71 -0
  819. package/dist/shared/static-platform-files.d.ts.map +1 -0
  820. package/dist/shared/status-reason-phrase.d.ts +26 -0
  821. package/dist/shared/status-reason-phrase.d.ts.map +1 -0
  822. package/dist/shims/font-google.d.ts +1 -1
  823. package/dist/shims/font-google.d.ts.map +1 -1
  824. package/dist/shims/font-google.js +42 -0
  825. package/dist/shims/font-google.js.map +1 -0
  826. package/dist/shims/font-local.d.ts +26 -0
  827. package/dist/shims/font-local.d.ts.map +1 -0
  828. package/dist/shims/font-local.js +20 -0
  829. package/dist/shims/font-local.js.map +1 -0
  830. package/dist/shims/headers.d.ts +53 -1
  831. package/dist/shims/headers.d.ts.map +1 -1
  832. package/dist/shims/image.d.ts +120 -120
  833. package/dist/shims/image.d.ts.map +1 -1
  834. package/dist/shims/navigation-client.d.ts +25 -12
  835. package/dist/shims/navigation-client.d.ts.map +1 -1
  836. package/dist/shims/navigation-rsc.d.ts +21 -0
  837. package/dist/shims/navigation-rsc.d.ts.map +1 -0
  838. package/dist/shims/navigation.d.ts +10 -5
  839. package/dist/shims/navigation.d.ts.map +1 -1
  840. package/dist/utils/state-machine.d.ts +80 -0
  841. package/dist/utils/state-machine.d.ts.map +1 -0
  842. package/docs/api/30-api-server.mdx +236 -0
  843. package/docs/api/31-api-client.mdx +167 -0
  844. package/docs/api/32-api-cache.mdx +311 -0
  845. package/docs/api/33-api-search-params.mdx +176 -0
  846. package/docs/api/34-api-config.mdx +329 -0
  847. package/docs/api/35-api-typescript.mdx +91 -0
  848. package/docs/api/36-cli.mdx +192 -0
  849. package/docs/learn/00-introduction.mdx +109 -0
  850. package/docs/learn/01-quick-start.mdx +94 -0
  851. package/docs/learn/02-pages-and-layouts.mdx +147 -0
  852. package/docs/learn/03-fetching-data.mdx +211 -0
  853. package/docs/learn/04-access-control.mdx +115 -0
  854. package/docs/learn/05-the-flush-point.mdx +175 -0
  855. package/docs/learn/06-typed-params.mdx +275 -0
  856. package/docs/learn/07-typed-routes.mdx +108 -0
  857. package/docs/learn/08-forms-and-actions.mdx +146 -0
  858. package/docs/learn/09-streaming.mdx +140 -0
  859. package/docs/learn/10-caching.mdx +252 -0
  860. package/docs/learn/11-middleware.mdx +158 -0
  861. package/docs/learn/12-error-handling.mdx +188 -0
  862. package/docs/learn/13-deploying.mdx +287 -0
  863. package/llms.txt +55 -0
  864. package/package.json +117 -29
  865. package/src/adapters/build-output-helper.ts +351 -0
  866. package/src/adapters/cloudflare-dev.ts +183 -0
  867. package/src/adapters/cloudflare-kv-cache.ts +207 -0
  868. package/src/adapters/cloudflare.ts +747 -130
  869. package/src/adapters/compress-module.ts +101 -88
  870. package/src/adapters/fs-identity.ts +156 -0
  871. package/src/adapters/nitro-presets.ts +139 -0
  872. package/src/adapters/nitro-preview.ts +340 -0
  873. package/src/adapters/nitro.ts +279 -418
  874. package/src/adapters/raw-imports.d.ts +5 -0
  875. package/src/adapters/shared.ts +274 -0
  876. package/src/adapters/types.ts +28 -7
  877. package/src/adapters/wrangler.d.ts +7 -0
  878. package/src/analyze/chains.ts +411 -0
  879. package/src/analyze/classify.ts +258 -0
  880. package/src/analyze/crawl-entry.ts +68 -0
  881. package/src/analyze/crawl.ts +500 -0
  882. package/src/analyze/graph-cache.ts +332 -0
  883. package/src/analyze/graph-command.ts +762 -0
  884. package/src/analyze/live-graph.ts +232 -0
  885. package/src/analyze/poison-rules.ts +165 -0
  886. package/src/analyze/poison-scan.ts +162 -0
  887. package/src/analyze/scan.ts +149 -0
  888. package/src/cache/cache-api.ts +107 -0
  889. package/src/cache/fast-hash.ts +39 -0
  890. package/src/cache/handler-store.ts +76 -0
  891. package/src/cache/index.ts +115 -22
  892. package/src/cache/invalidation-epoch.ts +93 -0
  893. package/src/cache/json-lossy-check.ts +75 -0
  894. package/src/cache/redis-handler.ts +198 -20
  895. package/src/cache/singleflight.ts +69 -6
  896. package/src/cache/sizeof.ts +33 -0
  897. package/src/cache/stable-stringify.ts +65 -2
  898. package/src/cache/store.ts +71 -0
  899. package/src/cache/stores/cloudflare-kv.ts +52 -0
  900. package/src/cache/stores/memory.ts +125 -0
  901. package/src/cache/stores/redis.ts +97 -0
  902. package/src/cache/stores/vercel.ts +59 -0
  903. package/src/cache/tag-aware-handler.ts +237 -0
  904. package/src/cache/timber-cache.ts +180 -48
  905. package/src/cdn/cloudflare-purge.ts +50 -0
  906. package/src/cdn/fastly-purge.ts +63 -0
  907. package/src/cdn/headers.ts +153 -0
  908. package/src/cdn/index.ts +23 -0
  909. package/src/cdn/purge-store.ts +34 -0
  910. package/src/cdn/workers-cache-purge.ts +34 -0
  911. package/src/cli-check.ts +507 -0
  912. package/src/cli-schema-sync.ts +401 -0
  913. package/src/cli.ts +262 -55
  914. package/src/client/browser-dev.ts +157 -2
  915. package/src/client/browser-entry/action-dispatch.ts +197 -0
  916. package/src/client/browser-entry/action-queue.ts +90 -0
  917. package/src/client/browser-entry/hmr.ts +70 -0
  918. package/src/client/browser-entry/hydrate.ts +148 -0
  919. package/src/client/browser-entry/index.ts +131 -0
  920. package/src/client/browser-entry/post-hydration.ts +123 -0
  921. package/src/client/browser-entry/router-init.ts +418 -0
  922. package/src/client/browser-entry/rsc-stream.ts +166 -0
  923. package/src/client/browser-entry/scroll.ts +50 -0
  924. package/src/client/deny-last-resort.tsx +54 -0
  925. package/src/client/error-boundary.tsx +316 -40
  926. package/src/client/error-reconstituter.tsx +79 -0
  927. package/src/client/form.tsx +36 -32
  928. package/src/client/global-context.ts +31 -0
  929. package/src/client/history.ts +81 -10
  930. package/src/client/index.ts +89 -53
  931. package/src/client/internal.ts +59 -0
  932. package/src/client/link.tsx +452 -159
  933. package/src/client/location-search.ts +15 -0
  934. package/src/client/navigation-api.ts +347 -0
  935. package/src/client/navigation-commit.ts +295 -0
  936. package/src/client/navigation-context.ts +67 -98
  937. package/src/client/navigation-root.tsx +224 -0
  938. package/src/client/navigation-transition.ts +327 -0
  939. package/src/client/nuqs-adapter.tsx +21 -9
  940. package/src/client/params-context.ts +187 -0
  941. package/src/client/react-root.ts +72 -0
  942. package/src/client/router-effects.ts +228 -0
  943. package/src/client/router-lifecycle.ts +354 -0
  944. package/src/client/router-pipeline.ts +490 -0
  945. package/src/client/router-ref.ts +3 -3
  946. package/src/client/router-skew.ts +30 -0
  947. package/src/client/router-types.ts +294 -0
  948. package/src/client/router.ts +436 -424
  949. package/src/client/rsc-fetch.ts +512 -73
  950. package/src/client/segment-cache.ts +327 -40
  951. package/src/client/segment-context.ts +13 -5
  952. package/src/client/segment-outlet.tsx +96 -0
  953. package/src/client/segment-update-context.ts +23 -0
  954. package/src/client/shallow-url.ts +22 -0
  955. package/src/client/slot-content-cache-context.ts +43 -0
  956. package/src/client/slot-context.ts +50 -0
  957. package/src/client/slot-outlet.tsx +22 -0
  958. package/src/client/slot-provider.tsx +32 -0
  959. package/src/client/ssr-data.ts +30 -9
  960. package/src/client/stale-client.ts +191 -0
  961. package/src/client/state.ts +29 -15
  962. package/src/client/status-page-marker.tsx +32 -0
  963. package/src/client/top-loader.tsx +36 -29
  964. package/src/client/unload-guard.ts +35 -3
  965. package/src/client/use-cookie.ts +70 -18
  966. package/src/client/use-link-status.ts +7 -7
  967. package/src/client/use-pathname.ts +22 -31
  968. package/src/client/use-pending-navigation.ts +40 -0
  969. package/src/client/use-query-states.ts +206 -36
  970. package/src/client/use-router.ts +6 -3
  971. package/src/client/use-search-params.ts +38 -49
  972. package/src/client/use-segment-params.ts +69 -0
  973. package/src/client/use-selected-layout-segment.ts +2 -2
  974. package/src/codec.ts +149 -0
  975. package/src/config-types.ts +322 -0
  976. package/src/config-validation.ts +347 -0
  977. package/src/cookies/define-cookie.ts +222 -53
  978. package/src/cookies/index.ts +13 -2
  979. package/src/cookies/json-cookie.ts +105 -0
  980. package/src/cookies/validation.ts +192 -0
  981. package/src/dev-tools/404-page.ts +286 -0
  982. package/src/dev-tools/browser-logs.ts +55 -0
  983. package/src/dev-tools/dev-page-shell.ts +260 -0
  984. package/src/dev-tools/error-page.ts +331 -0
  985. package/src/dev-tools/holding-server.ts +185 -0
  986. package/src/dev-tools/hydration-overlay.ts +158 -0
  987. package/src/dev-tools/index.ts +83 -0
  988. package/src/dev-tools/instrumentation.ts +213 -0
  989. package/src/{server/dev-logger.ts → dev-tools/logger.ts} +33 -51
  990. package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +122 -26
  991. package/src/dev-tools/overlay.ts +469 -0
  992. package/src/dev-tools/stack-classifier.ts +75 -0
  993. package/src/dev-tools/terminal.ts +182 -0
  994. package/src/fonts/ast-walk.ts +235 -0
  995. package/src/fonts/ast.ts +479 -128
  996. package/src/fonts/bundle.ts +138 -0
  997. package/src/fonts/css.ts +3 -2
  998. package/src/fonts/dev-middleware.ts +85 -0
  999. package/src/fonts/fallbacks.ts +0 -23
  1000. package/src/fonts/google.ts +101 -19
  1001. package/src/fonts/local.ts +13 -8
  1002. package/src/fonts/paths.ts +58 -0
  1003. package/src/fonts/pipeline.ts +348 -0
  1004. package/src/fonts/transform.ts +311 -0
  1005. package/src/fonts/types.ts +52 -1
  1006. package/src/fonts/virtual-modules.ts +179 -0
  1007. package/src/index.ts +486 -344
  1008. package/src/params/codec-registry.ts +34 -0
  1009. package/src/params/define-schema.ts +115 -0
  1010. package/src/params/index.ts +17 -0
  1011. package/src/params/resolve-schema.ts +84 -0
  1012. package/src/plugin-context.ts +503 -0
  1013. package/src/plugins/adapter-build.ts +229 -7
  1014. package/src/plugins/build-manifest.ts +201 -26
  1015. package/src/plugins/build-report.ts +275 -43
  1016. package/src/plugins/cache.ts +243 -0
  1017. package/src/plugins/callsite-ast.ts +472 -0
  1018. package/src/plugins/callsite-jsx.ts +243 -0
  1019. package/src/plugins/chunks.ts +74 -5
  1020. package/src/plugins/client-chunks.ts +185 -0
  1021. package/src/plugins/cloudflare-wasm.ts +141 -0
  1022. package/src/plugins/content.ts +5 -1
  1023. package/src/plugins/dev-discovery.ts +218 -0
  1024. package/src/plugins/dev-server.ts +369 -96
  1025. package/src/plugins/entries.ts +148 -18
  1026. package/src/plugins/fonts.ts +251 -524
  1027. package/src/plugins/graph-endpoint.ts +532 -0
  1028. package/src/plugins/mdx.ts +116 -40
  1029. package/src/plugins/prebuilt-capture.ts +217 -0
  1030. package/src/plugins/prebuilt-options-analysis.ts +175 -0
  1031. package/src/plugins/prebuilt.ts +655 -0
  1032. package/src/plugins/prerender-sugar.ts +320 -0
  1033. package/src/plugins/request-dep/analysis.ts +447 -0
  1034. package/src/plugins/request-dep/index.ts +376 -0
  1035. package/src/plugins/request-dep/origin.ts +310 -0
  1036. package/src/plugins/routing.ts +273 -277
  1037. package/src/plugins/server-bundle.ts +103 -14
  1038. package/src/plugins/shims.ts +259 -97
  1039. package/src/plugins/static-build.ts +708 -66
  1040. package/src/react-canary.d.ts +2 -0
  1041. package/src/routing/codegen-shared.ts +39 -0
  1042. package/src/routing/codegen-types.ts +62 -0
  1043. package/src/routing/codegen-write.ts +141 -0
  1044. package/src/routing/codegen.ts +349 -232
  1045. package/src/routing/collision-probe.ts +438 -0
  1046. package/src/routing/collision-spaces.ts +281 -0
  1047. package/src/routing/convention-lint.ts +623 -0
  1048. package/src/routing/export-detect.ts +448 -0
  1049. package/src/routing/file-cache.ts +23 -0
  1050. package/src/routing/index.ts +16 -7
  1051. package/src/routing/interception-overlap.ts +141 -0
  1052. package/src/routing/interception.ts +1044 -67
  1053. package/src/routing/link-codegen.ts +280 -0
  1054. package/src/routing/manifest-codegen.ts +226 -0
  1055. package/src/routing/scanner.ts +393 -219
  1056. package/src/routing/schema-validation.ts +155 -0
  1057. package/src/routing/segment-classify.ts +280 -0
  1058. package/src/routing/segment-codegen.ts +98 -0
  1059. package/src/routing/segment-keys.ts +186 -0
  1060. package/src/routing/slot-placement.ts +97 -0
  1061. package/src/routing/types.ts +75 -26
  1062. package/src/routing/walkers.ts +98 -0
  1063. package/src/rsc-runtime/rsc.ts +9 -0
  1064. package/src/rsc-runtime/ssr.ts +51 -0
  1065. package/src/rsc-runtime/transforms.ts +13 -0
  1066. package/src/rsc-runtime/vendor-types.d.ts +19 -0
  1067. package/src/schema-bridge.ts +380 -0
  1068. package/src/search-params/define.ts +677 -0
  1069. package/src/search-params/index.ts +14 -20
  1070. package/src/search-params/parse-total.ts +91 -0
  1071. package/src/search-params/serialize-equal.ts +14 -0
  1072. package/src/search-params/wrappers.ts +150 -0
  1073. package/src/server/access-gate.tsx +196 -57
  1074. package/src/server/action-client.ts +136 -35
  1075. package/src/server/action-encryption.ts +144 -0
  1076. package/src/server/action-handler.ts +256 -56
  1077. package/src/server/actions.ts +112 -68
  1078. package/src/server/als-registry.ts +160 -21
  1079. package/src/server/asset-headers.ts +15 -37
  1080. package/src/server/body-limits.ts +10 -2
  1081. package/src/server/build-manifest.ts +33 -57
  1082. package/src/server/canonicalize.ts +6 -3
  1083. package/src/server/chain-url-parts.ts +163 -0
  1084. package/src/server/children-interception.ts +115 -0
  1085. package/src/server/coalesce-tick.ts +75 -0
  1086. package/src/server/compress.ts +43 -8
  1087. package/src/server/cookie-context.ts +484 -0
  1088. package/src/server/cookie-parsing.ts +163 -0
  1089. package/src/server/csp-nonce.ts +70 -0
  1090. package/src/server/csrf.ts +39 -6
  1091. package/src/server/debug.ts +137 -0
  1092. package/src/server/default-logger.ts +99 -0
  1093. package/src/server/default-status-page.ts +88 -0
  1094. package/src/server/deny-boundary.ts +533 -0
  1095. package/src/server/deny-renderer.ts +214 -112
  1096. package/src/server/dev-source-map.ts +31 -0
  1097. package/src/server/early-hints-sender.ts +4 -3
  1098. package/src/server/early-hints.ts +39 -29
  1099. package/src/server/error-boundary-wrapper.ts +181 -44
  1100. package/src/server/error-response-headers.ts +18 -0
  1101. package/src/server/fallback-error.ts +79 -102
  1102. package/src/server/flight-injection-state.ts +113 -0
  1103. package/src/server/flight-scripts.ts +67 -0
  1104. package/src/server/form-data.ts +124 -12
  1105. package/src/server/form-flash.ts +2 -2
  1106. package/src/server/head-response.ts +54 -0
  1107. package/src/server/html-injector-core.ts +512 -0
  1108. package/src/server/html-injectors.ts +272 -235
  1109. package/src/server/index.ts +40 -192
  1110. package/src/server/instrumentation.ts +1 -1
  1111. package/src/server/internal.ts +173 -0
  1112. package/src/server/logger.ts +73 -36
  1113. package/src/server/metadata-collector.ts +174 -0
  1114. package/src/server/metadata-platform.ts +2 -2
  1115. package/src/server/metadata-render.ts +30 -8
  1116. package/src/server/metadata-routes.ts +205 -24
  1117. package/src/server/metadata-social.ts +2 -2
  1118. package/src/server/metadata.ts +23 -2
  1119. package/src/server/middleware-runner.ts +32 -5
  1120. package/src/server/node-stream-transforms.ts +323 -0
  1121. package/src/server/nuqs-ssr-provider.tsx +8 -7
  1122. package/src/server/param-coercion.ts +198 -0
  1123. package/src/server/pipeline-helpers.ts +159 -0
  1124. package/src/server/pipeline-interception.ts +109 -33
  1125. package/src/server/pipeline-metadata.ts +15 -1
  1126. package/src/server/pipeline-outcome.ts +218 -0
  1127. package/src/server/pipeline-phases.ts +606 -0
  1128. package/src/server/pipeline.ts +343 -389
  1129. package/src/server/port-resolution.ts +53 -0
  1130. package/src/server/prebuilt/cache-key.ts +299 -0
  1131. package/src/server/prebuilt/capture-state.ts +89 -0
  1132. package/src/server/prebuilt/key-discipline.ts +122 -0
  1133. package/src/server/prebuilt/manifest-tag-index.ts +46 -0
  1134. package/src/server/prebuilt/overlay.ts +256 -0
  1135. package/src/server/prebuilt/payload-source.ts +202 -0
  1136. package/src/server/prebuilt/slots.ts +190 -0
  1137. package/src/server/prebuilt/synthetic-store.ts +122 -0
  1138. package/src/server/prebuilt-builder.ts +804 -0
  1139. package/src/server/prebuilt-runtime.ts +817 -0
  1140. package/src/server/primitives.ts +246 -97
  1141. package/src/server/publish-params.ts +42 -0
  1142. package/src/server/render-timeout.ts +108 -0
  1143. package/src/server/render-utils.ts +35 -0
  1144. package/src/server/request-context.ts +244 -333
  1145. package/src/server/request-dep.ts +37 -0
  1146. package/src/server/response-cache-policy.ts +45 -0
  1147. package/src/server/route-element-builder.ts +508 -360
  1148. package/src/server/route-element-helpers.ts +37 -0
  1149. package/src/server/route-handler.ts +40 -13
  1150. package/src/server/route-matcher.ts +165 -272
  1151. package/src/server/route-module-loader.ts +161 -0
  1152. package/src/server/rsc-cache-key-guard.ts +122 -0
  1153. package/src/server/rsc-entry/action-middleware-runner.ts +174 -0
  1154. package/src/server/rsc-entry/api-handler.ts +78 -34
  1155. package/src/server/rsc-entry/deny-fallback.ts +93 -0
  1156. package/src/server/rsc-entry/error-renderer.ts +373 -95
  1157. package/src/server/rsc-entry/helpers.ts +226 -95
  1158. package/src/server/rsc-entry/index.ts +405 -323
  1159. package/src/server/rsc-entry/render-route.ts +304 -0
  1160. package/src/server/rsc-entry/revalidate-renderer.ts +350 -0
  1161. package/src/server/rsc-entry/rsc-payload.ts +239 -50
  1162. package/src/server/rsc-entry/rsc-stream.ts +160 -30
  1163. package/src/server/rsc-entry/ssr-bridge.ts +18 -5
  1164. package/src/server/rsc-entry/ssr-renderer.ts +315 -57
  1165. package/src/server/rsc-entry/wrap-action-dispatch.ts +186 -0
  1166. package/src/server/rsc-error-envelope.ts +18 -0
  1167. package/src/server/rsc-prop-warnings.ts +3 -1
  1168. package/src/server/safe-load.ts +60 -0
  1169. package/src/server/sensitive-fields.ts +230 -0
  1170. package/src/server/server-only-guard-noop.js +3 -0
  1171. package/src/server/server-timing.ts +1 -1
  1172. package/src/server/sitemap-generator.ts +337 -0
  1173. package/src/server/sitemap-handler.ts +157 -0
  1174. package/src/server/skippable-prefix.ts +172 -0
  1175. package/src/server/slot-interception.ts +168 -0
  1176. package/src/server/slot-resolver.ts +707 -300
  1177. package/src/server/slot-subtree-contain.ts +255 -0
  1178. package/src/server/ssr-bridge-types.ts +165 -0
  1179. package/src/server/ssr-entry.ts +230 -85
  1180. package/src/server/ssr-render.ts +357 -85
  1181. package/src/server/ssr-wrappers.tsx +162 -0
  1182. package/src/server/state-tree-diff.ts +85 -30
  1183. package/src/server/static-generator.ts +715 -0
  1184. package/src/server/static-not-found.ts +134 -0
  1185. package/src/server/status-code-resolver.ts +107 -148
  1186. package/src/server/stream-utils.ts +292 -0
  1187. package/src/server/tracing.ts +151 -16
  1188. package/src/server/tree-match.ts +262 -0
  1189. package/src/server/types.ts +95 -10
  1190. package/src/server/utils/element-type.ts +88 -0
  1191. package/src/server/utils/escape-html.ts +20 -0
  1192. package/src/server/utils/mdx-file.ts +22 -0
  1193. package/src/server/version-skew.ts +104 -0
  1194. package/src/server/waituntil-bridge.ts +5 -2
  1195. package/src/server/workers-cache-bridge.ts +33 -0
  1196. package/src/shared/als-slots.ts +74 -0
  1197. package/src/shared/base-path.ts +80 -0
  1198. package/src/shared/href-validation.ts +159 -0
  1199. package/src/shared/merge-search-params.ts +55 -0
  1200. package/src/shared/param-value.ts +281 -0
  1201. package/src/shared/payload-root.ts +152 -0
  1202. package/src/shared/redirect-type.ts +17 -0
  1203. package/src/shared/rsc-cache-key.ts +269 -0
  1204. package/src/shared/rsc-error-envelope.ts +16 -0
  1205. package/src/shared/rsc-manifest.ts +29 -0
  1206. package/src/shared/rsc-media-type.ts +59 -0
  1207. package/src/shared/rsc-payload-path.ts +45 -0
  1208. package/src/shared/segment-info.ts +67 -0
  1209. package/src/shared/slot-params.ts +109 -0
  1210. package/src/shared/static-platform-files.ts +75 -0
  1211. package/src/shared/status-reason-phrase.ts +61 -0
  1212. package/src/shims/font-google.ts +1 -1
  1213. package/src/shims/font-local.ts +34 -0
  1214. package/src/shims/headers.ts +122 -1
  1215. package/src/shims/navigation-client.ts +36 -32
  1216. package/src/shims/navigation-rsc.ts +47 -0
  1217. package/src/shims/navigation.ts +10 -7
  1218. package/src/utils/state-machine.ts +111 -0
  1219. package/dist/_chunks/als-registry-k-AtAQ9R.js +0 -41
  1220. package/dist/_chunks/als-registry-k-AtAQ9R.js.map +0 -1
  1221. package/dist/_chunks/format-DNt20Kt8.js +0 -163
  1222. package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
  1223. package/dist/_chunks/interception-DGDIjDbR.js +0 -676
  1224. package/dist/_chunks/interception-DGDIjDbR.js.map +0 -1
  1225. package/dist/_chunks/metadata-routes-CQCnF4VK.js +0 -153
  1226. package/dist/_chunks/metadata-routes-CQCnF4VK.js.map +0 -1
  1227. package/dist/_chunks/request-context-CRj2Zh1E.js +0 -329
  1228. package/dist/_chunks/request-context-CRj2Zh1E.js.map +0 -1
  1229. package/dist/_chunks/ssr-data-DLnbYpj1.js.map +0 -1
  1230. package/dist/_chunks/tracing-DF0G3FB7.js +0 -173
  1231. package/dist/_chunks/tracing-DF0G3FB7.js.map +0 -1
  1232. package/dist/_chunks/use-cookie-dDbpCTx-.js +0 -91
  1233. package/dist/_chunks/use-cookie-dDbpCTx-.js.map +0 -1
  1234. package/dist/_chunks/use-query-states-DAhgj8Gx.js +0 -109
  1235. package/dist/_chunks/use-query-states-DAhgj8Gx.js.map +0 -1
  1236. package/dist/adapters/cloudflare.js.map +0 -1
  1237. package/dist/cache/index.js.map +0 -1
  1238. package/dist/cache/register-cached-function.d.ts +0 -17
  1239. package/dist/cache/register-cached-function.d.ts.map +0 -1
  1240. package/dist/client/browser-entry.d.ts +0 -21
  1241. package/dist/client/browser-entry.d.ts.map +0 -1
  1242. package/dist/client/error-boundary.js.map +0 -1
  1243. package/dist/client/head.d.ts +0 -16
  1244. package/dist/client/head.d.ts.map +0 -1
  1245. package/dist/client/link-status-provider.d.ts +0 -11
  1246. package/dist/client/link-status-provider.d.ts.map +0 -1
  1247. package/dist/client/segment-merger.d.ts +0 -119
  1248. package/dist/client/segment-merger.d.ts.map +0 -1
  1249. package/dist/client/stale-reload.d.ts +0 -44
  1250. package/dist/client/stale-reload.d.ts.map +0 -1
  1251. package/dist/client/transition-root.d.ts +0 -74
  1252. package/dist/client/transition-root.d.ts.map +0 -1
  1253. package/dist/client/use-navigation-pending.d.ts +0 -26
  1254. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  1255. package/dist/client/use-params.d.ts +0 -92
  1256. package/dist/client/use-params.d.ts.map +0 -1
  1257. package/dist/content/index.d.ts +0 -11
  1258. package/dist/content/index.d.ts.map +0 -1
  1259. package/dist/content/index.js +0 -2
  1260. package/dist/plugins/cache-transform.d.ts +0 -36
  1261. package/dist/plugins/cache-transform.d.ts.map +0 -1
  1262. package/dist/plugins/dev-error-overlay.d.ts +0 -60
  1263. package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
  1264. package/dist/plugins/dev-logs.d.ts.map +0 -1
  1265. package/dist/plugins/dynamic-transform.d.ts +0 -72
  1266. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  1267. package/dist/plugins/server-action-exports.d.ts +0 -26
  1268. package/dist/plugins/server-action-exports.d.ts.map +0 -1
  1269. package/dist/routing/status-file-lint.d.ts +0 -33
  1270. package/dist/routing/status-file-lint.d.ts.map +0 -1
  1271. package/dist/search-params/analyze.d.ts +0 -54
  1272. package/dist/search-params/analyze.d.ts.map +0 -1
  1273. package/dist/search-params/builtin-codecs.d.ts +0 -105
  1274. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  1275. package/dist/search-params/codecs.d.ts +0 -53
  1276. package/dist/search-params/codecs.d.ts.map +0 -1
  1277. package/dist/search-params/create.d.ts +0 -106
  1278. package/dist/search-params/create.d.ts.map +0 -1
  1279. package/dist/search-params/registry.d.ts +0 -20
  1280. package/dist/search-params/registry.d.ts.map +0 -1
  1281. package/dist/server/client-module-map.d.ts +0 -47
  1282. package/dist/server/client-module-map.d.ts.map +0 -1
  1283. package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
  1284. package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
  1285. package/dist/server/dev-logger.d.ts.map +0 -1
  1286. package/dist/server/dev-span-processor.d.ts +0 -29
  1287. package/dist/server/dev-span-processor.d.ts.map +0 -1
  1288. package/dist/server/dev-warnings.d.ts +0 -129
  1289. package/dist/server/dev-warnings.d.ts.map +0 -1
  1290. package/dist/server/flush.d.ts +0 -74
  1291. package/dist/server/flush.d.ts.map +0 -1
  1292. package/dist/server/manifest-status-resolver.d.ts +0 -58
  1293. package/dist/server/manifest-status-resolver.d.ts.map +0 -1
  1294. package/dist/server/prerender.d.ts +0 -77
  1295. package/dist/server/prerender.d.ts.map +0 -1
  1296. package/dist/server/tree-builder.d.ts +0 -126
  1297. package/dist/server/tree-builder.d.ts.map +0 -1
  1298. package/dist/utils/directive-parser.d.ts +0 -70
  1299. package/dist/utils/directive-parser.d.ts.map +0 -1
  1300. package/src/cache/register-cached-function.ts +0 -99
  1301. package/src/client/browser-entry.ts +0 -674
  1302. package/src/client/head.ts +0 -61
  1303. package/src/client/link-status-provider.tsx +0 -30
  1304. package/src/client/segment-merger.ts +0 -345
  1305. package/src/client/stale-reload.ts +0 -89
  1306. package/src/client/transition-root.tsx +0 -160
  1307. package/src/client/use-navigation-pending.ts +0 -38
  1308. package/src/client/use-params.ts +0 -141
  1309. package/src/content/index.ts +0 -13
  1310. package/src/plugins/cache-transform.ts +0 -199
  1311. package/src/plugins/dev-error-overlay.ts +0 -230
  1312. package/src/plugins/dynamic-transform.ts +0 -161
  1313. package/src/plugins/server-action-exports.ts +0 -220
  1314. package/src/routing/status-file-lint.ts +0 -112
  1315. package/src/search-params/analyze.ts +0 -192
  1316. package/src/search-params/builtin-codecs.ts +0 -228
  1317. package/src/search-params/codecs.ts +0 -153
  1318. package/src/search-params/create.ts +0 -321
  1319. package/src/search-params/registry.ts +0 -31
  1320. package/src/server/client-module-map.ts +0 -58
  1321. package/src/server/dev-fetch-instrumentation.ts +0 -96
  1322. package/src/server/dev-span-processor.ts +0 -78
  1323. package/src/server/dev-warnings.ts +0 -282
  1324. package/src/server/flush.ts +0 -182
  1325. package/src/server/manifest-status-resolver.ts +0 -215
  1326. package/src/server/prerender.ts +0 -139
  1327. package/src/server/tree-builder.ts +0 -382
  1328. package/src/shims/server-only-noop.js +0 -6
  1329. package/src/utils/directive-parser.ts +0 -529
@@ -1,2696 +1,168 @@
1
- import { a as warnDenyAfterFlush, c as warnRedirectInAccess, d as warnSlowSlotWithoutSuspense, f as warnStaticRequestApi, i as warnCacheRequestProps, l as warnRedirectInSlotAccess, n as WarningId, o as warnDenyInSuspense, p as warnSuspenseWrappingChildren, r as setViteServer, s as warnDynamicApiInStaticBuild, t as formatSize, u as warnRedirectInSuspense } from "../_chunks/format-DNt20Kt8.js";
2
- import { i as getMetadataRouteServePath, n as classifyMetadataRoute, r as getMetadataRouteAutoLink, t as METADATA_ROUTE_CONVENTIONS } from "../_chunks/metadata-routes-CQCnF4VK.js";
3
- import { a as timingAls, i as revalidationAls, n as formFlashAls, s as waitUntilAls, t as earlyHintsSenderAls } from "../_chunks/als-registry-k-AtAQ9R.js";
4
- import { a as markResponseFlushed, c as setCookieSecrets, i as headers, l as setMutableCookieContext, n as cookies, o as runWithRequestContext, r as getSetCookieHeaders, s as searchParams, t as applyRequestHeaderOverlay, u as setParsedSearchParams } from "../_chunks/request-context-CRj2Zh1E.js";
5
- import { a as replaceTraceId, c as spanId, i as getTraceStore, l as traceId, n as generateTraceId, o as runWithTraceId, r as getOtelTraceId, s as setSpanAttribute, t as addSpanEvent, u as withSpan } from "../_chunks/tracing-DF0G3FB7.js";
6
- import { readFile } from "node:fs/promises";
7
- //#region src/server/waituntil-bridge.ts
1
+ import { n as formFlashAls } from "../_chunks/als-registry-C6kcfprT.js";
2
+ import { A as isDenySignal, B as getSegmentParams, F as waitUntil, N as redirect, P as redirectExternal, R as getHeaders, T as withSpan, X as isDevMode, Y as isDebug, b as getSpanId, g as addSpanEvent, j as isRedirectSignal, k as deny, q as getCookieJar, x as getTraceId } from "../_chunks/logger-uLBuGKDI.js";
3
+ import { t as formatSize } from "../_chunks/format-BKclgVbk.js";
4
+ import { a as parseFormData, i as coerce, n as revalidatePath, r as revalidateTag } from "../_chunks/actions-d1hCqnU3.js";
5
+ //#region src/shared/redirect-type.ts
8
6
  /**
9
- * Per-request waitUntil bridge — ALS bridge for platform adapters.
10
- *
11
- * The generated entry point (Nitro, Cloudflare) wraps the handler with
12
- * `runWithWaitUntil`, binding the platform's lifecycle extension function
13
- * (e.g., h3's `event.waitUntil()` or CF's `ctx.waitUntil()`) for the
14
- * request duration. The `waitUntil()` primitive reads from this ALS to
15
- * dispatch background work to the correct platform API.
16
- *
17
- * Design doc: design/11-platform.md §"waitUntil()"
18
- */
19
- /**
20
- * Get the current request's waitUntil function, if available.
21
- *
22
- * Returns undefined when no platform adapter has installed a waitUntil
23
- * handler for the current request (e.g., on platforms that don't support
24
- * lifecycle extension, or outside a request context).
25
- */
26
- function getWaitUntil() {
27
- return waitUntilAls.getStore();
28
- }
29
- //#endregion
30
- //#region src/server/primitives.ts
31
- /**
32
- * Check if a value is JSON-serializable without data loss.
33
- * Returns a description of the first non-serializable value found, or null if OK.
34
- *
35
- * @internal Exported for testing only.
36
- */
37
- function findNonSerializable(value, path = "data") {
38
- if (value === null || value === void 0) return null;
39
- switch (typeof value) {
40
- case "string":
41
- case "number":
42
- case "boolean": return null;
43
- case "bigint": return `${path} contains a BigInt — BigInt throws in JSON.stringify`;
44
- case "function": return `${path} is a function — functions are not JSON-serializable`;
45
- case "symbol": return `${path} is a symbol — symbols are not JSON-serializable`;
46
- case "object": break;
47
- default: return `${path} has unsupported type "${typeof value}"`;
48
- }
49
- if (value instanceof Date) return `${path} is a Date — Dates silently coerce to strings in JSON.stringify`;
50
- if (value instanceof Map) return `${path} is a Map — Maps serialize as {} in JSON.stringify (data loss)`;
51
- if (value instanceof Set) return `${path} is a Set — Sets serialize as {} in JSON.stringify (data loss)`;
52
- if (value instanceof RegExp) return `${path} is a RegExp — RegExps serialize as {} in JSON.stringify`;
53
- if (value instanceof Error) return `${path} is an Error — Errors serialize as {} in JSON.stringify`;
54
- if (Array.isArray(value)) {
55
- for (let i = 0; i < value.length; i++) {
56
- const result = findNonSerializable(value[i], `${path}[${i}]`);
57
- if (result) return result;
58
- }
59
- return null;
60
- }
61
- const proto = Object.getPrototypeOf(value);
62
- if (proto === null) return `${path} is a null-prototype object — React Flight rejects null prototypes`;
63
- if (proto !== Object.prototype) return `${path} is a ${value.constructor?.name ?? "unknown"} instance — class instances may lose data in JSON.stringify`;
64
- for (const key of Object.keys(value)) {
65
- const result = findNonSerializable(value[key], `${path}.${key}`);
66
- if (result) return result;
67
- }
68
- return null;
69
- }
70
- /**
71
- * Emit a dev-mode warning if data is not JSON-serializable.
72
- * No-op in production.
73
- */
74
- function warnIfNotSerializable(data, callerName) {
75
- if (process.env.NODE_ENV === "production") return;
76
- if (data === void 0) return;
77
- const issue = findNonSerializable(data);
78
- if (issue) console.warn(`[timber] ${callerName}: ${issue}. Data passed to deny() or RenderError must be JSON-serializable because the post-flush path uses JSON.stringify, not React Flight.`);
79
- }
80
- /**
81
- * Render-phase signal thrown by `deny()`. Caught by the framework to produce
82
- * the correct HTTP status code (segment context) or graceful degradation (slot context).
83
- */
84
- var DenySignal = class extends Error {
85
- status;
86
- data;
87
- constructor(status, data) {
88
- super(`Access denied with status ${status}`);
89
- this.name = "DenySignal";
90
- this.status = status;
91
- this.data = data;
92
- }
93
- /**
94
- * Extract the file that called deny() from the stack trace.
95
- * Returns a short path (e.g. "app/auth/access.ts") or undefined if
96
- * the stack can't be parsed. Dev-only — used for dev log output.
97
- */
98
- get sourceFile() {
99
- if (!this.stack) return void 0;
100
- const frames = this.stack.split("\n");
101
- for (let i = 2; i < frames.length; i++) {
102
- const frame = frames[i];
103
- if (!frame) continue;
104
- if (frame.includes("primitives.ts") || frame.includes("node_modules")) continue;
105
- const match = frame.match(/\(([^)]+?)(?::\d+:\d+)\)/) ?? frame.match(/at\s+([^\s]+?)(?::\d+:\d+)/);
106
- if (match?.[1]) {
107
- const full = match[1];
108
- const appIdx = full.indexOf("/app/");
109
- return appIdx >= 0 ? full.slice(appIdx + 1) : full;
110
- }
111
- }
112
- }
113
- };
114
- /**
115
- * Universal denial primitive. Throws a `DenySignal` that the framework catches.
116
- *
117
- * - In segment context (outside Suspense): produces HTTP status code
118
- * - In slot context: graceful degradation → denied.tsx → default.tsx → null
119
- * - Inside Suspense (hold window): promoted to pre-flush behavior
120
- * - Inside Suspense (after flush): error boundary + noindex meta
121
- *
122
- * @param status - Any 4xx HTTP status code. Defaults to 403.
123
- * @param data - Optional JSON-serializable data passed as `dangerouslyPassData` prop to status-code files.
124
- */
125
- function deny(status = 403, data) {
126
- if (status < 400 || status > 499) throw new Error(`deny() requires a 4xx status code, got ${status}. For 5xx errors, throw a RenderError instead.`);
127
- warnIfNotSerializable(data, "deny()");
128
- throw new DenySignal(status, data);
129
- }
130
- /**
131
- * Convenience alias for `deny(404)`.
132
- *
133
- * Provided for Next.js API compatibility — libraries and user code that
134
- * call `notFound()` from `next/navigation` get the same behavior as
135
- * `deny(404)` in timber.
136
- */
137
- function notFound() {
138
- throw new DenySignal(404);
139
- }
140
- /**
141
- * Next.js redirect type discriminator.
142
- *
143
- * Provided for API compatibility with libraries that import `RedirectType`
144
- * from `next/navigation`. In timber, `redirect()` always uses `replace`
145
- * semantics (no history entry for the redirect itself).
146
- */
147
- var RedirectType = {
148
- push: "push",
149
- replace: "replace"
150
- };
151
- /**
152
- * Render-phase signal thrown by `redirect()` and `redirectExternal()`.
153
- * Caught by the framework to produce a 3xx response or client-side navigation.
154
- */
155
- var RedirectSignal = class extends Error {
156
- location;
157
- status;
158
- constructor(location, status) {
159
- super(`Redirect to ${location}`);
160
- this.name = "RedirectSignal";
161
- this.location = location;
162
- this.status = status;
163
- }
164
- };
165
- /** Pattern matching absolute URLs: http(s):// or protocol-relative // */
166
- var ABSOLUTE_URL_RE = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/)/;
167
- /**
168
- * Redirect to a relative path. Rejects absolute and protocol-relative URLs.
169
- * Use `redirectExternal()` for external redirects with an allow-list.
170
- *
171
- * @param path - Relative path (e.g. '/login', 'settings', '/login?returnTo=/dash')
172
- * @param status - HTTP redirect status code (3xx). Defaults to 302.
173
- */
174
- function redirect(path, status = 302) {
175
- if (status < 300 || status > 399) throw new Error(`redirect() requires a 3xx status code, got ${status}.`);
176
- if (ABSOLUTE_URL_RE.test(path)) throw new Error(`redirect() only accepts relative URLs. Got absolute URL: "${path}". Use redirectExternal(url, allowList) for external redirects.`);
177
- throw new RedirectSignal(path, status);
178
- }
179
- /**
180
- * Permanent redirect to a relative path. Shorthand for `redirect(path, 308)`.
181
- *
182
- * Uses 308 (Permanent Redirect) which preserves the HTTP method — the browser
183
- * will replay POST requests to the new location. This matches Next.js behavior.
184
- *
185
- * @param path - Relative path (e.g. '/new-page', '/dashboard')
186
- */
187
- function permanentRedirect(path) {
188
- redirect(path, 308);
189
- }
190
- /**
191
- * Redirect to an external URL. The hostname must be in the provided allow-list.
192
- *
193
- * @param url - Absolute URL to redirect to.
194
- * @param allowList - Array of allowed hostnames (e.g. ['example.com', 'auth.example.com']).
195
- * @param status - HTTP redirect status code (3xx). Defaults to 302.
196
- */
197
- function redirectExternal(url, allowList, status = 302) {
198
- if (status < 300 || status > 399) throw new Error(`redirectExternal() requires a 3xx status code, got ${status}.`);
199
- let hostname;
200
- try {
201
- hostname = new URL(url).hostname;
202
- } catch {
203
- throw new Error(`redirectExternal() received an invalid URL: "${url}"`);
204
- }
205
- if (!allowList.includes(hostname)) throw new Error(`redirectExternal() target "${hostname}" is not in the allow-list. Allowed: [${allowList.join(", ")}]`);
206
- throw new RedirectSignal(url, status);
207
- }
208
- /**
209
- * Typed throw for render-phase errors that carry structured context to error boundaries.
210
- *
211
- * The `digest` (code + data) is serialized into the RSC stream separately from the
212
- * Error instance — only the digest crosses the RSC → client boundary.
213
- *
214
- * @example
215
- * ```ts
216
- * throw new RenderError('PRODUCT_NOT_FOUND', {
217
- * title: 'Product not found',
218
- * resourceId: params.id,
219
- * })
220
- * ```
221
- */
222
- var RenderError = class extends Error {
223
- code;
224
- digest;
225
- status;
226
- constructor(code, data, options) {
227
- super(`RenderError: ${code}`);
228
- this.name = "RenderError";
229
- this.code = code;
230
- this.digest = {
231
- code,
232
- data
233
- };
234
- warnIfNotSerializable(data, "RenderError");
235
- const status = options?.status ?? 500;
236
- if (status < 400 || status > 599) throw new Error(`RenderError status must be 4xx or 5xx, got ${status}.`);
237
- this.status = status;
238
- }
239
- };
240
- var _waitUntilWarned = false;
241
- /**
242
- * Register a promise to be kept alive after the response is sent.
243
- * Maps to `ctx.waitUntil()` on Cloudflare Workers and similar platforms.
244
- *
245
- * In production, the platform adapter installs a per-request waitUntil
246
- * function via ALS (see waituntil-bridge.ts). This function checks the
247
- * ALS bridge first, then falls back to the legacy adapter argument.
248
- *
249
- * If neither is available, a warning is logged once and the promise is
250
- * left to resolve (or reject) without being tracked.
251
- *
252
- * @param promise - The background work to keep alive.
253
- * @param adapter - Optional legacy adapter (prefer ALS bridge in production).
254
- */
255
- function waitUntil(promise, adapter) {
256
- const alsFn = getWaitUntil();
257
- if (alsFn) {
258
- alsFn(promise);
259
- return;
260
- }
261
- if (adapter && typeof adapter.waitUntil === "function") {
262
- adapter.waitUntil(promise);
263
- return;
264
- }
265
- if (!_waitUntilWarned) {
266
- _waitUntilWarned = true;
267
- console.warn("[timber] waitUntil() is not supported by the current adapter. Background work will not be tracked. This warning is shown once.");
268
- }
269
- }
270
- //#endregion
271
- //#region src/server/canonicalize.ts
272
- /**
273
- * Encoded separators that produce a 400 rejection.
274
- * %2f (/) and %5c (\) cause path-confusion attacks.
275
- */
276
- var ENCODED_SEPARATOR_RE = /%2f|%5c/i;
277
- /** Null byte — rejected. */
278
- var NULL_BYTE_RE = /%00/i;
279
- /**
280
- * Canonicalize a URL pathname.
281
- *
282
- * 1. Reject encoded separators (%2f, %5c) and null bytes (%00)
283
- * 2. Single percent-decode
284
- * 3. Collapse // → /
285
- * 4. Resolve .. segments (reject if escaping root)
286
- * 5. Strip trailing slash (except root "/")
287
- *
288
- * @param rawPathname - The raw pathname from the request URL (percent-encoded)
289
- * @param stripTrailingSlash - Whether to strip trailing slashes. Default: true.
290
- */
291
- function canonicalize(rawPathname, stripTrailingSlash = true) {
292
- if (ENCODED_SEPARATOR_RE.test(rawPathname)) return {
293
- ok: false,
294
- status: 400
295
- };
296
- if (NULL_BYTE_RE.test(rawPathname)) return {
297
- ok: false,
298
- status: 400
299
- };
300
- let decoded;
301
- try {
302
- decoded = decodeURIComponent(rawPathname);
303
- } catch {
304
- return {
305
- ok: false,
306
- status: 400
307
- };
308
- }
309
- if (decoded.includes("\0")) return {
310
- ok: false,
311
- status: 400
312
- };
313
- let pathname = decoded.replace(/\/\/+/g, "/");
314
- const segments = pathname.split("/");
315
- const resolved = [];
316
- for (const seg of segments) if (seg === "..") {
317
- if (resolved.length <= 1) return {
318
- ok: false,
319
- status: 400
320
- };
321
- resolved.pop();
322
- } else if (seg !== ".") resolved.push(seg);
323
- pathname = resolved.join("/") || "/";
324
- if (stripTrailingSlash && pathname.length > 1 && pathname.endsWith("/")) pathname = pathname.slice(0, -1);
325
- return {
326
- ok: true,
327
- pathname
328
- };
329
- }
330
- //#endregion
331
- //#region src/server/proxy.ts
332
- /**
333
- * Run the proxy pipeline.
334
- *
335
- * @param proxyExport - The default export from proxy.ts (function or array)
336
- * @param req - The incoming request
337
- * @param next - The continuation that proceeds to route matching and rendering
338
- * @returns The final response
339
- */
340
- async function runProxy(proxyExport, req, next) {
341
- const fns = Array.isArray(proxyExport) ? proxyExport : [proxyExport];
342
- let i = fns.length;
343
- let composed = next;
344
- while (i--) {
345
- const fn = fns[i];
346
- const downstream = composed;
347
- composed = () => Promise.resolve(fn(req, downstream));
348
- }
349
- return composed();
350
- }
351
- //#endregion
352
- //#region src/server/middleware-runner.ts
353
- /**
354
- * Run a route's middleware function.
355
- *
356
- * @param middlewareFn - The default export from the route's middleware.ts
357
- * @param ctx - The middleware context (req, params, headers, requestHeaders, searchParams)
358
- * @returns A Response if middleware short-circuited, or undefined to continue
359
- */
360
- async function runMiddleware(middlewareFn, ctx) {
361
- const result = await middlewareFn(ctx);
362
- if (result instanceof Response) return result;
363
- }
364
- //#endregion
365
- //#region src/server/server-timing.ts
366
- /**
367
- * Server-Timing header — dev-mode timing breakdowns for Chrome DevTools.
368
- *
369
- * Collects timing entries per request using ALS. Each pipeline phase
370
- * (proxy, middleware, render, SSR, access, fetch) records an entry.
371
- * Before response flush, entries are formatted into a Server-Timing header.
372
- *
373
- * Only active in dev mode — zero overhead in production.
374
- *
375
- * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing
376
- * Task: LOCAL-290
377
- */
378
- /**
379
- * Run a callback with a per-request timing collector.
380
- * Must be called at the top of the request pipeline (wraps the full request).
381
- */
382
- function runWithTimingCollector(fn) {
383
- return timingAls.run({ entries: [] }, fn);
384
- }
385
- /**
386
- * Run a function and automatically record its duration as a timing entry.
387
- * Returns the function's result. No-ops the recording if outside a collector.
388
- */
389
- async function withTiming(name, desc, fn) {
390
- const store = timingAls.getStore();
391
- if (!store) return fn();
392
- const start = performance.now();
393
- try {
394
- return await fn();
395
- } finally {
396
- const dur = Math.round(performance.now() - start);
397
- store.entries.push({
398
- name,
399
- dur,
400
- desc
401
- });
402
- }
403
- }
404
- /**
405
- * Get the Server-Timing header value for the current request.
406
- * Returns null if no entries exist or outside a collector.
407
- *
408
- * Format: `name;dur=123;desc="description", name2;dur=456`
409
- * See RFC 6797 / Server-Timing spec for format details.
410
- */
411
- function getServerTimingHeader() {
412
- const store = timingAls.getStore();
413
- if (!store || store.entries.length === 0) return null;
414
- const nameCounts = /* @__PURE__ */ new Map();
415
- const parts = store.entries.map((entry) => {
416
- const count = nameCounts.get(entry.name) ?? 0;
417
- nameCounts.set(entry.name, count + 1);
418
- const uniqueName = count > 0 ? `${entry.name}-${count}` : entry.name;
419
- return {
420
- ...entry,
421
- name: uniqueName
422
- };
423
- }).map((entry) => {
424
- let part = `${entry.name};dur=${entry.dur}`;
425
- if (entry.desc) {
426
- const safeDesc = entry.desc.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
427
- part += `;desc="${safeDesc}"`;
428
- }
429
- return part;
430
- });
431
- const MAX_HEADER_SIZE = 4096;
432
- let result = "";
433
- for (let i = 0; i < parts.length; i++) {
434
- const candidate = result ? `${result}, ${parts[i]}` : parts[i];
435
- if (candidate.length > MAX_HEADER_SIZE) break;
436
- result = candidate;
437
- }
438
- return result || null;
439
- }
440
- //#endregion
441
- //#region src/server/error-formatter.ts
442
- /**
443
- * Error Formatter — rewrites SSR/RSC error messages to surface user code.
444
- *
445
- * When React or Vite throw errors during SSR, stack traces reference
446
- * vendored dependency paths (e.g. `.vite/deps_ssr/@vitejs_plugin-rsc_vendor_...`)
447
- * and mangled export names (`__vite_ssr_export_default__`). This module
448
- * rewrites error messages and stack traces to point at user code instead.
449
- *
450
- * Dev-only — in production, errors go through the structured logger
451
- * without formatting.
452
- */
453
- /**
454
- * Patterns that identify internal Vite/RSC vendor paths in stack traces.
455
- * These are replaced with human-readable labels.
456
- */
457
- var VENDOR_PATH_PATTERNS = [
458
- {
459
- pattern: /node_modules\/\.vite\/deps_ssr\/@vitejs_plugin-rsc_vendor_react-server-dom[^\s)]+/g,
460
- replacement: "<react-server-dom>"
461
- },
462
- {
463
- pattern: /node_modules\/\.vite\/deps_ssr\/@vitejs_plugin-rsc_vendor[^\s)]+/g,
464
- replacement: "<rsc-vendor>"
465
- },
466
- {
467
- pattern: /node_modules\/\.vite\/deps_ssr\/[^\s)]+/g,
468
- replacement: "<vite-dep>"
469
- },
470
- {
471
- pattern: /node_modules\/\.vite\/deps\/[^\s)]+/g,
472
- replacement: "<vite-dep>"
473
- }
474
- ];
475
- /**
476
- * Patterns that identify Vite-mangled export names in error messages.
477
- */
478
- var MANGLED_NAME_PATTERNS = [{
479
- pattern: /__vite_ssr_export_default__/g,
480
- replacement: "<default export>"
481
- }, {
482
- pattern: /__vite_ssr_export_(\w+)__/g,
483
- replacement: "<export $1>"
484
- }];
485
- /**
486
- * Rewrite an error's message and stack to replace internal Vite paths
487
- * and mangled names with human-readable labels.
488
- */
489
- function formatSsrError(error) {
490
- if (!(error instanceof Error)) return String(error);
491
- let message = error.message;
492
- let stack = error.stack ?? "";
493
- for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) message = message.replace(pattern, replacement);
494
- for (const { pattern, replacement } of VENDOR_PATH_PATTERNS) stack = stack.replace(pattern, replacement);
495
- for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) stack = stack.replace(pattern, replacement);
496
- const hint = extractErrorHint(error.message);
497
- const parts = [];
498
- parts.push(message);
499
- if (hint) parts.push(` → ${hint}`);
500
- const userFrames = extractUserFrames(stack);
501
- if (userFrames.length > 0) {
502
- parts.push("");
503
- parts.push(" User code in stack:");
504
- for (const frame of userFrames) parts.push(` ${frame}`);
505
- }
506
- return parts.join("\n");
507
- }
508
- /**
509
- * Extract a human-readable hint from common React/RSC error messages.
510
- *
511
- * React error messages contain useful information but the surrounding
512
- * context (vendor paths, mangled names) obscures it. This extracts the
513
- * actionable part as a one-line hint.
514
- */
515
- function extractErrorHint(message) {
516
- if (message.match(/Functions cannot be passed directly to Client Components/)) {
517
- const propMatch = message.match(/<[^>]*?\s(\w+)=\{function/);
518
- if (propMatch) return `Prop "${propMatch[1]}" is a function — mark it "use server" or call it before passing`;
519
- return "A function prop was passed to a Client Component — mark it \"use server\" or call it before passing";
520
- }
521
- if (message.includes("Objects are not valid as a React child")) return "An object was rendered as JSX children — convert to string or extract the value";
522
- const nullRefMatch = message.match(/Cannot read propert(?:y|ies) of (undefined|null) \(reading '(\w+)'\)/);
523
- if (nullRefMatch) return `Accessed .${nullRefMatch[2]} on ${nullRefMatch[1]} — check that the value exists`;
524
- const notFnMatch = message.match(/(\w+) is not a function/);
525
- if (notFnMatch) return `"${notFnMatch[1]}" is not a function — check imports and exports`;
526
- if (message.includes("Element type is invalid")) return "A component resolved to undefined/null — check default exports and import paths";
527
- if (message.includes("Invalid hook call")) return "A hook was called outside of a React component render. If this is a 'use client' component, ensure the directive is at the very top of the file (before any imports) and that @vitejs/plugin-rsc is loaded correctly. Barrel re-exports from non-'use client' files do not propagate the directive.";
528
- return null;
529
- }
530
- /**
531
- * Extract stack frames that reference user code (not node_modules,
532
- * not framework internals).
533
- *
534
- * Returns at most 5 frames to keep output concise.
535
- */
536
- function extractUserFrames(stack) {
537
- const lines = stack.split("\n");
538
- const userFrames = [];
539
- for (const line of lines) {
540
- const trimmed = line.trim();
541
- if (!trimmed.startsWith("at ")) continue;
542
- if (trimmed.includes("node_modules") || trimmed.includes("<react-server-dom>") || trimmed.includes("<rsc-vendor>") || trimmed.includes("<vite-dep>") || trimmed.includes("node:internal")) continue;
543
- userFrames.push(trimmed);
544
- if (userFrames.length >= 5) break;
545
- }
546
- return userFrames;
547
- }
548
- //#endregion
549
- //#region src/server/logger.ts
550
- /**
551
- * Logger — structured logging with environment-aware formatting.
552
- *
553
- * timber.js does not ship a logger. Users export any object with
554
- * info/warn/error/debug methods from instrumentation.ts and the framework
555
- * picks it up. Silent if no logger export is present.
556
- *
557
- * See design/17-logging.md §"Production Logging"
558
- */
559
- var _logger = null;
560
- /**
561
- * Set the user-provided logger. Called by the instrumentation loader
562
- * when it finds a `logger` export in instrumentation.ts.
563
- */
564
- function setLogger(logger) {
565
- _logger = logger;
566
- }
567
- /**
568
- * Get the current logger, or null if none configured.
569
- * Framework-internal — used at framework event points to emit structured logs.
570
- */
571
- function getLogger() {
572
- return _logger;
573
- }
574
- /**
575
- * Inject trace_id and span_id into log data for log–trace correlation.
576
- * Always injects trace_id (never undefined). Injects span_id only when OTEL is active.
577
- */
578
- function withTraceContext(data) {
579
- const store = getTraceStore();
580
- const enriched = { ...data };
581
- if (store) {
582
- enriched.trace_id = store.traceId;
583
- if (store.spanId) enriched.span_id = store.spanId;
584
- }
585
- return enriched;
586
- }
587
- /** Log a completed request. Level: info. */
588
- function logRequestCompleted(data) {
589
- _logger?.info("request completed", withTraceContext(data));
590
- }
591
- /** Log request received. Level: debug. */
592
- function logRequestReceived(data) {
593
- _logger?.debug("request received", withTraceContext(data));
594
- }
595
- /** Log a slow request warning. Level: warn. */
596
- function logSlowRequest(data) {
597
- _logger?.warn("slow request exceeded threshold", withTraceContext(data));
598
- }
599
- /** Log middleware short-circuit. Level: debug. */
600
- function logMiddlewareShortCircuit(data) {
601
- _logger?.debug("middleware short-circuited", withTraceContext(data));
602
- }
603
- /** Log unhandled error in middleware phase. Level: error. */
604
- function logMiddlewareError(data) {
605
- if (_logger) _logger.error("unhandled error in middleware phase", withTraceContext(data));
606
- else if (process.env.NODE_ENV !== "production") console.error("[timber] middleware error", data.error);
607
- }
608
- /** Log unhandled render-phase error. Level: error. */
609
- function logRenderError(data) {
610
- if (_logger) _logger.error("unhandled render-phase error", withTraceContext(data));
611
- else if (process.env.NODE_ENV !== "production") console.error("[timber] render error:", formatSsrError(data.error));
612
- }
613
- /** Log proxy.ts uncaught error. Level: error. */
614
- function logProxyError(data) {
615
- if (_logger) _logger.error("proxy.ts threw uncaught error", withTraceContext(data));
616
- else if (process.env.NODE_ENV !== "production") console.error("[timber] proxy error", data.error);
617
- }
618
- /** Log waitUntil() adapter missing (once at startup). Level: warn. */
619
- function logWaitUntilUnsupported() {
620
- _logger?.warn("adapter does not support waitUntil()");
621
- }
622
- /** Log waitUntil() promise rejection. Level: warn. */
623
- function logWaitUntilRejected(data) {
624
- _logger?.warn("waitUntil() promise rejected", withTraceContext(data));
625
- }
626
- /** Log staleWhileRevalidate refetch failure. Level: warn. */
627
- function logSwrRefetchFailed(data) {
628
- _logger?.warn("staleWhileRevalidate refetch failed", withTraceContext(data));
629
- }
630
- /** Log cache miss. Level: debug. */
631
- function logCacheMiss(data) {
632
- _logger?.debug("timber.cache MISS", withTraceContext(data));
633
- }
634
- //#endregion
635
- //#region src/server/instrumentation.ts
636
- /**
637
- * Instrumentation — loads and runs the user's instrumentation.ts file.
638
- *
639
- * instrumentation.ts is a file convention at the project root that exports:
640
- * - register() — called once at server startup, before the first request
641
- * - onRequestError() — called for every unhandled server error
642
- * - logger — any object with info/warn/error/debug methods
643
- *
644
- * See design/17-logging.md §"instrumentation.ts — The Entry Point"
645
- */
646
- var _initialized = false;
647
- var _onRequestError = null;
648
- /**
649
- * Load and initialize the user's instrumentation.ts module.
650
- *
651
- * - Awaits register() before returning (server blocks on this).
652
- * - Picks up the logger export and wires it into the framework logger.
653
- * - Stores onRequestError for later invocation.
654
- *
655
- * @param loader - Function that dynamically imports the user's instrumentation module.
656
- * Returns null if no instrumentation.ts exists.
657
- */
658
- async function loadInstrumentation(loader) {
659
- if (_initialized) return;
660
- _initialized = true;
661
- let mod;
662
- try {
663
- mod = await loader();
664
- } catch (error) {
665
- console.error("[timber] Failed to load instrumentation.ts:", error);
666
- return;
667
- }
668
- if (!mod) return;
669
- if (mod.logger && typeof mod.logger.info === "function") setLogger(mod.logger);
670
- if (typeof mod.onRequestError === "function") _onRequestError = mod.onRequestError;
671
- if (typeof mod.register === "function") try {
672
- await mod.register();
673
- } catch (error) {
674
- console.error("[timber] instrumentation.ts register() threw:", error);
675
- throw error;
676
- }
677
- }
678
- /**
679
- * Call the user's onRequestError hook. Catches and logs any errors thrown
680
- * by the hook itself — it must not affect the response.
681
- */
682
- async function callOnRequestError(error, request, context) {
683
- if (!_onRequestError) return;
684
- try {
685
- await _onRequestError(error, request, context);
686
- } catch (hookError) {
687
- console.error("[timber] onRequestError hook threw:", hookError);
688
- }
689
- }
690
- /**
691
- * Check if onRequestError is registered.
692
- */
693
- function hasOnRequestError() {
694
- return _onRequestError !== null;
695
- }
696
- //#endregion
697
- //#region src/server/pipeline-metadata.ts
698
- /**
699
- * Metadata route helpers for the request pipeline.
700
- *
701
- * Handles serving static metadata files and serializing sitemap responses.
702
- * Extracted from pipeline.ts to keep files under 500 lines.
703
- *
704
- * See design/16-metadata.md §"Metadata Routes"
705
- */
706
- /**
707
- * Content types that are text-based and should include charset=utf-8.
708
- * Binary formats (images) should not include charset.
709
- */
710
- var TEXT_CONTENT_TYPES = new Set([
711
- "application/xml",
712
- "text/plain",
713
- "application/json",
714
- "application/manifest+json",
715
- "image/svg+xml"
716
- ]);
717
- /**
718
- * Serve a static metadata file by reading it from disk.
719
- *
720
- * Static metadata route files (.xml, .txt, .json, .png, .ico, .svg, etc.)
721
- * are served as-is with the appropriate Content-Type header.
722
- * Text files include charset=utf-8; binary files do not.
723
- *
724
- * See design/16-metadata.md §"Metadata Routes"
725
- */
726
- async function serveStaticMetadataFile(metaMatch) {
727
- const { contentType, file } = metaMatch;
728
- const isText = TEXT_CONTENT_TYPES.has(contentType);
729
- const body = await readFile(file.filePath);
730
- const headers = {
731
- "Content-Type": isText ? `${contentType}; charset=utf-8` : contentType,
732
- "Content-Length": String(body.byteLength)
733
- };
734
- return new Response(body, {
735
- status: 200,
736
- headers
737
- });
738
- }
739
- /**
740
- * Serialize a sitemap array to XML.
741
- * Follows the sitemap.org protocol: https://www.sitemaps.org/protocol.html
742
- */
743
- function serializeSitemap(entries) {
744
- return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${entries.map((e) => {
745
- let xml = ` <url>\n <loc>${escapeXml(e.url)}</loc>`;
746
- if (e.lastModified) {
747
- const date = e.lastModified instanceof Date ? e.lastModified.toISOString() : e.lastModified;
748
- xml += `\n <lastmod>${escapeXml(date)}</lastmod>`;
749
- }
750
- if (e.changeFrequency) xml += `\n <changefreq>${escapeXml(e.changeFrequency)}</changefreq>`;
751
- if (e.priority !== void 0) xml += `\n <priority>${e.priority}</priority>`;
752
- xml += "\n </url>";
753
- return xml;
754
- }).join("\n")}\n</urlset>`;
755
- }
756
- /** Escape special XML characters. */
757
- function escapeXml(str) {
758
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
759
- }
760
- //#endregion
761
- //#region src/server/pipeline-interception.ts
762
- /**
763
- * Check if an intercepting route applies for this soft navigation.
764
- *
765
- * Matches the target pathname against interception rewrites, constrained
766
- * by the source URL (X-Timber-URL header — where the user navigates FROM).
767
- *
768
- * Returns the source pathname to re-match if interception applies, or null.
769
- */
770
- function findInterceptionMatch(targetPathname, sourceUrl, rewrites) {
771
- for (const rewrite of rewrites) {
772
- if (!sourceUrl.startsWith(rewrite.interceptingPrefix)) continue;
773
- if (pathnameMatchesPattern(targetPathname, rewrite.interceptedPattern)) return { sourcePathname: rewrite.interceptingPrefix };
774
- }
775
- return null;
776
- }
777
- /**
778
- * Check if a pathname matches a URL pattern with dynamic segments.
779
- *
780
- * Supports [param] (single segment) and [...param] (one or more segments).
781
- * Static segments must match exactly.
782
- */
783
- function pathnameMatchesPattern(pathname, pattern) {
784
- const pathParts = pathname === "/" ? [] : pathname.slice(1).split("/");
785
- const patternParts = pattern === "/" ? [] : pattern.slice(1).split("/");
786
- let pi = 0;
787
- for (let i = 0; i < patternParts.length; i++) {
788
- const segment = patternParts[i];
789
- if (segment.startsWith("[...") || segment.startsWith("[[...")) return pi < pathParts.length || segment.startsWith("[[...");
790
- if (segment.startsWith("[") && segment.endsWith("]")) {
791
- if (pi >= pathParts.length) return false;
792
- pi++;
793
- continue;
794
- }
795
- if (pi >= pathParts.length || pathParts[pi] !== segment) return false;
796
- pi++;
797
- }
798
- return pi === pathParts.length;
799
- }
800
- //#endregion
801
- //#region src/server/pipeline.ts
802
- /**
803
- * Request pipeline — the central dispatch for all timber.js requests.
804
- *
805
- * Pipeline stages (in order):
806
- * proxy.ts → canonicalize → route match → 103 Early Hints → middleware.ts → render
807
- *
808
- * Each stage is a pure function or returns a Response to short-circuit.
809
- * Each request gets a trace ID, structured logging, and OTEL spans.
810
- *
811
- * See design/07-routing.md §"Request Lifecycle", design/02-rendering-pipeline.md §"Request Flow",
812
- * and design/17-logging.md §"Production Logging"
813
- */
814
- /**
815
- * Create the request handler from a pipeline configuration.
816
- *
817
- * Returns a function that processes an incoming Request through all pipeline stages
818
- * and produces a Response. This is the top-level entry point for the server.
819
- */
820
- function createPipeline(config) {
821
- const { proxy, matchRoute, render, earlyHints, stripTrailingSlash = true, slowRequestMs = 3e3, enableServerTiming = false, onPipelineError } = config;
822
- let activeRequests = 0;
823
- return async (req) => {
824
- const url = new URL(req.url);
825
- const method = req.method;
826
- const path = url.pathname;
827
- const startTime = performance.now();
828
- activeRequests++;
829
- return runWithTraceId(generateTraceId(), async () => {
830
- return runWithRequestContext(req, async () => {
831
- const runRequest = async () => {
832
- logRequestReceived({
833
- method,
834
- path
835
- });
836
- const response = await withSpan("http.server.request", {
837
- "http.request.method": method,
838
- "url.path": path
839
- }, async () => {
840
- const otelIds = await getOtelTraceId();
841
- if (otelIds) replaceTraceId(otelIds.traceId, otelIds.spanId);
842
- let result;
843
- if (proxy || config.proxyLoader) result = await runProxyPhase(req, method, path);
844
- else result = await handleRequest(req, method, path);
845
- await setSpanAttribute("http.response.status_code", result.status);
846
- if (enableServerTiming) {
847
- const serverTiming = getServerTimingHeader();
848
- if (serverTiming) {
849
- result = ensureMutableResponse(result);
850
- result.headers.set("Server-Timing", serverTiming);
851
- }
852
- } else {
853
- const totalMs = Math.round(performance.now() - startTime);
854
- result = ensureMutableResponse(result);
855
- result.headers.set("Server-Timing", `total;dur=${totalMs}`);
856
- }
857
- return result;
858
- });
859
- const durationMs = Math.round(performance.now() - startTime);
860
- const status = response.status;
861
- const concurrency = activeRequests;
862
- activeRequests--;
863
- logRequestCompleted({
864
- method,
865
- path,
866
- status,
867
- durationMs,
868
- concurrency
869
- });
870
- if (slowRequestMs > 0 && durationMs > slowRequestMs) logSlowRequest({
871
- method,
872
- path,
873
- durationMs,
874
- threshold: slowRequestMs,
875
- concurrency
876
- });
877
- return response;
878
- };
879
- return enableServerTiming ? runWithTimingCollector(runRequest) : runRequest();
880
- });
881
- });
882
- };
883
- async function runProxyPhase(req, method, path) {
884
- try {
885
- let proxyExport;
886
- if (config.proxyLoader) proxyExport = (await config.proxyLoader()).default;
887
- else proxyExport = config.proxy;
888
- const proxyFn = () => runProxy(proxyExport, req, () => handleRequest(req, method, path));
889
- return await withSpan("timber.proxy", {}, () => enableServerTiming ? withTiming("proxy", "proxy.ts", proxyFn) : proxyFn());
890
- } catch (error) {
891
- logProxyError({ error });
892
- await fireOnRequestError(error, req, "proxy");
893
- if (onPipelineError && error instanceof Error) onPipelineError(error, "proxy");
894
- return new Response(null, { status: 500 });
895
- }
896
- }
897
- async function handleRequest(req, method, path) {
898
- const result = canonicalize(new URL(req.url).pathname, stripTrailingSlash);
899
- if (!result.ok) return new Response(null, { status: result.status });
900
- const canonicalPathname = result.pathname;
901
- if (config.matchMetadataRoute) {
902
- const metaMatch = config.matchMetadataRoute(canonicalPathname);
903
- if (metaMatch) try {
904
- if (metaMatch.isStatic) return await serveStaticMetadataFile(metaMatch);
905
- const mod = await metaMatch.file.load();
906
- if (typeof mod.default !== "function") return new Response("Metadata route must export a default function", { status: 500 });
907
- const handlerResult = await mod.default();
908
- if (handlerResult instanceof Response) return handlerResult;
909
- const contentType = metaMatch.contentType;
910
- let body;
911
- if (typeof handlerResult === "string") body = handlerResult;
912
- else if (contentType === "application/xml") body = serializeSitemap(handlerResult);
913
- else if (contentType === "application/manifest+json") body = JSON.stringify(handlerResult, null, 2);
914
- else body = typeof handlerResult === "string" ? handlerResult : String(handlerResult);
915
- return new Response(body, {
916
- status: 200,
917
- headers: { "Content-Type": `${contentType}; charset=utf-8` }
918
- });
919
- } catch (error) {
920
- logRenderError({
921
- method,
922
- path,
923
- error
924
- });
925
- if (onPipelineError && error instanceof Error) onPipelineError(error, "metadata-route");
926
- return new Response(null, { status: 500 });
927
- }
928
- }
929
- let match = matchRoute(canonicalPathname);
930
- let interception;
931
- const sourceUrl = req.headers.get("X-Timber-URL");
932
- if (sourceUrl && config.interceptionRewrites?.length) {
933
- const intercepted = findInterceptionMatch(canonicalPathname, sourceUrl, config.interceptionRewrites);
934
- if (intercepted) {
935
- const sourceMatch = matchRoute(intercepted.sourcePathname);
936
- if (sourceMatch) {
937
- match = sourceMatch;
938
- interception = { targetPathname: canonicalPathname };
939
- }
940
- }
941
- }
942
- if (!match) {
943
- if (config.renderNoMatch) {
944
- const responseHeaders = new Headers();
945
- return config.renderNoMatch(req, responseHeaders);
946
- }
947
- return new Response(null, { status: 404 });
948
- }
949
- const responseHeaders = new Headers();
950
- const requestHeaderOverlay = new Headers();
951
- responseHeaders.set("Cache-Control", "private, no-cache, no-store, max-age=0, must-revalidate");
952
- if (earlyHints) try {
953
- await earlyHints(match, req, responseHeaders);
954
- } catch {}
955
- if (match.middleware) {
956
- const ctx = {
957
- req,
958
- requestHeaders: requestHeaderOverlay,
959
- headers: responseHeaders,
960
- params: match.params,
961
- searchParams: new URL(req.url).searchParams,
962
- earlyHints: (hints) => {
963
- for (const hint of hints) {
964
- let value = `<${hint.href}>; rel=${hint.rel}`;
965
- if (hint.as !== void 0) value += `; as=${hint.as}`;
966
- if (hint.crossOrigin !== void 0) value += `; crossorigin=${hint.crossOrigin}`;
967
- if (hint.fetchPriority !== void 0) value += `; fetchpriority=${hint.fetchPriority}`;
968
- responseHeaders.append("Link", value);
969
- }
970
- }
971
- };
972
- try {
973
- setMutableCookieContext(true);
974
- const middlewareFn = () => runMiddleware(match.middleware, ctx);
975
- const middlewareResponse = await withSpan("timber.middleware", {}, () => enableServerTiming ? withTiming("mw", "middleware.ts", middlewareFn) : middlewareFn());
976
- setMutableCookieContext(false);
977
- if (middlewareResponse) {
978
- const finalResponse = ensureMutableResponse(middlewareResponse);
979
- applyCookieJar(finalResponse.headers);
980
- logMiddlewareShortCircuit({
981
- method,
982
- path,
983
- status: finalResponse.status
984
- });
985
- return finalResponse;
986
- }
987
- applyRequestHeaderOverlay(requestHeaderOverlay);
988
- } catch (error) {
989
- setMutableCookieContext(false);
990
- if (error instanceof RedirectSignal) {
991
- applyCookieJar(responseHeaders);
992
- if ((req.headers.get("Accept") ?? "").includes("text/x-component")) {
993
- responseHeaders.set("X-Timber-Redirect", error.location);
994
- return new Response(null, {
995
- status: 204,
996
- headers: responseHeaders
997
- });
998
- }
999
- responseHeaders.set("Location", error.location);
1000
- return new Response(null, {
1001
- status: error.status,
1002
- headers: responseHeaders
1003
- });
1004
- }
1005
- if (error instanceof DenySignal) return new Response(null, { status: error.status });
1006
- logMiddlewareError({
1007
- method,
1008
- path,
1009
- error
1010
- });
1011
- await fireOnRequestError(error, req, "handler");
1012
- if (onPipelineError && error instanceof Error) onPipelineError(error, "middleware");
1013
- return new Response(null, { status: 500 });
1014
- }
1015
- }
1016
- applyCookieJar(responseHeaders);
1017
- try {
1018
- const renderFn = () => render(req, match, responseHeaders, requestHeaderOverlay, interception);
1019
- const response = await withSpan("timber.render", { "http.route": canonicalPathname }, () => enableServerTiming ? withTiming("render", "RSC + SSR render", renderFn) : renderFn());
1020
- markResponseFlushed();
1021
- return response;
1022
- } catch (error) {
1023
- if (error instanceof DenySignal) return new Response(null, { status: error.status });
1024
- if (error instanceof RedirectSignal) {
1025
- responseHeaders.set("Location", error.location);
1026
- return new Response(null, {
1027
- status: error.status,
1028
- headers: responseHeaders
1029
- });
1030
- }
1031
- logRenderError({
1032
- method,
1033
- path,
1034
- error
1035
- });
1036
- await fireOnRequestError(error, req, "render");
1037
- if (onPipelineError && error instanceof Error) onPipelineError(error, "render");
1038
- if (config.renderFallbackError) try {
1039
- return await config.renderFallbackError(error, req, responseHeaders);
1040
- } catch {}
1041
- return new Response(null, { status: 500 });
1042
- }
1043
- }
1044
- }
1045
- /**
1046
- * Fire the user's onRequestError hook with request context.
1047
- * Extracts request info from the Request object and calls the instrumentation hook.
1048
- */
1049
- async function fireOnRequestError(error, req, phase) {
1050
- const url = new URL(req.url);
1051
- const headersObj = {};
1052
- req.headers.forEach((v, k) => {
1053
- headersObj[k] = v;
1054
- });
1055
- await callOnRequestError(error, {
1056
- method: req.method,
1057
- path: url.pathname,
1058
- headers: headersObj
1059
- }, {
1060
- phase,
1061
- routePath: url.pathname,
1062
- routeType: "page",
1063
- traceId: traceId()
1064
- });
1065
- }
1066
- /**
1067
- * Apply all Set-Cookie headers from the cookie jar to a Headers object.
1068
- * Each cookie gets its own Set-Cookie header per RFC 6265 §4.1.
1069
- */
1070
- function applyCookieJar(headers) {
1071
- for (const value of getSetCookieHeaders()) headers.append("Set-Cookie", value);
1072
- }
1073
- /**
1074
- * Ensure a Response has mutable headers so the pipeline can safely append
1075
- * Set-Cookie and Server-Timing entries.
1076
- *
1077
- * `Response.redirect()` and some platform-level responses return objects
1078
- * with immutable headers. Calling `.set()` or `.append()` on them throws
1079
- * `TypeError: immutable`. This helper detects the immutable case by
1080
- * attempting a no-op write and, on failure, clones into a fresh Response
1081
- * with mutable headers.
1082
- */
1083
- function ensureMutableResponse(response) {
1084
- try {
1085
- response.headers.set("X-Timber-Probe", "1");
1086
- response.headers.delete("X-Timber-Probe");
1087
- return response;
1088
- } catch {
1089
- return new Response(response.body, {
1090
- status: response.status,
1091
- statusText: response.statusText,
1092
- headers: new Headers(response.headers)
1093
- });
1094
- }
1095
- }
1096
- //#endregion
1097
- //#region src/server/build-manifest.ts
1098
- /**
1099
- * Collect all CSS files needed for a matched route's segment chain.
1100
- *
1101
- * Walks segments root → leaf, collecting CSS for each layout and page.
1102
- * Deduplicates while preserving order (root layout CSS first).
1103
- */
1104
- function collectRouteCss(segments, manifest) {
1105
- const seen = /* @__PURE__ */ new Set();
1106
- const result = [];
1107
- for (const segment of segments) for (const file of [segment.layout, segment.page]) {
1108
- if (!file) continue;
1109
- const cssFiles = manifest.css[file.filePath];
1110
- if (!cssFiles) continue;
1111
- for (const url of cssFiles) if (!seen.has(url)) {
1112
- seen.add(url);
1113
- result.push(url);
1114
- }
1115
- }
1116
- return result;
1117
- }
1118
- /**
1119
- * Collect all font entries needed for a matched route's segment chain.
1120
- *
1121
- * Walks segments root → leaf, collecting fonts for each layout and page.
1122
- * Deduplicates by href while preserving order.
1123
- */
1124
- function collectRouteFonts(segments, manifest) {
1125
- const seen = /* @__PURE__ */ new Set();
1126
- const result = [];
1127
- for (const segment of segments) for (const file of [segment.layout, segment.page]) {
1128
- if (!file) continue;
1129
- const fonts = manifest.fonts[file.filePath];
1130
- if (!fonts) continue;
1131
- for (const entry of fonts) if (!seen.has(entry.href)) {
1132
- seen.add(entry.href);
1133
- result.push(entry);
1134
- }
1135
- }
1136
- return result;
1137
- }
1138
- /**
1139
- * Collect modulepreload URLs for a matched route's segment chain.
1140
- *
1141
- * Walks segments root → leaf, collecting transitive JS dependencies
1142
- * for each layout and page. Deduplicates across segments.
1143
- */
1144
- function collectRouteModulepreloads(segments, manifest) {
1145
- const seen = /* @__PURE__ */ new Set();
1146
- const result = [];
1147
- for (const segment of segments) for (const file of [segment.layout, segment.page]) {
1148
- if (!file) continue;
1149
- const preloads = manifest.modulepreload[file.filePath];
1150
- if (!preloads) continue;
1151
- for (const url of preloads) if (!seen.has(url)) {
1152
- seen.add(url);
1153
- result.push(url);
1154
- }
1155
- }
1156
- return result;
1157
- }
1158
- //#endregion
1159
- //#region src/server/early-hints.ts
1160
- /**
1161
- * 103 Early Hints utilities.
1162
- *
1163
- * Early Hints are sent before the final response to let the browser
1164
- * start fetching critical resources (CSS, fonts, JS) while the server
1165
- * is still rendering.
1166
- *
1167
- * The framework collects hints from two sources:
1168
- * 1. Build manifest — CSS, fonts, and JS chunks known at route-match time
1169
- * 2. ctx.earlyHints() — explicit hints added by middleware or route handlers
1170
- *
1171
- * Both are emitted as Link headers. Cloudflare CDN automatically converts
1172
- * Link headers into 103 Early Hints responses.
1173
- *
1174
- * Design docs: 02-rendering-pipeline.md §"Early Hints (103)"
1175
- */
1176
- /**
1177
- * Format a single EarlyHint as a Link header value.
1178
- *
1179
- * Examples:
1180
- * `</styles/root.css>; rel=preload; as=style`
1181
- * `</fonts/inter.woff2>; rel=preload; as=font; crossorigin=anonymous`
1182
- * `</_timber/client.js>; rel=modulepreload`
1183
- * `<https://fonts.googleapis.com>; rel=preconnect`
1184
- */
1185
- function formatLinkHeader(hint) {
1186
- let value = `<${hint.href}>; rel=${hint.rel}`;
1187
- if (hint.as !== void 0) value += `; as=${hint.as}`;
1188
- if (hint.crossOrigin !== void 0) value += `; crossorigin=${hint.crossOrigin}`;
1189
- if (hint.fetchPriority !== void 0) value += `; fetchpriority=${hint.fetchPriority}`;
1190
- return value;
1191
- }
1192
- /**
1193
- * Collect all Link header strings for a matched route's segment chain.
1194
- *
1195
- * Walks the build manifest to emit hints for:
1196
- * - CSS stylesheets (rel=preload; as=style)
1197
- * - Font assets (rel=preload; as=font; crossorigin)
1198
- * - JS modulepreload hints (rel=modulepreload) — unless skipJs is set
1199
- *
1200
- * Also emits global CSS from the `_global` manifest key. Route files
1201
- * are server components that don't appear in the client bundle, so
1202
- * per-route CSS keying doesn't work with the RSC plugin. The `_global`
1203
- * key contains all CSS assets from the client build — fine for early
1204
- * hints since they're just prefetch signals.
1205
- *
1206
- * Returns formatted Link header strings, deduplicated, root → leaf order.
1207
- * Returns an empty array in dev mode (manifest is empty).
1208
- */
1209
- function collectEarlyHintHeaders(segments, manifest, options) {
1210
- const result = [];
1211
- const seen = /* @__PURE__ */ new Set();
1212
- const add = (header) => {
1213
- if (!seen.has(header)) {
1214
- seen.add(header);
1215
- result.push(header);
1216
- }
1217
- };
1218
- for (const url of collectRouteCss(segments, manifest)) add(formatLinkHeader({
1219
- href: url,
1220
- rel: "preload",
1221
- as: "style"
1222
- }));
1223
- for (const url of manifest.css["_global"] ?? []) add(formatLinkHeader({
1224
- href: url,
1225
- rel: "preload",
1226
- as: "style"
1227
- }));
1228
- for (const font of collectRouteFonts(segments, manifest)) add(formatLinkHeader({
1229
- href: font.href,
1230
- rel: "preload",
1231
- as: "font",
1232
- crossOrigin: "anonymous"
1233
- }));
1234
- if (!options?.skipJs) for (const url of collectRouteModulepreloads(segments, manifest)) add(formatLinkHeader({
1235
- href: url,
1236
- rel: "modulepreload"
1237
- }));
1238
- return result;
1239
- }
1240
- //#endregion
1241
- //#region src/server/early-hints-sender.ts
1242
- /**
1243
- * Per-request 103 Early Hints sender — ALS bridge for platform adapters.
1244
- *
1245
- * The pipeline collects Link headers for CSS, fonts, and JS chunks at
1246
- * route-match time. On platforms that support it (Node.js v18.11+, Bun),
1247
- * the adapter can send these as a 103 Early Hints interim response before
1248
- * the final response is ready.
1249
- *
1250
- * This module provides an ALS-based bridge: the generated entry point
1251
- * (e.g., the Nitro entry) wraps the handler with `runWithEarlyHintsSender`,
1252
- * binding a per-request sender function. The pipeline calls
1253
- * `sendEarlyHints103()` to fire the 103 if a sender is available.
1254
- *
1255
- * On platforms where 103 is handled at the CDN level (e.g., Cloudflare
1256
- * converts Link headers into 103 automatically), no sender is installed
1257
- * and `sendEarlyHints103()` is a no-op.
1258
- *
1259
- * Design doc: 02-rendering-pipeline.md §"Early Hints (103)"
1260
- */
1261
- /**
1262
- * Run a function with a per-request early hints sender installed.
1263
- *
1264
- * Called by generated entry points (e.g., Nitro node-server/bun) to
1265
- * bind the platform's writeEarlyHints capability for the request duration.
1266
- */
1267
- function runWithEarlyHintsSender(sender, fn) {
1268
- return earlyHintsSenderAls.run(sender, fn);
1269
- }
1270
- /**
1271
- * Send collected Link headers as a 103 Early Hints response.
1272
- *
1273
- * No-op if no sender is installed for the current request (e.g., on
1274
- * Cloudflare where the CDN handles 103 automatically, or in dev mode).
1275
- *
1276
- * Non-fatal: errors from the sender are caught and silently ignored.
1277
- */
1278
- function sendEarlyHints103(links) {
1279
- if (!links.length) return;
1280
- const sender = earlyHintsSenderAls.getStore();
1281
- if (!sender) return;
1282
- try {
1283
- sender(links);
1284
- } catch {}
1285
- }
1286
- //#endregion
1287
- //#region src/server/tree-builder.ts
1288
- /**
1289
- * Build the unified element tree from a matched segment chain.
1290
- *
1291
- * Construction is bottom-up:
1292
- * 1. Start with the page component (leaf segment)
1293
- * 2. Wrap in status-code error boundaries (fallback chain)
1294
- * 3. Wrap in AccessGate (if segment has access.ts)
1295
- * 4. Pass as children to the segment's layout
1296
- * 5. Repeat up the segment chain to root
1297
- *
1298
- * Parallel slots are resolved at each layout level and composed as named props.
1299
- */
1300
- async function buildElementTree(config) {
1301
- const { segments, params, searchParams, loadModule, createElement, errorBoundaryComponent } = config;
1302
- if (segments.length === 0) throw new Error("[timber] buildElementTree: empty segment chain");
1303
- const leaf = segments[segments.length - 1];
1304
- if (leaf.route && !leaf.page) return {
1305
- tree: null,
1306
- isApiRoute: true
1307
- };
1308
- const PageComponent = (leaf.page ? await loadModule(leaf.page) : null)?.default;
1309
- if (!PageComponent) throw new Error(`[timber] No page component found for route at ${leaf.urlPath}. Each route must have a page.tsx or route.ts.`);
1310
- let element = createElement(PageComponent, {
1311
- params,
1312
- searchParams
1313
- });
1314
- for (let i = segments.length - 1; i >= 0; i--) {
1315
- const segment = segments[i];
1316
- element = await wrapWithErrorBoundaries(segment, element, loadModule, createElement, errorBoundaryComponent);
1317
- if (segment.access) {
1318
- const accessFn = (await loadModule(segment.access)).default;
1319
- element = createElement("timber:access-gate", {
1320
- accessFn,
1321
- params,
1322
- searchParams,
1323
- segmentName: segment.segmentName,
1324
- children: element
1325
- });
1326
- }
1327
- if (segment.layout) {
1328
- const LayoutComponent = (await loadModule(segment.layout)).default;
1329
- if (LayoutComponent) {
1330
- const slotProps = {};
1331
- if (segment.slots.size > 0) for (const [slotName, slotNode] of segment.slots) slotProps[slotName] = await buildSlotElement(slotNode, params, searchParams, loadModule, createElement, errorBoundaryComponent);
1332
- element = createElement(LayoutComponent, {
1333
- ...slotProps,
1334
- params,
1335
- searchParams,
1336
- children: element
1337
- });
1338
- }
1339
- }
1340
- }
1341
- return {
1342
- tree: element,
1343
- isApiRoute: false
1344
- };
1345
- }
1346
- /**
1347
- * Build the element tree for a parallel slot.
1348
- *
1349
- * Slots have their own access.ts (SlotAccessGate) and error boundaries.
1350
- * On access denial: denied.tsx → default.tsx → null (graceful degradation).
1351
- */
1352
- async function buildSlotElement(slotNode, params, searchParams, loadModule, createElement, errorBoundaryComponent) {
1353
- const PageComponent = (slotNode.page ? await loadModule(slotNode.page) : null)?.default;
1354
- const DefaultComponent = (slotNode.default ? await loadModule(slotNode.default) : null)?.default;
1355
- if (!PageComponent) return DefaultComponent ? createElement(DefaultComponent, {
1356
- params,
1357
- searchParams
1358
- }) : null;
1359
- let element = createElement(PageComponent, {
1360
- params,
1361
- searchParams
1362
- });
1363
- element = await wrapWithErrorBoundaries(slotNode, element, loadModule, createElement, errorBoundaryComponent);
1364
- if (slotNode.access) {
1365
- const accessFn = (await loadModule(slotNode.access)).default;
1366
- const DeniedComponent = (slotNode.denied ? await loadModule(slotNode.denied) : null)?.default;
1367
- element = createElement("timber:slot-access-gate", {
1368
- accessFn,
1369
- params,
1370
- searchParams,
1371
- deniedFallback: DeniedComponent ? createElement(DeniedComponent, {
1372
- slot: slotNode.segmentName.replace(/^@/, ""),
1373
- dangerouslyPassData: void 0
1374
- }) : null,
1375
- defaultFallback: DefaultComponent ? createElement(DefaultComponent, {
1376
- params,
1377
- searchParams
1378
- }) : null,
1379
- children: element
1380
- });
1381
- }
1382
- return element;
1383
- }
1384
- /**
1385
- * Wrap an element with error boundaries from a segment's status-code files.
1386
- *
1387
- * Wrapping order (innermost to outermost):
1388
- * 1. Specific status files (503.tsx, 429.tsx, etc.)
1389
- * 2. Category catch-alls (4xx.tsx, 5xx.tsx)
1390
- * 3. error.tsx (general error boundary)
1391
- *
1392
- * This creates the fallback chain described in design/10-error-handling.md.
1393
- */
1394
- async function wrapWithErrorBoundaries(segment, element, loadModule, createElement, errorBoundaryComponent) {
1395
- if (segment.statusFiles) {
1396
- for (const [key, file] of segment.statusFiles) if (key !== "4xx" && key !== "5xx") {
1397
- const status = parseInt(key, 10);
1398
- if (!isNaN(status)) {
1399
- const Component = (await loadModule(file)).default;
1400
- if (Component) element = createElement(errorBoundaryComponent, {
1401
- fallbackComponent: Component,
1402
- status,
1403
- children: element
1404
- });
1405
- }
1406
- }
1407
- for (const [key, file] of segment.statusFiles) if (key === "4xx" || key === "5xx") {
1408
- const Component = (await loadModule(file)).default;
1409
- if (Component) element = createElement(errorBoundaryComponent, {
1410
- fallbackComponent: Component,
1411
- status: key === "4xx" ? 400 : 500,
1412
- children: element
1413
- });
1414
- }
1415
- }
1416
- if (segment.error) {
1417
- const ErrorComponent = (await loadModule(segment.error)).default;
1418
- if (ErrorComponent) element = createElement(errorBoundaryComponent, {
1419
- fallbackComponent: ErrorComponent,
1420
- children: element
1421
- });
1422
- }
1423
- return element;
1424
- }
1425
- //#endregion
1426
- //#region src/server/access-gate.tsx
1427
- /**
1428
- * AccessGate and SlotAccessGate — framework-injected async server components.
1429
- *
1430
- * AccessGate wraps each segment's layout in the element tree. It calls the
1431
- * segment's access.ts before the layout renders. If access.ts calls deny()
1432
- * or redirect(), the signal propagates as a render-phase throw — caught by
1433
- * the flush controller to produce the correct HTTP status code.
1434
- *
1435
- * SlotAccessGate wraps parallel slot content. On denial, it renders the
1436
- * graceful degradation chain: denied.tsx → default.tsx → null. Slot denial
1437
- * does not affect the HTTP status code.
1438
- *
1439
- * See design/04-authorization.md and design/02-rendering-pipeline.md §"AccessGate"
1440
- */
1441
- /**
1442
- * Framework-injected access gate for segments.
1443
- *
1444
- * When a pre-computed `verdict` prop is provided (from the pre-render pass
1445
- * in route-element-builder.ts), AccessGate replays it synchronously — no
1446
- * async, no re-execution of access.ts, immune to Suspense timing. The OTEL
1447
- * span was already emitted during the pre-render pass.
1448
- *
1449
- * When no verdict is provided (backward compat with tree-builder.ts),
1450
- * AccessGate calls accessFn directly with OTEL instrumentation.
1451
- *
1452
- * access.ts is a pure gate — return values are discarded. The layout below
1453
- * gets the same data by calling the same cached functions (React.cache dedup).
1454
- */
1455
- function AccessGate(props) {
1456
- const { accessFn, params, searchParams, segmentName, verdict, children } = props;
1457
- if (verdict !== void 0) {
1458
- if (verdict === "pass") return children;
1459
- throw verdict;
1460
- }
1461
- return accessGateFallback(accessFn, params, searchParams, segmentName, children);
1462
- }
1463
- /**
1464
- * Async fallback for AccessGate when no pre-computed verdict is available.
1465
- * Calls accessFn with OTEL instrumentation.
1466
- */
1467
- async function accessGateFallback(accessFn, params, searchParams, segmentName, children) {
1468
- await withSpan("timber.access", { "timber.segment": segmentName ?? "unknown" }, async () => {
1469
- try {
1470
- await accessFn({
1471
- params,
1472
- searchParams
1473
- });
1474
- await setSpanAttribute("timber.result", "pass");
1475
- } catch (error) {
1476
- if (error instanceof DenySignal) {
1477
- await setSpanAttribute("timber.result", "deny");
1478
- await setSpanAttribute("timber.deny_status", error.status);
1479
- if (error.sourceFile) await setSpanAttribute("timber.deny_file", error.sourceFile);
1480
- } else if (error instanceof RedirectSignal) await setSpanAttribute("timber.result", "redirect");
1481
- throw error;
1482
- }
1483
- });
1484
- return children;
1485
- }
1486
- /**
1487
- * Framework-injected access gate for parallel slots.
1488
- *
1489
- * On denial, graceful degradation: denied.tsx → default.tsx → null.
1490
- * The HTTP status code is unaffected — slot denial is a UI concern, not
1491
- * a protocol concern. The parent layout and sibling slots still render.
1492
- *
1493
- * redirect() in slot access.ts is a dev-mode error — redirecting from a
1494
- * slot doesn't make architectural sense.
1495
- */
1496
- async function SlotAccessGate(props) {
1497
- const { accessFn, params, searchParams, deniedFallback, defaultFallback, children } = props;
1498
- try {
1499
- await accessFn({
1500
- params,
1501
- searchParams
1502
- });
1503
- } catch (error) {
1504
- if (error instanceof DenySignal) return deniedFallback ?? defaultFallback ?? null;
1505
- if (error instanceof RedirectSignal) {
1506
- if (process.env.NODE_ENV !== "production") console.error("[timber] redirect() is not allowed in slot access.ts. Slots use deny() for graceful degradation — denied.tsx → default.tsx → null. If you need to redirect, move the logic to the parent segment's access.ts.");
1507
- return deniedFallback ?? defaultFallback ?? null;
1508
- }
1509
- if (process.env.NODE_ENV !== "production") console.warn("[timber] Unhandled error in slot access.ts. Use deny() for access control, not unhandled throws.", error);
1510
- throw error;
1511
- }
1512
- return children;
1513
- }
1514
- //#endregion
1515
- //#region src/server/status-code-resolver.ts
1516
- /**
1517
- * Maps legacy file convention names to their corresponding HTTP status codes.
1518
- * Only used in the 4xx component fallback chain.
1519
- */
1520
- var LEGACY_FILE_TO_STATUS = {
1521
- "not-found": 404,
1522
- "forbidden": 403,
1523
- "unauthorized": 401
1524
- };
1525
- /**
1526
- * Resolve the status-code file to render for a given HTTP status code.
1527
- *
1528
- * Walks the segment chain from leaf to root following the fallback chain
1529
- * defined in design/10-error-handling.md. Returns null if no file is found
1530
- * (caller should render the framework default).
1531
- *
1532
- * @param status - The HTTP status code (4xx or 5xx).
1533
- * @param segments - The matched segment chain from root (index 0) to leaf (last).
1534
- * @param format - The response format family ('component' or 'json'). Defaults to 'component'.
1535
- */
1536
- function resolveStatusFile(status, segments, format = "component") {
1537
- if (status >= 400 && status <= 499) return format === "json" ? resolve4xxJson(status, segments) : resolve4xx(status, segments);
1538
- if (status >= 500 && status <= 599) return format === "json" ? resolve5xxJson(status, segments) : resolve5xx(status, segments);
1539
- return null;
1540
- }
1541
- /**
1542
- * 4xx component fallback chain (three separate passes):
1543
- * Pass 1 — status files (leaf → root): {status}.tsx → 4xx.tsx
1544
- * Pass 2 — legacy compat (leaf → root): not-found.tsx / forbidden.tsx / unauthorized.tsx
1545
- * Pass 3 — error.tsx (leaf → root)
1546
- */
1547
- function resolve4xx(status, segments) {
1548
- const statusStr = String(status);
1549
- for (let i = segments.length - 1; i >= 0; i--) {
1550
- const segment = segments[i];
1551
- if (!segment.statusFiles) continue;
1552
- const exact = segment.statusFiles.get(statusStr);
1553
- if (exact) return {
1554
- file: exact,
1555
- status,
1556
- kind: "exact",
1557
- segmentIndex: i
1558
- };
1559
- const category = segment.statusFiles.get("4xx");
1560
- if (category) return {
1561
- file: category,
1562
- status,
1563
- kind: "category",
1564
- segmentIndex: i
1565
- };
1566
- }
1567
- for (let i = segments.length - 1; i >= 0; i--) {
1568
- const segment = segments[i];
1569
- if (!segment.legacyStatusFiles) continue;
1570
- for (const [name, legacyStatus] of Object.entries(LEGACY_FILE_TO_STATUS)) if (legacyStatus === status) {
1571
- const file = segment.legacyStatusFiles.get(name);
1572
- if (file) return {
1573
- file,
1574
- status,
1575
- kind: "legacy",
1576
- segmentIndex: i
1577
- };
1578
- }
1579
- }
1580
- for (let i = segments.length - 1; i >= 0; i--) if (segments[i].error) return {
1581
- file: segments[i].error,
1582
- status,
1583
- kind: "error",
1584
- segmentIndex: i
1585
- };
1586
- return null;
1587
- }
1588
- /**
1589
- * 4xx JSON fallback chain (single pass):
1590
- * Pass 1 — json status files (leaf → root): {status}.json → 4xx.json
1591
- * No legacy compat, no error.tsx — JSON chain terminates at category catch-all.
1592
- */
1593
- function resolve4xxJson(status, segments) {
1594
- const statusStr = String(status);
1595
- for (let i = segments.length - 1; i >= 0; i--) {
1596
- const segment = segments[i];
1597
- if (!segment.jsonStatusFiles) continue;
1598
- const exact = segment.jsonStatusFiles.get(statusStr);
1599
- if (exact) return {
1600
- file: exact,
1601
- status,
1602
- kind: "exact",
1603
- segmentIndex: i
1604
- };
1605
- const category = segment.jsonStatusFiles.get("4xx");
1606
- if (category) return {
1607
- file: category,
1608
- status,
1609
- kind: "category",
1610
- segmentIndex: i
1611
- };
1612
- }
1613
- return null;
1614
- }
1615
- /**
1616
- * 5xx component fallback chain (single pass, per-segment):
1617
- * At each segment (leaf → root): {status}.tsx → 5xx.tsx → error.tsx
1618
- */
1619
- function resolve5xx(status, segments) {
1620
- const statusStr = String(status);
1621
- for (let i = segments.length - 1; i >= 0; i--) {
1622
- const segment = segments[i];
1623
- if (segment.statusFiles) {
1624
- const exact = segment.statusFiles.get(statusStr);
1625
- if (exact) return {
1626
- file: exact,
1627
- status,
1628
- kind: "exact",
1629
- segmentIndex: i
1630
- };
1631
- const category = segment.statusFiles.get("5xx");
1632
- if (category) return {
1633
- file: category,
1634
- status,
1635
- kind: "category",
1636
- segmentIndex: i
1637
- };
1638
- }
1639
- if (segment.error) return {
1640
- file: segment.error,
1641
- status,
1642
- kind: "error",
1643
- segmentIndex: i
1644
- };
1645
- }
1646
- return null;
1647
- }
1648
- /**
1649
- * 5xx JSON fallback chain (single pass):
1650
- * At each segment (leaf → root): {status}.json → 5xx.json
1651
- * No error.tsx equivalent — JSON chain terminates at category catch-all.
1652
- */
1653
- function resolve5xxJson(status, segments) {
1654
- const statusStr = String(status);
1655
- for (let i = segments.length - 1; i >= 0; i--) {
1656
- const segment = segments[i];
1657
- if (!segment.jsonStatusFiles) continue;
1658
- const exact = segment.jsonStatusFiles.get(statusStr);
1659
- if (exact) return {
1660
- file: exact,
1661
- status,
1662
- kind: "exact",
1663
- segmentIndex: i
1664
- };
1665
- const category = segment.jsonStatusFiles.get("5xx");
1666
- if (category) return {
1667
- file: category,
1668
- status,
1669
- kind: "category",
1670
- segmentIndex: i
1671
- };
1672
- }
1673
- return null;
1674
- }
1675
- /**
1676
- * Resolve the denial file for a parallel route slot.
1677
- *
1678
- * Slot denial is graceful degradation — no HTTP status on the wire.
1679
- * Fallback chain: denied.tsx → default.tsx → null.
1680
- *
1681
- * @param slotNode - The segment node for the slot (segmentType === 'slot').
1682
- */
1683
- function resolveSlotDenied(slotNode) {
1684
- const slotName = slotNode.segmentName.replace(/^@/, "");
1685
- if (slotNode.denied) return {
1686
- file: slotNode.denied,
1687
- slotName,
1688
- kind: "denied"
1689
- };
1690
- if (slotNode.default) return {
1691
- file: slotNode.default,
1692
- slotName,
1693
- kind: "default"
1694
- };
1695
- return null;
1696
- }
1697
- //#endregion
1698
- //#region src/server/flush.ts
1699
- /**
1700
- * Flush controller for timber.js rendering.
1701
- *
1702
- * Holds the response until `onShellReady` fires, then commits the HTTP status
1703
- * code and flushes the shell. Render-phase signals (deny, redirect, unhandled
1704
- * throws) caught before flush produce correct HTTP status codes.
1705
- *
1706
- * See design/02-rendering-pipeline.md §"The Flush Point" and §"The Hold Window"
1707
- */
1708
- /**
1709
- * Execute a render and hold the response until the shell is ready.
1710
- *
1711
- * The flush controller:
1712
- * 1. Calls the render function to start renderToReadableStream
1713
- * 2. Waits for shellReady (onShellReady)
1714
- * 3. If a render-phase signal was thrown (deny, redirect, error), produces
1715
- * the correct HTTP status code
1716
- * 4. If the shell rendered successfully, commits the status and streams
1717
- *
1718
- * Render-phase signals caught before flush:
1719
- * - `DenySignal` → HTTP 4xx with appropriate status code
1720
- * - `RedirectSignal` → HTTP 3xx with Location header
1721
- * - `RenderError` → HTTP status from error (default 500)
1722
- * - Unhandled error → HTTP 500
1723
- *
1724
- * @param renderFn - Function that starts the React render.
1725
- * @param options - Flush configuration.
1726
- * @returns The committed HTTP Response.
1727
- */
1728
- async function flushResponse(renderFn, options = {}) {
1729
- const { responseHeaders = new Headers(), defaultStatus = 200 } = options;
1730
- let renderResult;
1731
- try {
1732
- renderResult = await renderFn();
1733
- } catch (error) {
1734
- return handleSignal(error, responseHeaders);
1735
- }
1736
- try {
1737
- await renderResult.shellReady;
1738
- } catch (error) {
1739
- return handleSignal(error, responseHeaders);
1740
- }
1741
- responseHeaders.set("Content-Type", "text/html; charset=utf-8");
1742
- return {
1743
- response: new Response(renderResult.stream, {
1744
- status: defaultStatus,
1745
- headers: responseHeaders
1746
- }),
1747
- status: defaultStatus,
1748
- isRedirect: false,
1749
- isDenial: false
1750
- };
1751
- }
1752
- /**
1753
- * Handle a render-phase signal and produce the correct HTTP response.
1754
- */
1755
- function handleSignal(error, responseHeaders) {
1756
- if (error instanceof RedirectSignal) {
1757
- responseHeaders.set("Location", error.location);
1758
- return {
1759
- response: new Response(null, {
1760
- status: error.status,
1761
- headers: responseHeaders
1762
- }),
1763
- status: error.status,
1764
- isRedirect: true,
1765
- isDenial: false
1766
- };
1767
- }
1768
- if (error instanceof DenySignal) return {
1769
- response: new Response(null, {
1770
- status: error.status,
1771
- headers: responseHeaders
1772
- }),
1773
- status: error.status,
1774
- isRedirect: false,
1775
- isDenial: true
1776
- };
1777
- if (error instanceof RenderError) return {
1778
- response: new Response(null, {
1779
- status: error.status,
1780
- headers: responseHeaders
1781
- }),
1782
- status: error.status,
1783
- isRedirect: false,
1784
- isDenial: false
1785
- };
1786
- console.error("[timber] Unhandled render-phase error:", error);
1787
- return {
1788
- response: new Response(null, {
1789
- status: 500,
1790
- headers: responseHeaders
1791
- }),
1792
- status: 500,
1793
- isRedirect: false,
1794
- isDenial: false
1795
- };
1796
- }
1797
- //#endregion
1798
- //#region src/server/csrf.ts
1799
- /** HTTP methods that are considered safe (no mutation). */
1800
- var SAFE_METHODS = new Set([
1801
- "GET",
1802
- "HEAD",
1803
- "OPTIONS"
1804
- ]);
1805
- /**
1806
- * Validate the Origin header against the request's Host.
1807
- *
1808
- * For mutation methods (POST, PUT, PATCH, DELETE):
1809
- * - If `csrf: false`, skip validation.
1810
- * - If `allowedOrigins` is set, Origin must match one exactly (no wildcards).
1811
- * - Otherwise, Origin's host must match the request's Host header.
1812
- *
1813
- * Safe methods (GET, HEAD, OPTIONS) always pass.
1814
- */
1815
- function validateCsrf(req, config) {
1816
- if (SAFE_METHODS.has(req.method)) return { ok: true };
1817
- if (config.csrf === false) return { ok: true };
1818
- const origin = req.headers.get("Origin");
1819
- if (!origin) return {
1820
- ok: false,
1821
- status: 403
1822
- };
1823
- if (config.allowedOrigins) return config.allowedOrigins.includes(origin) ? { ok: true } : {
1824
- ok: false,
1825
- status: 403
1826
- };
1827
- const host = req.headers.get("Host");
1828
- if (!host) return {
1829
- ok: false,
1830
- status: 403
1831
- };
1832
- let originHost;
1833
- try {
1834
- originHost = new URL(origin).host;
1835
- } catch {
1836
- return {
1837
- ok: false,
1838
- status: 403
1839
- };
1840
- }
1841
- return originHost === host ? { ok: true } : {
1842
- ok: false,
1843
- status: 403
1844
- };
1845
- }
1846
- //#endregion
1847
- //#region src/server/body-limits.ts
1848
- var KB = 1024;
1849
- var MB = 1024 * KB;
1850
- var GB = 1024 * MB;
1851
- var DEFAULT_LIMITS = {
1852
- actionBodySize: 1 * MB,
1853
- uploadBodySize: 10 * MB,
1854
- maxFields: 100
1855
- };
1856
- var SIZE_PATTERN = /^(\d+(?:\.\d+)?)\s*(kb|mb|gb)?$/i;
1857
- /** Parse a human-readable size string ("1mb", "512kb", "1024") into bytes. */
1858
- function parseBodySize(size) {
1859
- const match = SIZE_PATTERN.exec(size.trim());
1860
- if (!match) throw new Error(`Invalid body size format: "${size}". Expected format like "1mb", "512kb", or "1024".`);
1861
- const value = Number.parseFloat(match[1]);
1862
- const unit = (match[2] ?? "").toLowerCase();
1863
- switch (unit) {
1864
- case "kb": return Math.floor(value * KB);
1865
- case "mb": return Math.floor(value * MB);
1866
- case "gb": return Math.floor(value * GB);
1867
- case "": return Math.floor(value);
1868
- default: throw new Error(`Unknown size unit: "${unit}"`);
1869
- }
1870
- }
1871
- /** Check whether a request body exceeds the configured size limit (stateless, no ALS). */
1872
- function enforceBodyLimits(req, kind, config) {
1873
- const contentLength = req.headers.get("Content-Length");
1874
- if (!contentLength) return {
1875
- ok: false,
1876
- status: 411
1877
- };
1878
- const bodySize = Number.parseInt(contentLength, 10);
1879
- if (Number.isNaN(bodySize)) return {
1880
- ok: false,
1881
- status: 411
1882
- };
1883
- return bodySize <= resolveLimit(kind, config) ? { ok: true } : {
1884
- ok: false,
1885
- status: 413
1886
- };
1887
- }
1888
- /**
1889
- * Resolve the byte limit for a given body kind, using config overrides or defaults.
1890
- */
1891
- function resolveLimit(kind, config) {
1892
- const userLimits = config.limits;
1893
- if (kind === "action") return userLimits?.actionBodySize ? parseBodySize(userLimits.actionBodySize) : DEFAULT_LIMITS.actionBodySize;
1894
- return userLimits?.uploadBodySize ? parseBodySize(userLimits.uploadBodySize) : DEFAULT_LIMITS.uploadBodySize;
1895
- }
1896
- //#endregion
1897
- //#region src/server/metadata-social.ts
1898
- /**
1899
- * Render Open Graph metadata into head element descriptors.
1900
- *
1901
- * Handles og:title, og:description, og:image (with dimensions/alt),
1902
- * og:video, og:audio, og:article:author, and other OG properties.
1903
- */
1904
- function renderOpenGraph(og, elements) {
1905
- const simpleProps = [
1906
- ["og:title", og.title],
1907
- ["og:description", og.description],
1908
- ["og:url", og.url],
1909
- ["og:site_name", og.siteName],
1910
- ["og:locale", og.locale],
1911
- ["og:type", og.type],
1912
- ["og:article:published_time", og.publishedTime],
1913
- ["og:article:modified_time", og.modifiedTime]
1914
- ];
1915
- for (const [property, content] of simpleProps) if (content) elements.push({
1916
- tag: "meta",
1917
- attrs: {
1918
- property,
1919
- content
1920
- }
1921
- });
1922
- if (og.images) if (typeof og.images === "string") elements.push({
1923
- tag: "meta",
1924
- attrs: {
1925
- property: "og:image",
1926
- content: og.images
1927
- }
1928
- });
1929
- else {
1930
- const imgList = Array.isArray(og.images) ? og.images : [og.images];
1931
- for (const img of imgList) {
1932
- elements.push({
1933
- tag: "meta",
1934
- attrs: {
1935
- property: "og:image",
1936
- content: img.url
1937
- }
1938
- });
1939
- if (img.width) elements.push({
1940
- tag: "meta",
1941
- attrs: {
1942
- property: "og:image:width",
1943
- content: String(img.width)
1944
- }
1945
- });
1946
- if (img.height) elements.push({
1947
- tag: "meta",
1948
- attrs: {
1949
- property: "og:image:height",
1950
- content: String(img.height)
1951
- }
1952
- });
1953
- if (img.alt) elements.push({
1954
- tag: "meta",
1955
- attrs: {
1956
- property: "og:image:alt",
1957
- content: img.alt
1958
- }
1959
- });
1960
- }
1961
- }
1962
- if (og.videos) for (const video of og.videos) elements.push({
1963
- tag: "meta",
1964
- attrs: {
1965
- property: "og:video",
1966
- content: video.url
1967
- }
1968
- });
1969
- if (og.audio) for (const audio of og.audio) elements.push({
1970
- tag: "meta",
1971
- attrs: {
1972
- property: "og:audio",
1973
- content: audio.url
1974
- }
1975
- });
1976
- if (og.authors) for (const author of og.authors) elements.push({
1977
- tag: "meta",
1978
- attrs: {
1979
- property: "og:article:author",
1980
- content: author
1981
- }
1982
- });
1983
- }
1984
- /**
1985
- * Render Twitter Card metadata into head element descriptors.
1986
- *
1987
- * Handles twitter:card, twitter:site, twitter:title, twitter:image,
1988
- * twitter:player, and twitter:app (per-platform name/id/url).
1989
- */
1990
- function renderTwitter(tw, elements) {
1991
- const simpleProps = [
1992
- ["twitter:card", tw.card],
1993
- ["twitter:site", tw.site],
1994
- ["twitter:site:id", tw.siteId],
1995
- ["twitter:title", tw.title],
1996
- ["twitter:description", tw.description],
1997
- ["twitter:creator", tw.creator],
1998
- ["twitter:creator:id", tw.creatorId]
1999
- ];
2000
- for (const [name, content] of simpleProps) if (content) elements.push({
2001
- tag: "meta",
2002
- attrs: {
2003
- name,
2004
- content
2005
- }
2006
- });
2007
- if (tw.images) if (typeof tw.images === "string") elements.push({
2008
- tag: "meta",
2009
- attrs: {
2010
- name: "twitter:image",
2011
- content: tw.images
2012
- }
2013
- });
2014
- else {
2015
- const imgList = Array.isArray(tw.images) ? tw.images : [tw.images];
2016
- for (const img of imgList) {
2017
- const url = typeof img === "string" ? img : img.url;
2018
- elements.push({
2019
- tag: "meta",
2020
- attrs: {
2021
- name: "twitter:image",
2022
- content: url
2023
- }
2024
- });
2025
- }
2026
- }
2027
- if (tw.players) for (const player of tw.players) {
2028
- elements.push({
2029
- tag: "meta",
2030
- attrs: {
2031
- name: "twitter:player",
2032
- content: player.playerUrl
2033
- }
2034
- });
2035
- if (player.width) elements.push({
2036
- tag: "meta",
2037
- attrs: {
2038
- name: "twitter:player:width",
2039
- content: String(player.width)
2040
- }
2041
- });
2042
- if (player.height) elements.push({
2043
- tag: "meta",
2044
- attrs: {
2045
- name: "twitter:player:height",
2046
- content: String(player.height)
2047
- }
2048
- });
2049
- if (player.streamUrl) elements.push({
2050
- tag: "meta",
2051
- attrs: {
2052
- name: "twitter:player:stream",
2053
- content: player.streamUrl
2054
- }
2055
- });
2056
- }
2057
- if (tw.app) {
2058
- const platforms = [
2059
- ["iPhone", "iphone"],
2060
- ["iPad", "ipad"],
2061
- ["googlePlay", "googleplay"]
2062
- ];
2063
- if (tw.app.name) {
2064
- for (const [key, tag] of platforms) if (tw.app.id?.[key]) elements.push({
2065
- tag: "meta",
2066
- attrs: {
2067
- name: `twitter:app:name:${tag}`,
2068
- content: tw.app.name
2069
- }
2070
- });
2071
- }
2072
- for (const [key, tag] of platforms) {
2073
- const id = tw.app.id?.[key];
2074
- if (id) elements.push({
2075
- tag: "meta",
2076
- attrs: {
2077
- name: `twitter:app:id:${tag}`,
2078
- content: id
2079
- }
2080
- });
2081
- }
2082
- for (const [key, tag] of platforms) {
2083
- const url = tw.app.url?.[key];
2084
- if (url) elements.push({
2085
- tag: "meta",
2086
- attrs: {
2087
- name: `twitter:app:url:${tag}`,
2088
- content: url
2089
- }
2090
- });
2091
- }
2092
- }
2093
- }
2094
- //#endregion
2095
- //#region src/server/metadata-platform.ts
2096
- /**
2097
- * Render icon link elements (favicon, shortcut, apple-touch-icon, custom).
2098
- */
2099
- function renderIcons(icons, elements) {
2100
- if (icons.icon) {
2101
- if (typeof icons.icon === "string") elements.push({
2102
- tag: "link",
2103
- attrs: {
2104
- rel: "icon",
2105
- href: icons.icon
2106
- }
2107
- });
2108
- else if (Array.isArray(icons.icon)) for (const icon of icons.icon) {
2109
- const attrs = {
2110
- rel: "icon",
2111
- href: icon.url
2112
- };
2113
- if (icon.sizes) attrs.sizes = icon.sizes;
2114
- if (icon.type) attrs.type = icon.type;
2115
- elements.push({
2116
- tag: "link",
2117
- attrs
2118
- });
2119
- }
2120
- }
2121
- if (icons.shortcut) {
2122
- const urls = Array.isArray(icons.shortcut) ? icons.shortcut : [icons.shortcut];
2123
- for (const url of urls) elements.push({
2124
- tag: "link",
2125
- attrs: {
2126
- rel: "shortcut icon",
2127
- href: url
2128
- }
2129
- });
2130
- }
2131
- if (icons.apple) {
2132
- if (typeof icons.apple === "string") elements.push({
2133
- tag: "link",
2134
- attrs: {
2135
- rel: "apple-touch-icon",
2136
- href: icons.apple
2137
- }
2138
- });
2139
- else if (Array.isArray(icons.apple)) for (const icon of icons.apple) {
2140
- const attrs = {
2141
- rel: "apple-touch-icon",
2142
- href: icon.url
2143
- };
2144
- if (icon.sizes) attrs.sizes = icon.sizes;
2145
- elements.push({
2146
- tag: "link",
2147
- attrs
2148
- });
2149
- }
2150
- }
2151
- if (icons.other) for (const icon of icons.other) {
2152
- const attrs = {
2153
- rel: icon.rel,
2154
- href: icon.url
2155
- };
2156
- if (icon.sizes) attrs.sizes = icon.sizes;
2157
- if (icon.type) attrs.type = icon.type;
2158
- elements.push({
2159
- tag: "link",
2160
- attrs
2161
- });
2162
- }
2163
- }
2164
- /**
2165
- * Render alternate link elements (canonical, hreflang, media, types).
2166
- */
2167
- function renderAlternates(alternates, elements) {
2168
- if (alternates.canonical) elements.push({
2169
- tag: "link",
2170
- attrs: {
2171
- rel: "canonical",
2172
- href: alternates.canonical
2173
- }
2174
- });
2175
- if (alternates.languages) for (const [lang, href] of Object.entries(alternates.languages)) elements.push({
2176
- tag: "link",
2177
- attrs: {
2178
- rel: "alternate",
2179
- hreflang: lang,
2180
- href
2181
- }
2182
- });
2183
- if (alternates.media) for (const [media, href] of Object.entries(alternates.media)) elements.push({
2184
- tag: "link",
2185
- attrs: {
2186
- rel: "alternate",
2187
- media,
2188
- href
2189
- }
2190
- });
2191
- if (alternates.types) for (const [type, href] of Object.entries(alternates.types)) elements.push({
2192
- tag: "link",
2193
- attrs: {
2194
- rel: "alternate",
2195
- type,
2196
- href
2197
- }
2198
- });
2199
- }
2200
- /**
2201
- * Render site verification meta tags (Google, Yahoo, Yandex, custom).
2202
- */
2203
- function renderVerification(verification, elements) {
2204
- const verificationProps = [
2205
- ["google-site-verification", verification.google],
2206
- ["y_key", verification.yahoo],
2207
- ["yandex-verification", verification.yandex]
2208
- ];
2209
- for (const [name, content] of verificationProps) if (content) elements.push({
2210
- tag: "meta",
2211
- attrs: {
2212
- name,
2213
- content
2214
- }
2215
- });
2216
- if (verification.other) for (const [name, value] of Object.entries(verification.other)) {
2217
- const content = Array.isArray(value) ? value.join(", ") : value;
2218
- elements.push({
2219
- tag: "meta",
2220
- attrs: {
2221
- name,
2222
- content
2223
- }
2224
- });
2225
- }
2226
- }
2227
- /**
2228
- * Render Apple Web App meta tags and startup image links.
2229
- */
2230
- function renderAppleWebApp(appleWebApp, elements) {
2231
- if (appleWebApp.capable) elements.push({
2232
- tag: "meta",
2233
- attrs: {
2234
- name: "apple-mobile-web-app-capable",
2235
- content: "yes"
2236
- }
2237
- });
2238
- if (appleWebApp.title) elements.push({
2239
- tag: "meta",
2240
- attrs: {
2241
- name: "apple-mobile-web-app-title",
2242
- content: appleWebApp.title
2243
- }
2244
- });
2245
- if (appleWebApp.statusBarStyle) elements.push({
2246
- tag: "meta",
2247
- attrs: {
2248
- name: "apple-mobile-web-app-status-bar-style",
2249
- content: appleWebApp.statusBarStyle
2250
- }
2251
- });
2252
- if (appleWebApp.startupImage) {
2253
- const images = Array.isArray(appleWebApp.startupImage) ? appleWebApp.startupImage : [{ url: appleWebApp.startupImage }];
2254
- for (const img of images) {
2255
- const attrs = {
2256
- rel: "apple-touch-startup-image",
2257
- href: typeof img === "string" ? img : img.url
2258
- };
2259
- if (typeof img === "object" && img.media) attrs.media = img.media;
2260
- elements.push({
2261
- tag: "link",
2262
- attrs
2263
- });
2264
- }
2265
- }
2266
- }
2267
- /**
2268
- * Render App Links (al:*) meta tags for deep linking across platforms.
2269
- */
2270
- function renderAppLinks(appLinks, elements) {
2271
- const platformEntries = [
2272
- ["ios", appLinks.ios],
2273
- ["android", appLinks.android],
2274
- ["windows", appLinks.windows],
2275
- ["windows_phone", appLinks.windowsPhone],
2276
- ["windows_universal", appLinks.windowsUniversal]
2277
- ];
2278
- for (const [platform, entries] of platformEntries) {
2279
- if (!entries) continue;
2280
- for (const entry of entries) for (const [key, value] of Object.entries(entry)) if (value !== void 0 && value !== null) elements.push({
2281
- tag: "meta",
2282
- attrs: {
2283
- property: `al:${platform}:${key}`,
2284
- content: String(value)
2285
- }
2286
- });
2287
- }
2288
- if (appLinks.web) {
2289
- if (appLinks.web.url) elements.push({
2290
- tag: "meta",
2291
- attrs: {
2292
- property: "al:web:url",
2293
- content: appLinks.web.url
2294
- }
2295
- });
2296
- if (appLinks.web.shouldFallback !== void 0) elements.push({
2297
- tag: "meta",
2298
- attrs: {
2299
- property: "al:web:should_fallback",
2300
- content: appLinks.web.shouldFallback ? "true" : "false"
2301
- }
2302
- });
2303
- }
2304
- }
2305
- /**
2306
- * Render Apple iTunes smart banner meta tag.
2307
- */
2308
- function renderItunes(itunes, elements) {
2309
- const parts = [`app-id=${itunes.appId}`];
2310
- if (itunes.affiliateData) parts.push(`affiliate-data=${itunes.affiliateData}`);
2311
- if (itunes.appArgument) parts.push(`app-argument=${itunes.appArgument}`);
2312
- elements.push({
2313
- tag: "meta",
2314
- attrs: {
2315
- name: "apple-itunes-app",
2316
- content: parts.join(", ")
2317
- }
2318
- });
2319
- }
2320
- //#endregion
2321
- //#region src/server/metadata-render.ts
2322
- /**
2323
- * Convert resolved metadata into an array of head element descriptors.
2324
- *
2325
- * Each descriptor has a `tag` ('title', 'meta', 'link') and either
2326
- * `content` (for <title>) or `attrs` (for <meta>/<link>).
2327
- *
2328
- * The framework's MetadataResolver component consumes these descriptors
2329
- * and renders them into the <head>.
2330
- */
2331
- function renderMetadataToElements(metadata) {
2332
- const elements = [];
2333
- if (typeof metadata.title === "string") elements.push({
2334
- tag: "title",
2335
- content: metadata.title
2336
- });
2337
- const simpleMetaProps = [
2338
- ["description", metadata.description],
2339
- ["generator", metadata.generator],
2340
- ["application-name", metadata.applicationName],
2341
- ["referrer", metadata.referrer],
2342
- ["category", metadata.category],
2343
- ["creator", metadata.creator],
2344
- ["publisher", metadata.publisher]
2345
- ];
2346
- for (const [name, content] of simpleMetaProps) if (content) elements.push({
2347
- tag: "meta",
2348
- attrs: {
2349
- name,
2350
- content
2351
- }
2352
- });
2353
- if (metadata.keywords) {
2354
- const content = Array.isArray(metadata.keywords) ? metadata.keywords.join(", ") : metadata.keywords;
2355
- elements.push({
2356
- tag: "meta",
2357
- attrs: {
2358
- name: "keywords",
2359
- content
2360
- }
2361
- });
2362
- }
2363
- if (metadata.robots) {
2364
- const content = typeof metadata.robots === "string" ? metadata.robots : renderRobotsObject(metadata.robots);
2365
- elements.push({
2366
- tag: "meta",
2367
- attrs: {
2368
- name: "robots",
2369
- content
2370
- }
2371
- });
2372
- if (typeof metadata.robots === "object" && metadata.robots.googleBot) {
2373
- const gbContent = typeof metadata.robots.googleBot === "string" ? metadata.robots.googleBot : renderRobotsObject(metadata.robots.googleBot);
2374
- elements.push({
2375
- tag: "meta",
2376
- attrs: {
2377
- name: "googlebot",
2378
- content: gbContent
2379
- }
2380
- });
2381
- }
2382
- }
2383
- if (metadata.openGraph) renderOpenGraph(metadata.openGraph, elements);
2384
- if (metadata.twitter) renderTwitter(metadata.twitter, elements);
2385
- if (metadata.icons) renderIcons(metadata.icons, elements);
2386
- if (metadata.manifest) elements.push({
2387
- tag: "link",
2388
- attrs: {
2389
- rel: "manifest",
2390
- href: metadata.manifest
2391
- }
2392
- });
2393
- if (metadata.alternates) renderAlternates(metadata.alternates, elements);
2394
- if (metadata.verification) renderVerification(metadata.verification, elements);
2395
- if (metadata.formatDetection) {
2396
- const parts = [];
2397
- if (metadata.formatDetection.telephone === false) parts.push("telephone=no");
2398
- if (metadata.formatDetection.email === false) parts.push("email=no");
2399
- if (metadata.formatDetection.address === false) parts.push("address=no");
2400
- if (parts.length > 0) elements.push({
2401
- tag: "meta",
2402
- attrs: {
2403
- name: "format-detection",
2404
- content: parts.join(", ")
2405
- }
2406
- });
2407
- }
2408
- if (metadata.authors) {
2409
- const authorList = Array.isArray(metadata.authors) ? metadata.authors : [metadata.authors];
2410
- for (const author of authorList) {
2411
- if (author.name) elements.push({
2412
- tag: "meta",
2413
- attrs: {
2414
- name: "author",
2415
- content: author.name
2416
- }
2417
- });
2418
- if (author.url) elements.push({
2419
- tag: "link",
2420
- attrs: {
2421
- rel: "author",
2422
- href: author.url
2423
- }
2424
- });
2425
- }
2426
- }
2427
- if (metadata.appleWebApp) renderAppleWebApp(metadata.appleWebApp, elements);
2428
- if (metadata.appLinks) renderAppLinks(metadata.appLinks, elements);
2429
- if (metadata.itunes) renderItunes(metadata.itunes, elements);
2430
- if (metadata.other) for (const [name, value] of Object.entries(metadata.other)) {
2431
- const content = Array.isArray(value) ? value.join(", ") : value;
2432
- elements.push({
2433
- tag: "meta",
2434
- attrs: {
2435
- name,
2436
- content
2437
- }
2438
- });
2439
- }
2440
- return elements;
2441
- }
2442
- function renderRobotsObject(robots) {
2443
- const parts = [];
2444
- if (robots.index === true) parts.push("index");
2445
- if (robots.index === false) parts.push("noindex");
2446
- if (robots.follow === true) parts.push("follow");
2447
- if (robots.follow === false) parts.push("nofollow");
2448
- return parts.join(", ");
2449
- }
2450
- //#endregion
2451
- //#region src/server/metadata.ts
2452
- /**
2453
- * Resolve a title value with an optional template.
2454
- *
2455
- * - string → apply template if present
2456
- * - { absolute: '...' } → use as-is, skip template
2457
- * - { default: '...' } → use as fallback (no template applied)
2458
- * - undefined → undefined
2459
- */
2460
- function resolveTitle(title, template) {
2461
- if (title === void 0 || title === null) return;
2462
- if (typeof title === "string") return template ? template.replace("%s", title) : title;
2463
- if (title.absolute !== void 0) return title.absolute;
2464
- if (title.default !== void 0) return title.default;
2465
- }
2466
- /**
2467
- * Resolve metadata from a segment chain.
2468
- *
2469
- * Processes entries from root layout to page (in segment order).
2470
- * The merge algorithm:
2471
- * 1. Shallow-merge all keys except title (later wins)
2472
- * 2. Track the most recent title template
2473
- * 3. Resolve the final title using the template
2474
- *
2475
- * In error state, the page entry is dropped and noindex is injected.
7
+ * Next.js redirect type discriminator.
2476
8
  *
2477
- * See design/16-metadata.md §"Merge Algorithm"
2478
- */
2479
- function resolveMetadata(entries, options = {}) {
2480
- const { errorState = false } = options;
2481
- const merged = {};
2482
- let titleTemplate;
2483
- let lastDefault;
2484
- let rawTitle;
2485
- for (const { metadata, isPage } of entries) {
2486
- if (errorState && isPage) continue;
2487
- if (metadata.title !== void 0 && typeof metadata.title === "object") {
2488
- if (metadata.title.template !== void 0) titleTemplate = metadata.title.template;
2489
- if (metadata.title.default !== void 0) lastDefault = metadata.title.default;
2490
- }
2491
- for (const key of Object.keys(metadata)) {
2492
- if (key === "title") continue;
2493
- merged[key] = metadata[key];
2494
- }
2495
- if (metadata.title !== void 0) rawTitle = metadata.title;
2496
- }
2497
- if (errorState) {
2498
- rawTitle = lastDefault !== void 0 ? { default: lastDefault } : rawTitle;
2499
- titleTemplate = void 0;
2500
- }
2501
- const resolvedTitle = resolveTitle(rawTitle, titleTemplate);
2502
- if (resolvedTitle !== void 0) merged.title = resolvedTitle;
2503
- if (errorState) merged.robots = "noindex";
2504
- return merged;
2505
- }
2506
- /**
2507
- * Check if a string is an absolute URL.
2508
- */
2509
- function isAbsoluteUrl(url) {
2510
- return url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//");
2511
- }
2512
- /**
2513
- * Resolve a relative URL against a base URL.
2514
- */
2515
- function resolveUrl(url, base) {
2516
- if (isAbsoluteUrl(url)) return url;
2517
- return new URL(url, base).toString();
2518
- }
2519
- /**
2520
- * Resolve relative URLs in metadata fields against metadataBase.
9
+ * Provided for API compatibility with libraries that import `RedirectType`
10
+ * from `next/navigation`. In timber, `redirect()` always uses `replace`
11
+ * semantics (no history entry for the redirect itself).
2521
12
  *
2522
- * Returns a new metadata object with URLs resolved. Absolute URLs are not modified.
2523
- * If metadataBase is not set, returns the metadata unchanged.
13
+ * Lives in shared/ (isomorphic) so both the server primitives and the
14
+ * client-only next/navigation shim export the same definition without the
15
+ * client shim pulling in server code.
2524
16
  */
2525
- function resolveMetadataUrls(metadata) {
2526
- const base = metadata.metadataBase;
2527
- if (!base) return metadata;
2528
- const result = { ...metadata };
2529
- if (result.openGraph) {
2530
- result.openGraph = { ...result.openGraph };
2531
- if (typeof result.openGraph.images === "string") result.openGraph.images = resolveUrl(result.openGraph.images, base);
2532
- else if (Array.isArray(result.openGraph.images)) result.openGraph.images = result.openGraph.images.map((img) => ({
2533
- ...img,
2534
- url: resolveUrl(img.url, base)
2535
- }));
2536
- else if (result.openGraph.images) result.openGraph.images = {
2537
- ...result.openGraph.images,
2538
- url: resolveUrl(result.openGraph.images.url, base)
2539
- };
2540
- if (result.openGraph.url && !isAbsoluteUrl(result.openGraph.url)) result.openGraph.url = resolveUrl(result.openGraph.url, base);
2541
- }
2542
- if (result.twitter) {
2543
- result.twitter = { ...result.twitter };
2544
- if (typeof result.twitter.images === "string") result.twitter.images = resolveUrl(result.twitter.images, base);
2545
- else if (Array.isArray(result.twitter.images)) {
2546
- const resolved = result.twitter.images.map((img) => typeof img === "string" ? resolveUrl(img, base) : {
2547
- ...img,
2548
- url: resolveUrl(img.url, base)
2549
- });
2550
- const allStrings = resolved.every((r) => typeof r === "string");
2551
- result.twitter.images = allStrings ? resolved : resolved;
2552
- } else if (result.twitter.images) result.twitter.images = {
2553
- ...result.twitter.images,
2554
- url: resolveUrl(result.twitter.images.url, base)
2555
- };
2556
- }
2557
- if (result.alternates) {
2558
- result.alternates = { ...result.alternates };
2559
- if (result.alternates.canonical && !isAbsoluteUrl(result.alternates.canonical)) result.alternates.canonical = resolveUrl(result.alternates.canonical, base);
2560
- if (result.alternates.languages) {
2561
- const langs = {};
2562
- for (const [lang, url] of Object.entries(result.alternates.languages)) langs[lang] = isAbsoluteUrl(url) ? url : resolveUrl(url, base);
2563
- result.alternates.languages = langs;
2564
- }
2565
- }
2566
- if (result.icons) {
2567
- result.icons = { ...result.icons };
2568
- if (typeof result.icons.icon === "string") result.icons.icon = resolveUrl(result.icons.icon, base);
2569
- else if (Array.isArray(result.icons.icon)) result.icons.icon = result.icons.icon.map((i) => ({
2570
- ...i,
2571
- url: resolveUrl(i.url, base)
2572
- }));
2573
- if (typeof result.icons.apple === "string") result.icons.apple = resolveUrl(result.icons.apple, base);
2574
- else if (Array.isArray(result.icons.apple)) result.icons.apple = result.icons.apple.map((i) => ({
2575
- ...i,
2576
- url: resolveUrl(i.url, base)
2577
- }));
2578
- }
2579
- return result;
2580
- }
17
+ var RedirectType = {
18
+ push: "push",
19
+ replace: "replace"
20
+ };
2581
21
  //#endregion
2582
- //#region src/server/form-data.ts
2583
- /**
2584
- * FormData preprocessing — schema-agnostic conversion of FormData to typed objects.
2585
- *
2586
- * FormData is all strings. Schema validation expects typed values. This module
2587
- * bridges the gap with intelligent coercion that runs *before* schema validation.
2588
- *
2589
- * Inspired by zod-form-data, but schema-agnostic — works with any Standard Schema
2590
- * library (Zod, Valibot, ArkType).
2591
- *
2592
- * See design/08-forms-and-actions.md §"parseFormData() and coerce helpers"
2593
- */
2594
- /**
2595
- * Convert FormData into a plain object with intelligent coercion.
2596
- *
2597
- * Handles:
2598
- * - **Duplicate keys → arrays**: `tags=js&tags=ts` → `{ tags: ["js", "ts"] }`
2599
- * - **Nested dot-paths**: `user.name=Alice` → `{ user: { name: "Alice" } }`
2600
- * - **Empty strings → undefined**: Enables `.optional()` semantics in schemas
2601
- * - **Empty Files → undefined**: File inputs with no selection become `undefined`
2602
- * - **Strips `$ACTION_*` fields**: React's internal hidden fields are excluded
2603
- */
2604
- function parseFormData(formData) {
2605
- const flat = {};
2606
- for (const key of new Set(formData.keys())) {
2607
- if (key.startsWith("$ACTION_")) continue;
2608
- const processed = formData.getAll(key).map(normalizeValue);
2609
- if (processed.length === 1) flat[key] = processed[0];
2610
- else flat[key] = processed.filter((v) => v !== void 0);
2611
- }
2612
- return expandDotPaths(flat);
2613
- }
2614
- /**
2615
- * Normalize a single FormData entry value.
2616
- * - Empty strings → undefined (enables .optional() semantics)
2617
- * - Empty File objects (no selection) → undefined
2618
- * - Everything else passes through as-is
2619
- */
2620
- function normalizeValue(value) {
2621
- if (typeof value === "string") return value === "" ? void 0 : value;
2622
- if (value instanceof File && value.size === 0 && value.name === "") return;
2623
- return value;
2624
- }
22
+ //#region src/server/sensitive-fields.ts
23
+ /**
24
+ * Sensitive field stripping — removes password/token/CVV-style fields
25
+ * from form values before they are echoed back to the client as
26
+ * `submittedValues` for form repopulation.
27
+ *
28
+ * Applied to both action paths:
29
+ * - With-JS action path: `createActionClient()` in `action-client.ts`
30
+ * - No-JS form POST path: `handleFormAction()` in `action-handler.ts`
31
+ *
32
+ * Why: on a validation failure, timber echoes submitted form values back so
33
+ * the user doesn't have to re-type everything. Without filtering, plaintext
34
+ * passwords / credit-card numbers / TOTP codes would travel through the RSC
35
+ * stream (with-JS) or land in the HTML as `defaultValue` attributes (no-JS)
36
+ * — ending up in browser history, proxy logs, disk caches, and the
37
+ * back-forward cache.
38
+ *
39
+ * Safe by default: the built-in deny-list is applied unconditionally unless
40
+ * the user explicitly opts out via `forms.stripSensitiveFields: false` in
41
+ * `timber.config.ts` or per-action via `createActionClient({ stripSensitiveFields: false })`.
42
+ *
43
+ * See design/08-forms-and-actions.md §"Validation errors"
44
+ * See design/13-security.md §"Sensitive field stripping"
45
+ * See TIM-816
46
+ */
47
+ /**
48
+ * Substring patterns matched against the normalized field name.
49
+ * Normalization = lowercase + strip `_` and `-`.
50
+ *
51
+ * Any field whose normalized name *contains* one of these strings is
52
+ * considered sensitive. Entries like `currentPassword`, `passwordConfirmation`,
53
+ * and `user.password` all match via the `password` substring.
54
+ */
55
+ var BUILTIN_SUBSTRING_PATTERNS = [
56
+ "password",
57
+ "passwd",
58
+ "pwd",
59
+ "secret",
60
+ "apikey",
61
+ "accesstoken",
62
+ "refreshtoken",
63
+ "cvv",
64
+ "cvc",
65
+ "cardnumber",
66
+ "cardcvc",
67
+ "ssn",
68
+ "socialsecuritynumber",
69
+ "otp",
70
+ "totp",
71
+ "mfacode",
72
+ "twofactorcode",
73
+ "privatekey"
74
+ ];
2625
75
  /**
2626
- * Expand dot-notation keys into nested objects.
2627
- * `{ "user.name": "Alice", "user.age": "30" }` → `{ user: { name: "Alice", age: "30" } }`
2628
- *
2629
- * Keys without dots are left as-is. Bracket notation (e.g. `items[0]`) is NOT
2630
- * supported — use dot notation (`items.0`) instead.
2631
- */
2632
- function expandDotPaths(flat) {
76
+ * Exact matches against the normalized field name. These are field names that
77
+ * are too short or too common to substring-match safely. e.g. `token` alone
78
+ * would match `csrfToken`, which is not sensitive — so `token` is exact-only,
79
+ * while legitimate token fields are covered by `accesstoken` / `refreshtoken`.
80
+ */
81
+ var BUILTIN_EXACT_PATTERNS = ["token"];
82
+ /**
83
+ * Normalize a field name for deny-list comparison.
84
+ * Lowercases the string and strips `_` and `-` so camelCase, snake_case, and
85
+ * kebab-case variants all compare equal (`api_key` / `apiKey` / `api-key` →
86
+ * `apikey`).
87
+ */
88
+ function normalize(name) {
89
+ let out = "";
90
+ for (let i = 0; i < name.length; i++) {
91
+ const ch = name.charCodeAt(i);
92
+ if (ch === 95 || ch === 45) continue;
93
+ if (ch >= 65 && ch <= 90) out += String.fromCharCode(ch + 32);
94
+ else out += name[i];
95
+ }
96
+ return out;
97
+ }
98
+ /**
99
+ * Check whether a name matches the built-in deny-list (with optional extras).
100
+ * Extras are merged into the substring pattern list after normalization.
101
+ */
102
+ function isBuiltinSensitive(name, extras) {
103
+ const normalized = normalize(name);
104
+ if (BUILTIN_EXACT_PATTERNS.includes(normalized)) return true;
105
+ for (const pattern of BUILTIN_SUBSTRING_PATTERNS) if (normalized.includes(pattern)) return true;
106
+ if (extras && extras.length > 0) for (const extra of extras) {
107
+ const normExtra = normalize(extra);
108
+ if (normExtra.length === 0) continue;
109
+ if (normalized.includes(normExtra)) return true;
110
+ }
111
+ return false;
112
+ }
113
+ /**
114
+ * Resolve a `SensitiveFieldsOption` into a concrete predicate.
115
+ * Precedence: per-action > global > built-in default.
116
+ *
117
+ * - Per-action `undefined` → fall back to global.
118
+ * - Global `undefined` → use built-in list.
119
+ * - Either level set to `false` → disable stripping entirely (returns `null`).
120
+ * - `true` → built-in list.
121
+ * - `string[]` → built-in ∪ extras.
122
+ * - function → custom, replaces the built-in list entirely.
123
+ */
124
+ function resolveSensitivePredicate(perAction, global) {
125
+ const chosen = perAction !== void 0 ? perAction : global;
126
+ if (chosen === false) return null;
127
+ if (chosen === void 0 || chosen === true) return (name) => isBuiltinSensitive(name);
128
+ if (typeof chosen === "function") return chosen;
129
+ const extras = chosen;
130
+ return (name) => isBuiltinSensitive(name, extras);
131
+ }
132
+ var warnedFields = /* @__PURE__ */ new Set();
133
+ function warnStripped(name) {
134
+ if (!isDebug()) return;
135
+ if (warnedFields.has(name)) return;
136
+ warnedFields.add(name);
137
+ console.warn(`[timber] stripped sensitive field "${name}" from submittedValues. Override via forms.stripSensitiveFields in timber.config.ts.`);
138
+ }
139
+ /**
140
+ * Walk an object (recursively) and return a copy with every key matching
141
+ * `predicate` removed. Nested objects like `{ user: { password: '...' } }`
142
+ * are handled — `user.password` is stripped while other `user.*` fields remain.
143
+ *
144
+ * - Arrays are walked element-wise (object entries inside arrays are cleaned).
145
+ * - Non-plain values (strings, numbers, Files, Dates, etc.) are returned as-is.
146
+ * - When a stripped key is encountered, it is omitted from the result entirely
147
+ * — we do NOT set it to an empty string, because that would overwrite a
148
+ * valid `defaultValue` the form author might have set.
149
+ */
150
+ function stripSensitiveFields(value, predicate) {
151
+ if (predicate === null) return value;
152
+ if (value === null || value === void 0) return value;
153
+ if (typeof value !== "object") return value;
154
+ if (value instanceof File || value instanceof Date) return value;
155
+ if (Array.isArray(value)) return value.map((item) => stripSensitiveFields(item, predicate));
2633
156
  const result = {};
2634
- let hasDotPaths = false;
2635
- for (const key of Object.keys(flat)) if (key.includes(".")) {
2636
- hasDotPaths = true;
2637
- break;
2638
- }
2639
- if (!hasDotPaths) return flat;
2640
- for (const [key, value] of Object.entries(flat)) {
2641
- if (!key.includes(".")) {
2642
- result[key] = value;
157
+ for (const [key, nested] of Object.entries(value)) {
158
+ if (predicate(key)) {
159
+ warnStripped(key);
2643
160
  continue;
2644
161
  }
2645
- const parts = key.split(".");
2646
- let current = result;
2647
- for (let i = 0; i < parts.length - 1; i++) {
2648
- const part = parts[i];
2649
- if (current[part] === void 0 || current[part] === null) current[part] = {};
2650
- if (typeof current[part] !== "object" || current[part] instanceof File) current[part] = {};
2651
- current = current[part];
2652
- }
2653
- current[parts[parts.length - 1]] = value;
162
+ result[key] = stripSensitiveFields(nested, predicate);
2654
163
  }
2655
164
  return result;
2656
165
  }
2657
- /**
2658
- * Schema-agnostic coercion primitives for common FormData patterns.
2659
- *
2660
- * These are plain transform functions — they compose with any schema library's
2661
- * `transform`/`preprocess` pipeline:
2662
- *
2663
- * ```ts
2664
- * // Zod
2665
- * z.preprocess(coerce.number, z.number())
2666
- * // Valibot
2667
- * v.pipe(v.unknown(), v.transform(coerce.number), v.number())
2668
- * ```
2669
- */
2670
- var coerce = {
2671
- number(value) {
2672
- if (value === void 0 || value === null || value === "") return void 0;
2673
- if (typeof value === "number") return value;
2674
- if (typeof value !== "string") return void 0;
2675
- const num = Number(value);
2676
- if (Number.isNaN(num)) return void 0;
2677
- return num;
2678
- },
2679
- checkbox(value) {
2680
- if (value === void 0 || value === null || value === "") return false;
2681
- if (typeof value === "boolean") return value;
2682
- return typeof value === "string" && value.length > 0;
2683
- },
2684
- json(value) {
2685
- if (value === void 0 || value === null || value === "") return void 0;
2686
- if (typeof value !== "string") return value;
2687
- try {
2688
- return JSON.parse(value);
2689
- } catch {
2690
- return;
2691
- }
2692
- }
2693
- };
2694
166
  //#endregion
2695
167
  //#region src/server/action-client.ts
2696
168
  /**
@@ -2703,7 +175,7 @@ var coerce = {
2703
175
  * 1. Direct call: action(input) → Promise<ActionResult>
2704
176
  * 2. React useActionState: (prevState, formData) => Promise<ActionResult>
2705
177
  *
2706
- * See design/08-forms-and-actions.md §"Middleware for Server Actions"
178
+ * See design/08-forms-and-actions.md §"Middleware and Server Actions"
2707
179
  */
2708
180
  /**
2709
181
  * Typed error class for server actions. Carries a string code and optional data.
@@ -2791,7 +263,7 @@ function handleActionError(error) {
2791
263
  } };
2792
264
  return { serverError: {
2793
265
  code: "INTERNAL_ERROR",
2794
- ...typeof process !== "undefined" && process.env.NODE_ENV !== "production" && error instanceof Error ? { data: { message: error.message } } : {}
266
+ ...isDevMode() && error instanceof Error ? { data: { message: error.message } } : {}
2795
267
  } };
2796
268
  }
2797
269
  /**
@@ -2821,55 +293,64 @@ function createActionClient(config = {}) {
2821
293
  const ctx = await runActionMiddleware(config.middleware);
2822
294
  let rawInput;
2823
295
  if (args.length === 2 && args[1] instanceof FormData) rawInput = schema ? parseFormData(args[1]) : args[1];
296
+ else if (args.length === 1 && args[0] instanceof FormData) rawInput = schema ? parseFormData(args[0]) : args[0];
2824
297
  else rawInput = args[0];
298
+ const sensitivePredicate = resolveSensitivePredicate(config.stripSensitiveFields, void 0);
299
+ const buildSubmittedValues = () => {
300
+ const withoutFiles = stripFiles(rawInput);
301
+ if (withoutFiles === void 0) return void 0;
302
+ return stripSensitiveFields(withoutFiles, sensitivePredicate);
303
+ };
2825
304
  if (config.fileSizeLimit !== void 0 && rawInput && typeof rawInput === "object") {
2826
305
  const fileSizeErrors = validateFileSizes(rawInput, config.fileSizeLimit);
2827
306
  if (fileSizeErrors) return {
2828
307
  validationErrors: fileSizeErrors,
2829
- submittedValues: stripFiles(rawInput)
308
+ submittedValues: buildSubmittedValues()
2830
309
  };
2831
310
  }
2832
- const submittedValues = schema ? stripFiles(rawInput) : void 0;
311
+ const submittedValues = schema ? buildSubmittedValues() : void 0;
2833
312
  let input;
2834
- if (schema) if (isStandardSchema(schema)) {
2835
- const result = schema["~standard"].validate(rawInput);
2836
- if (result instanceof Promise) throw new Error("[timber] createActionClient: schema returned a Promise — only sync schemas are supported.");
2837
- if (result.issues) {
2838
- const validationErrors = extractStandardSchemaErrors(result.issues);
2839
- logValidationFailure(validationErrors);
2840
- return {
2841
- validationErrors,
2842
- submittedValues
2843
- };
2844
- }
2845
- input = result.value;
2846
- } else if (typeof schema.safeParse === "function") {
2847
- const result = schema.safeParse(rawInput);
2848
- if (!result.success) {
2849
- const validationErrors = extractValidationErrors(result.error);
313
+ if (schema) {
314
+ if (isStandardSchema(schema)) {
315
+ const result = schema["~standard"].validate(rawInput);
316
+ if (result instanceof Promise) throw new Error("[timber] createActionClient: schema returned a Promise — only sync schemas are supported.");
317
+ if (result.issues) {
318
+ const validationErrors = extractStandardSchemaErrors(result.issues);
319
+ logValidationFailure(validationErrors);
320
+ return {
321
+ validationErrors,
322
+ submittedValues
323
+ };
324
+ }
325
+ input = result.value;
326
+ } else if (typeof schema.safeParse === "function") {
327
+ const result = schema.safeParse(rawInput);
328
+ if (!result.success) {
329
+ const validationErrors = extractValidationErrors(result.error);
330
+ logValidationFailure(validationErrors);
331
+ return {
332
+ validationErrors,
333
+ submittedValues
334
+ };
335
+ }
336
+ input = result.data;
337
+ } else try {
338
+ input = schema.parse(rawInput);
339
+ } catch (parseError) {
340
+ const validationErrors = extractValidationErrors(parseError);
2850
341
  logValidationFailure(validationErrors);
2851
342
  return {
2852
343
  validationErrors,
2853
344
  submittedValues
2854
345
  };
2855
346
  }
2856
- input = result.data;
2857
- } else try {
2858
- input = schema.parse(rawInput);
2859
- } catch (parseError) {
2860
- const validationErrors = extractValidationErrors(parseError);
2861
- logValidationFailure(validationErrors);
2862
- return {
2863
- validationErrors,
2864
- submittedValues
2865
- };
2866
- }
2867
- else input = rawInput;
347
+ } else input = rawInput;
2868
348
  return { data: await fn({
2869
349
  ctx,
2870
350
  input
2871
351
  }) };
2872
352
  } catch (error) {
353
+ if (isRedirectSignal(error) || isDenySignal(error)) throw error;
2873
354
  return handleActionError(error);
2874
355
  }
2875
356
  }
@@ -2912,7 +393,7 @@ function validated(schema, handler) {
2912
393
  * In production, validation errors are only returned to the client.
2913
394
  */
2914
395
  function logValidationFailure(errors) {
2915
- if (!(typeof process !== "undefined" && process.env.NODE_ENV !== "production")) return;
396
+ if (!isDebug()) return;
2916
397
  const fields = Object.entries(errors).map(([field, messages]) => ` ${field}: ${messages.join(", ")}`).join("\n");
2917
398
  console.warn(`[timber] action schema validation failed:\n${fields}`);
2918
399
  }
@@ -2921,14 +402,23 @@ function logValidationFailure(errors) {
2921
402
  * Returns validation errors keyed by field name, or null if all files are ok.
2922
403
  */
2923
404
  function validateFileSizes(input, limit) {
2924
- const errors = {};
2925
405
  const limitKb = Math.round(limit / 1024);
2926
- const limitLabel = limit >= 1024 * 1024 ? `${Math.round(limit / (1024 * 1024))}MB` : `${limitKb}KB`;
2927
- for (const [key, value] of Object.entries(input)) if (value instanceof File && value.size > limit) errors[key] = [`File "${value.name}" (${formatSize(value.size)}) exceeds the ${limitLabel} limit`];
2928
- else if (Array.isArray(value)) {
2929
- const oversized = value.filter((item) => item instanceof File && item.size > limit);
2930
- if (oversized.length > 0) errors[key] = oversized.map((f) => `File "${f.name}" (${formatSize(f.size)}) exceeds the ${limitLabel} limit`);
406
+ const limitLabel = limit >= 1048576 ? `${Math.round(limit / 1048576)}MB` : `${limitKb}KB`;
407
+ const errors = {};
408
+ function walk(obj, prefix) {
409
+ for (const [key, value] of Object.entries(obj)) {
410
+ const path = prefix ? `${prefix}.${key}` : key;
411
+ if (value instanceof File && value.size > limit) errors[path] = [`File "${value.name}" (${formatSize(value.size)}) exceeds the ${limitLabel} limit`];
412
+ else if (Array.isArray(value)) for (let i = 0; i < value.length; i++) {
413
+ const item = value[i];
414
+ const itemPath = `${path}[${i}]`;
415
+ if (item instanceof File && item.size > limit) (errors[itemPath] ??= []).push(`File "${item.name}" (${formatSize(item.size)}) exceeds the ${limitLabel} limit`);
416
+ else if (typeof item === "object" && item !== null && !(item instanceof File)) walk(item, itemPath);
417
+ }
418
+ else if (typeof value === "object" && value !== null && !(value instanceof File)) walk(value, path);
419
+ }
2931
420
  }
421
+ walk(input, "");
2932
422
  return Object.keys(errors).length > 0 ? errors : null;
2933
423
  }
2934
424
  /**
@@ -2941,7 +431,7 @@ function stripFiles(value) {
2941
431
  const result = {};
2942
432
  for (const [k, v] of Object.entries(value)) {
2943
433
  if (v instanceof File) continue;
2944
- if (Array.isArray(v)) result[k] = v.filter((item) => !(item instanceof File));
434
+ if (Array.isArray(v)) result[k] = v.filter((item) => !(item instanceof File)).map((item) => typeof item === "object" && item !== null && !(item instanceof File) ? stripFiles(item) ?? {} : item);
2945
435
  else if (typeof v === "object" && v !== null && !(v instanceof File)) result[k] = stripFiles(v) ?? {};
2946
436
  else result[k] = v;
2947
437
  }
@@ -2978,214 +468,6 @@ function getFormFlash() {
2978
468
  return formFlashAls.getStore() ?? null;
2979
469
  }
2980
470
  //#endregion
2981
- //#region src/server/actions.ts
2982
- /**
2983
- * Get the current revalidation state. Throws if called outside an action context.
2984
- * @internal
2985
- */
2986
- function getRevalidationState() {
2987
- const state = revalidationAls.getStore();
2988
- if (!state) throw new Error("revalidatePath/revalidateTag called outside of a server action context. These functions can only be called during action execution.");
2989
- return state;
2990
- }
2991
- /**
2992
- * Re-render the route at `path` and include the RSC flight payload in the
2993
- * action response. The client reconciles inline — no separate fetch needed.
2994
- *
2995
- * Can be called from server actions, API routes, or any server-side context.
2996
- *
2997
- * @param path - The path to re-render (e.g. '/dashboard', '/todos').
2998
- */
2999
- function revalidatePath(path) {
3000
- const state = getRevalidationState();
3001
- if (!state.paths.includes(path)) state.paths.push(path);
3002
- }
3003
- /**
3004
- * Invalidate all pre-rendered shells and 'use cache' entries tagged with `tag`.
3005
- * Does not return a payload — the next request for an invalidated route re-renders fresh.
3006
- *
3007
- * @param tag - The cache tag to invalidate (e.g. 'products', 'user:123').
3008
- */
3009
- function revalidateTag(tag) {
3010
- const state = getRevalidationState();
3011
- if (!state.tags.includes(tag)) state.tags.push(tag);
3012
- }
3013
- /**
3014
- * Execute a server action and process revalidation.
3015
- *
3016
- * 1. Sets up revalidation state
3017
- * 2. Calls the action function
3018
- * 3. Processes revalidateTag calls (invalidates cache entries)
3019
- * 4. Processes revalidatePath calls (re-renders and captures RSC payload)
3020
- * 5. Returns the action result + optional RSC payload
3021
- *
3022
- * @param actionFn - The server action function to execute.
3023
- * @param args - Arguments to pass to the action.
3024
- * @param config - Handler configuration (cache handler, renderer).
3025
- */
3026
- async function executeAction(actionFn, args, config = {}, spanMeta) {
3027
- const state = {
3028
- paths: [],
3029
- tags: []
3030
- };
3031
- let actionResult;
3032
- let redirectTo;
3033
- let redirectStatus;
3034
- await revalidationAls.run(state, async () => {
3035
- try {
3036
- actionResult = await withSpan("timber.action", {
3037
- ...spanMeta?.actionFile ? { "timber.action_file": spanMeta.actionFile } : {},
3038
- ...spanMeta?.actionName ? { "timber.action_name": spanMeta.actionName } : {}
3039
- }, () => actionFn(...args));
3040
- } catch (error) {
3041
- if (error instanceof RedirectSignal) {
3042
- redirectTo = error.location;
3043
- redirectStatus = error.status;
3044
- } else throw error;
3045
- }
3046
- });
3047
- if (state.tags.length > 0 && config.cacheHandler) await Promise.all(state.tags.map((tag) => config.cacheHandler.invalidate({ tag })));
3048
- let revalidation;
3049
- if (state.paths.length > 0 && config.renderer) {
3050
- const path = state.paths[0];
3051
- try {
3052
- revalidation = await config.renderer(path);
3053
- } catch (renderError) {
3054
- if (renderError instanceof RedirectSignal) {
3055
- redirectTo = renderError.location;
3056
- redirectStatus = renderError.status;
3057
- } else console.error("[timber] revalidatePath render failed:", renderError);
3058
- }
3059
- }
3060
- return {
3061
- actionResult,
3062
- revalidation,
3063
- ...redirectTo ? {
3064
- redirectTo,
3065
- redirectStatus
3066
- } : {}
3067
- };
3068
- }
3069
- /**
3070
- * Build an HTTP Response for a no-JS form submission.
3071
- * Standard POST → 302 redirect pattern.
3072
- *
3073
- * @param redirectPath - Where to redirect after the action executes.
3074
- */
3075
- function buildNoJsResponse(redirectPath, status = 302) {
3076
- return new Response(null, {
3077
- status,
3078
- headers: { Location: redirectPath }
3079
- });
3080
- }
3081
- /**
3082
- * Detect whether the incoming request is an RSC action request (with JS)
3083
- * or a plain HTML form POST (no JS).
3084
- *
3085
- * RSC action requests use Accept: text/x-component or Content-Type: text/x-component.
3086
- */
3087
- function isRscActionRequest(req) {
3088
- const accept = req.headers.get("Accept") ?? "";
3089
- const contentType = req.headers.get("Content-Type") ?? "";
3090
- return accept.includes("text/x-component") || contentType.includes("text/x-component");
3091
- }
3092
- //#endregion
3093
- //#region src/server/route-handler.ts
3094
- /** All recognized HTTP method export names. */
3095
- var HTTP_METHODS = [
3096
- "GET",
3097
- "POST",
3098
- "PUT",
3099
- "PATCH",
3100
- "DELETE",
3101
- "HEAD",
3102
- "OPTIONS"
3103
- ];
3104
- /**
3105
- * Resolve the full list of allowed methods for a route module.
3106
- *
3107
- * Includes:
3108
- * - All explicitly exported methods
3109
- * - HEAD (implicit when GET is exported)
3110
- * - OPTIONS (always implicit)
3111
- */
3112
- function resolveAllowedMethods(mod) {
3113
- const methods = [];
3114
- for (const method of HTTP_METHODS) {
3115
- if (method === "HEAD" || method === "OPTIONS") continue;
3116
- if (mod[method]) methods.push(method);
3117
- }
3118
- if (mod.GET && !mod.HEAD) methods.push("HEAD");
3119
- else if (mod.HEAD) methods.push("HEAD");
3120
- if (!mod.OPTIONS) methods.push("OPTIONS");
3121
- else methods.push("OPTIONS");
3122
- return methods;
3123
- }
3124
- /**
3125
- * Handle an incoming request against a route.ts module.
3126
- *
3127
- * Dispatches to the named method handler, auto-generates 405/OPTIONS,
3128
- * and merges response headers from ctx.headers.
3129
- */
3130
- async function handleRouteRequest(mod, ctx) {
3131
- const method = ctx.req.method.toUpperCase();
3132
- const allowHeader = resolveAllowedMethods(mod).join(", ");
3133
- if (method === "OPTIONS") {
3134
- if (mod.OPTIONS) return runHandler(mod.OPTIONS, ctx);
3135
- return new Response(null, {
3136
- status: 204,
3137
- headers: { Allow: allowHeader }
3138
- });
3139
- }
3140
- if (method === "HEAD") {
3141
- if (mod.HEAD) return runHandler(mod.HEAD, ctx);
3142
- if (mod.GET) {
3143
- const res = await runHandler(mod.GET, ctx);
3144
- return new Response(null, {
3145
- status: res.status,
3146
- headers: res.headers
3147
- });
3148
- }
3149
- }
3150
- const handler = mod[method];
3151
- if (!handler) return new Response(null, {
3152
- status: 405,
3153
- headers: { Allow: allowHeader }
3154
- });
3155
- return runHandler(handler, ctx);
3156
- }
3157
- /**
3158
- * Run a handler, merge ctx.headers into the response, and catch errors.
3159
- */
3160
- async function runHandler(handler, ctx) {
3161
- try {
3162
- return mergeResponseHeaders(await handler(ctx), ctx.headers);
3163
- } catch (error) {
3164
- console.error("[timber] Uncaught error in route.ts handler:", error);
3165
- return new Response(null, { status: 500 });
3166
- }
3167
- }
3168
- /**
3169
- * Merge response headers from ctx.headers into the handler's response.
3170
- * ctx.headers (set by middleware or the handler) are applied to the final response.
3171
- * Handler-set headers take precedence over ctx.headers.
3172
- */
3173
- function mergeResponseHeaders(res, ctxHeaders) {
3174
- let hasCtxHeaders = false;
3175
- ctxHeaders.forEach(() => {
3176
- hasCtxHeaders = true;
3177
- });
3178
- if (!hasCtxHeaders) return res;
3179
- const merged = new Headers();
3180
- ctxHeaders.forEach((value, key) => merged.set(key, value));
3181
- res.headers.forEach((value, key) => merged.set(key, value));
3182
- return new Response(res.body, {
3183
- status: res.status,
3184
- statusText: res.statusText,
3185
- headers: merged
3186
- });
3187
- }
3188
- //#endregion
3189
- export { AccessGate, ActionError, DEFAULT_LIMITS, DenySignal, METADATA_ROUTE_CONVENTIONS, RedirectSignal, RedirectType, RenderError, SlotAccessGate, WarningId, addSpanEvent, buildElementTree, buildNoJsResponse, callOnRequestError, canonicalize, classifyMetadataRoute, coerce, collectEarlyHintHeaders, cookies, createActionClient, createPipeline, deny, enforceBodyLimits, executeAction, flushResponse, formatLinkHeader, generateTraceId, getFormFlash, getLogger, getMetadataRouteAutoLink, getMetadataRouteServePath, getSetCookieHeaders, handleRouteRequest, hasOnRequestError, headers, isRscActionRequest, loadInstrumentation, logCacheMiss, logMiddlewareError, logMiddlewareShortCircuit, logProxyError, logRenderError, logRequestCompleted, logRequestReceived, logSlowRequest, logSwrRefetchFailed, logWaitUntilRejected, logWaitUntilUnsupported, markResponseFlushed, notFound, parseBodySize, parseFormData, permanentRedirect, redirect, redirectExternal, renderMetadataToElements, replaceTraceId, resolveAllowedMethods, resolveMetadata, resolveMetadataUrls, resolveSlotDenied, resolveStatusFile, resolveTitle, revalidatePath, revalidateTag, runMiddleware, runProxy, runWithEarlyHintsSender, runWithRequestContext, runWithTraceId, searchParams, sendEarlyHints103, setCookieSecrets, setLogger, setMutableCookieContext, setParsedSearchParams, setViteServer, spanId, traceId, validateCsrf, validated, waitUntil, warnCacheRequestProps, warnDenyAfterFlush, warnDenyInSuspense, warnDynamicApiInStaticBuild, warnRedirectInAccess, warnRedirectInSlotAccess, warnRedirectInSuspense, warnSlowSlotWithoutSuspense, warnStaticRequestApi, warnSuspenseWrappingChildren, withSpan };
471
+ export { ActionError, RedirectType, addSpanEvent, coerce, createActionClient, deny, getCookieJar, getFormFlash, getHeaders, getSegmentParams, getSpanId, getTraceId, parseFormData, redirect, redirectExternal, revalidatePath, revalidateTag, validated, waitUntil, withSpan };
3190
472
 
3191
473
  //# sourceMappingURL=index.js.map