@timber-js/app 0.2.0-alpha.191 → 0.2.0-alpha.194

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 (672) hide show
  1. package/agent-skill.md +2 -0
  2. package/dist/_chunks/{actions-BjbbNRFN.js → actions-CWYtq6ii.js} +3 -3
  3. package/dist/_chunks/actions-CWYtq6ii.js.map +1 -0
  4. package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -1
  5. package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -1
  6. package/dist/_chunks/{build-output-helper-C3DrfzZR.js → build-output-helper-9dqCv1pZ.js} +3 -2
  7. package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +1 -0
  8. package/dist/_chunks/{cache-api-DllJ-Lyw.js → cache-api-CQeYzA5g.js} +6 -8
  9. package/dist/_chunks/cache-api-CQeYzA5g.js.map +1 -0
  10. package/dist/_chunks/chains-h7EO-u3n.js +412 -0
  11. package/dist/_chunks/chains-h7EO-u3n.js.map +1 -0
  12. package/dist/_chunks/{cli-check-DJZDc22E.js → cli-check-BVthpfLS.js} +43 -6
  13. package/dist/_chunks/cli-check-BVthpfLS.js.map +1 -0
  14. package/dist/_chunks/{cli-schema-sync-D4_AZVUb.js → cli-schema-sync-ZwM9u_ob.js} +6 -5
  15. package/dist/_chunks/{cli-schema-sync-D4_AZVUb.js.map → cli-schema-sync-ZwM9u_ob.js.map} +1 -1
  16. package/dist/_chunks/{cloudflare-CGP6BZKO.js → cloudflare-BKJC3SC_.js} +28 -22
  17. package/dist/_chunks/{cloudflare-CGP6BZKO.js.map → cloudflare-BKJC3SC_.js.map} +1 -1
  18. package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -1
  19. package/dist/_chunks/{convention-lint-CpteIpTm.js → convention-lint-DO10_pVl.js} +93 -7
  20. package/dist/_chunks/convention-lint-DO10_pVl.js.map +1 -0
  21. package/dist/_chunks/dist-DtrJyBbw.js +386 -0
  22. package/dist/_chunks/dist-DtrJyBbw.js.map +1 -0
  23. package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -1
  24. package/dist/_chunks/{file-cache-DmX7OqZP.js → file-cache-Dw6BJPG7.js} +5 -1
  25. package/dist/_chunks/{file-cache-DmX7OqZP.js.map → file-cache-Dw6BJPG7.js.map} +1 -1
  26. package/dist/_chunks/{format-CfwjgPz9.js → format-BKclgVbk.js} +3 -3
  27. package/dist/_chunks/{format-CfwjgPz9.js.map → format-BKclgVbk.js.map} +1 -1
  28. package/dist/_chunks/graph-cache-CP4GEmf9.js +304 -0
  29. package/dist/_chunks/graph-cache-CP4GEmf9.js.map +1 -0
  30. package/dist/_chunks/href-validation-CMc5JRls.js.map +1 -1
  31. package/dist/_chunks/live-graph-Bx4HodF1.js +150 -0
  32. package/dist/_chunks/live-graph-Bx4HodF1.js.map +1 -0
  33. package/dist/_chunks/{logger-CH7IcMmg.js → logger-pumCm3Il.js} +25 -7
  34. package/dist/_chunks/{logger-CH7IcMmg.js.map → logger-pumCm3Il.js.map} +1 -1
  35. package/dist/_chunks/{mdx-file-C005ay-P.js → mdx-file-CXyHGUpS.js} +3 -3
  36. package/dist/_chunks/mdx-file-CXyHGUpS.js.map +1 -0
  37. package/dist/_chunks/{plugin-context-rCinWLiE.js → plugin-context-8idfR3UZ.js} +2 -2
  38. package/dist/_chunks/plugin-context-8idfR3UZ.js.map +1 -0
  39. package/dist/_chunks/poison-rules-DoEhbqaY.js +110 -0
  40. package/dist/_chunks/poison-rules-DoEhbqaY.js.map +1 -0
  41. package/dist/_chunks/poison-scan-BAxfTT5L.js +101 -0
  42. package/dist/_chunks/poison-scan-BAxfTT5L.js.map +1 -0
  43. package/dist/_chunks/resolve-schema-CBR6Lm4i.js.map +1 -1
  44. package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  45. package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -1
  46. package/dist/_chunks/{rsc-media-type-DRqE_lD_.js → rsc-media-type-DDc7duTD.js} +17 -2
  47. package/dist/_chunks/{rsc-media-type-DRqE_lD_.js.map → rsc-media-type-DDc7duTD.js.map} +1 -1
  48. package/dist/_chunks/scan-BoP17W3w.js +140 -0
  49. package/dist/_chunks/scan-BoP17W3w.js.map +1 -0
  50. package/dist/_chunks/{scanner-CAietmj4.js → scanner-BRIOmHE2.js} +43 -4
  51. package/dist/_chunks/scanner-BRIOmHE2.js.map +1 -0
  52. package/dist/_chunks/schema-bridge-C83xa9lT.js.map +1 -1
  53. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -1
  54. package/dist/_chunks/{segment-keys-BawYuNFO.js → segment-keys-BhqoHiLc.js} +14 -2
  55. package/dist/_chunks/{segment-keys-BawYuNFO.js.map → segment-keys-BhqoHiLc.js.map} +1 -1
  56. package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -1
  57. package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -1
  58. package/dist/_chunks/use-query-states-I3JMng6J.js.map +1 -1
  59. package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -1
  60. package/dist/_chunks/{walkers-BsVLmD1S.js → walkers-uCu3WW6_.js} +9 -6
  61. package/dist/_chunks/{walkers-BsVLmD1S.js.map → walkers-uCu3WW6_.js.map} +1 -1
  62. package/dist/adapters/build-output-helper.d.ts +1 -1
  63. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  64. package/dist/adapters/cloudflare-dev.d.ts.map +1 -1
  65. package/dist/adapters/cloudflare-dev.js +2 -1
  66. package/dist/adapters/cloudflare-dev.js.map +1 -1
  67. package/dist/adapters/cloudflare-kv-cache.d.ts +1 -1
  68. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -1
  69. package/dist/adapters/cloudflare-kv-cache.js +7 -8
  70. package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
  71. package/dist/adapters/cloudflare.d.ts +1 -1
  72. package/dist/adapters/cloudflare.d.ts.map +1 -1
  73. package/dist/adapters/cloudflare.js +1 -1
  74. package/dist/adapters/nitro-presets.d.ts +37 -0
  75. package/dist/adapters/nitro-presets.d.ts.map +1 -0
  76. package/dist/adapters/nitro-preview.d.ts +32 -0
  77. package/dist/adapters/nitro-preview.d.ts.map +1 -0
  78. package/dist/adapters/nitro.d.ts +28 -51
  79. package/dist/adapters/nitro.d.ts.map +1 -1
  80. package/dist/adapters/nitro.js +224 -171
  81. package/dist/adapters/nitro.js.map +1 -1
  82. package/dist/analyze/chains.d.ts +124 -0
  83. package/dist/analyze/chains.d.ts.map +1 -0
  84. package/dist/analyze/classify.d.ts +150 -0
  85. package/dist/analyze/classify.d.ts.map +1 -0
  86. package/dist/analyze/crawl-entry.d.ts +17 -0
  87. package/dist/analyze/crawl-entry.d.ts.map +1 -0
  88. package/dist/analyze/crawl-entry.js +313 -0
  89. package/dist/analyze/crawl-entry.js.map +1 -0
  90. package/dist/analyze/crawl.d.ts +134 -0
  91. package/dist/analyze/crawl.d.ts.map +1 -0
  92. package/dist/analyze/graph-cache.d.ts +104 -0
  93. package/dist/analyze/graph-cache.d.ts.map +1 -0
  94. package/dist/analyze/graph-command.d.ts +43 -0
  95. package/dist/analyze/graph-command.d.ts.map +1 -0
  96. package/dist/analyze/graph-command.js +472 -0
  97. package/dist/analyze/graph-command.js.map +1 -0
  98. package/dist/analyze/live-graph.d.ts +81 -0
  99. package/dist/analyze/live-graph.d.ts.map +1 -0
  100. package/dist/analyze/poison-rules.d.ts +72 -0
  101. package/dist/analyze/poison-rules.d.ts.map +1 -0
  102. package/dist/analyze/poison-scan.d.ts +48 -0
  103. package/dist/analyze/poison-scan.d.ts.map +1 -0
  104. package/dist/analyze/scan.d.ts +73 -0
  105. package/dist/analyze/scan.d.ts.map +1 -0
  106. package/dist/cache/cache-api.d.ts +2 -2
  107. package/dist/cache/cache-api.d.ts.map +1 -1
  108. package/dist/cache/index.d.ts +8 -8
  109. package/dist/cache/index.d.ts.map +1 -1
  110. package/dist/cache/index.js +1 -1
  111. package/dist/cache/redis-handler.d.ts +1 -1
  112. package/dist/cache/redis-handler.d.ts.map +1 -1
  113. package/dist/cache/stores/cloudflare-kv.d.ts +1 -1
  114. package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -1
  115. package/dist/cache/stores/cloudflare-kv.js.map +1 -1
  116. package/dist/cache/stores/memory.d.ts +1 -1
  117. package/dist/cache/stores/memory.d.ts.map +1 -1
  118. package/dist/cache/stores/memory.js.map +1 -1
  119. package/dist/cache/stores/redis.d.ts +1 -1
  120. package/dist/cache/stores/redis.d.ts.map +1 -1
  121. package/dist/cache/stores/redis.js.map +1 -1
  122. package/dist/cache/stores/vercel.d.ts +1 -1
  123. package/dist/cache/stores/vercel.d.ts.map +1 -1
  124. package/dist/cache/stores/vercel.js.map +1 -1
  125. package/dist/cache/tag-aware-handler.d.ts +2 -2
  126. package/dist/cache/tag-aware-handler.d.ts.map +1 -1
  127. package/dist/cache/timber-cache.d.ts +1 -1
  128. package/dist/cache/timber-cache.d.ts.map +1 -1
  129. package/dist/cdn/cloudflare-purge.d.ts +1 -1
  130. package/dist/cdn/cloudflare-purge.d.ts.map +1 -1
  131. package/dist/cdn/cloudflare-purge.js.map +1 -1
  132. package/dist/cdn/fastly-purge.d.ts +1 -1
  133. package/dist/cdn/fastly-purge.d.ts.map +1 -1
  134. package/dist/cdn/fastly-purge.js.map +1 -1
  135. package/dist/cdn/index.d.ts +4 -4
  136. package/dist/cdn/index.d.ts.map +1 -1
  137. package/dist/cdn/workers-cache-purge.d.ts +5 -1
  138. package/dist/cdn/workers-cache-purge.d.ts.map +1 -1
  139. package/dist/cdn/workers-cache-purge.js.map +1 -1
  140. package/dist/cli-check.d.ts +10 -0
  141. package/dist/cli-check.d.ts.map +1 -1
  142. package/dist/cli.d.ts +12 -4
  143. package/dist/cli.d.ts.map +1 -1
  144. package/dist/cli.js +30 -6
  145. package/dist/cli.js.map +1 -1
  146. package/dist/client/browser-entry/hydrate.d.ts +2 -2
  147. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  148. package/dist/client/browser-entry/post-hydration.d.ts +2 -2
  149. package/dist/client/browser-entry/router-init.d.ts +2 -2
  150. package/dist/client/browser-entry/rsc-stream.d.ts +1 -1
  151. package/dist/client/form.d.ts +2 -2
  152. package/dist/client/form.d.ts.map +1 -1
  153. package/dist/client/history.d.ts +2 -2
  154. package/dist/client/index.d.ts +18 -18
  155. package/dist/client/index.d.ts.map +1 -1
  156. package/dist/client/index.js.map +1 -1
  157. package/dist/client/internal.d.ts +19 -19
  158. package/dist/client/internal.d.ts.map +1 -1
  159. package/dist/client/internal.js +11 -15
  160. package/dist/client/internal.js.map +1 -1
  161. package/dist/client/link.d.ts +3 -3
  162. package/dist/client/navigation-commit.d.ts +5 -5
  163. package/dist/client/navigation-root.d.ts +1 -1
  164. package/dist/client/navigation-root.d.ts.map +1 -1
  165. package/dist/client/params-context.d.ts +3 -3
  166. package/dist/client/router-pipeline.d.ts +7 -7
  167. package/dist/client/router-ref.d.ts +1 -1
  168. package/dist/client/router-types.d.ts +6 -6
  169. package/dist/client/router-types.d.ts.map +1 -1
  170. package/dist/client/router.d.ts +1 -1
  171. package/dist/client/rsc-fetch.d.ts +4 -4
  172. package/dist/client/rsc-fetch.d.ts.map +1 -1
  173. package/dist/client/segment-cache.d.ts +2 -2
  174. package/dist/client/slot-provider.d.ts +1 -1
  175. package/dist/client/ssr-data.d.ts +2 -2
  176. package/dist/client/state.d.ts +4 -4
  177. package/dist/client/use-query-states.d.ts +1 -1
  178. package/dist/client/use-segment-params.d.ts +3 -3
  179. package/dist/codec.d.ts +2 -2
  180. package/dist/codec.js.map +1 -1
  181. package/dist/config-types.d.ts +24 -6
  182. package/dist/config-types.d.ts.map +1 -1
  183. package/dist/config-validation.d.ts +1 -1
  184. package/dist/cookies/define-cookie.d.ts +3 -3
  185. package/dist/cookies/index.d.ts +3 -3
  186. package/dist/cookies/index.js +3 -4
  187. package/dist/cookies/index.js.map +1 -1
  188. package/dist/cookies/json-cookie.d.ts +1 -1
  189. package/dist/dev-tools/404-page.d.ts +2 -2
  190. package/dist/dev-tools/error-page.d.ts +2 -2
  191. package/dist/dev-tools/index.d.ts +12 -12
  192. package/dist/dev-tools/instrumentation.d.ts +1 -1
  193. package/dist/dev-tools/logs.d.ts +1 -1
  194. package/dist/dev-tools/overlay.d.ts +2 -2
  195. package/dist/dev-tools/terminal.d.ts +1 -1
  196. package/dist/fonts/ast.d.ts +4 -4
  197. package/dist/fonts/bundle.d.ts +3 -3
  198. package/dist/fonts/css.d.ts +1 -1
  199. package/dist/fonts/dev-middleware.d.ts +1 -1
  200. package/dist/fonts/google.d.ts +1 -1
  201. package/dist/fonts/local.d.ts +1 -1
  202. package/dist/fonts/pipeline.d.ts +3 -3
  203. package/dist/fonts/transform.d.ts +2 -2
  204. package/dist/fonts/types.d.ts +1 -1
  205. package/dist/fonts/virtual-modules.d.ts +1 -1
  206. package/dist/index.d.ts +3 -3
  207. package/dist/index.d.ts.map +1 -1
  208. package/dist/index.js +816 -310
  209. package/dist/index.js.map +1 -1
  210. package/dist/params/codec-registry.d.ts +1 -1
  211. package/dist/params/define-schema.d.ts +2 -2
  212. package/dist/params/index.d.ts +4 -4
  213. package/dist/params/index.js.map +1 -1
  214. package/dist/params/resolve-schema.d.ts +1 -1
  215. package/dist/plugin-context.d.ts +9 -9
  216. package/dist/plugin-context.d.ts.map +1 -1
  217. package/dist/plugins/adapter-build.d.ts +2 -2
  218. package/dist/plugins/build-manifest.d.ts +2 -2
  219. package/dist/plugins/build-report.d.ts +5 -5
  220. package/dist/plugins/cache.d.ts +1 -1
  221. package/dist/plugins/callsite-jsx.d.ts +2 -2
  222. package/dist/plugins/chunks.d.ts +1 -1
  223. package/dist/plugins/chunks.d.ts.map +1 -1
  224. package/dist/plugins/cloudflare-wasm.d.ts +1 -1
  225. package/dist/plugins/content.d.ts +1 -1
  226. package/dist/plugins/content.d.ts.map +1 -1
  227. package/dist/plugins/dev-discovery.d.ts +123 -0
  228. package/dist/plugins/dev-discovery.d.ts.map +1 -0
  229. package/dist/plugins/dev-server.d.ts +1 -1
  230. package/dist/plugins/dev-server.d.ts.map +1 -1
  231. package/dist/plugins/entries.d.ts +1 -1
  232. package/dist/plugins/fonts.d.ts +3 -3
  233. package/dist/plugins/fonts.d.ts.map +1 -1
  234. package/dist/plugins/graph-endpoint.d.ts +112 -0
  235. package/dist/plugins/graph-endpoint.d.ts.map +1 -0
  236. package/dist/plugins/mdx.d.ts +18 -5
  237. package/dist/plugins/mdx.d.ts.map +1 -1
  238. package/dist/plugins/prebuilt-capture.d.ts +2 -2
  239. package/dist/plugins/prebuilt-options-analysis.d.ts +1 -1
  240. package/dist/plugins/prebuilt.d.ts +1 -1
  241. package/dist/plugins/prerender-sugar.d.ts +11 -14
  242. package/dist/plugins/prerender-sugar.d.ts.map +1 -1
  243. package/dist/plugins/request-dep/analysis.d.ts +1 -1
  244. package/dist/plugins/request-dep/index.d.ts +5 -5
  245. package/dist/plugins/request-dep/origin.d.ts +1 -1
  246. package/dist/plugins/routing.d.ts +1 -1
  247. package/dist/plugins/routing.d.ts.map +1 -1
  248. package/dist/plugins/server-bundle.d.ts.map +1 -1
  249. package/dist/plugins/shims.d.ts +1 -1
  250. package/dist/plugins/shims.d.ts.map +1 -1
  251. package/dist/plugins/static-build.d.ts +5 -5
  252. package/dist/routing/codegen-shared.d.ts +1 -1
  253. package/dist/routing/codegen-write.d.ts +1 -1
  254. package/dist/routing/codegen.d.ts +1 -1
  255. package/dist/routing/collision-probe.d.ts +1 -1
  256. package/dist/routing/collision-spaces.d.ts +1 -1
  257. package/dist/routing/convention-lint.d.ts +1 -1
  258. package/dist/routing/convention-lint.d.ts.map +1 -1
  259. package/dist/routing/index.d.ts +13 -13
  260. package/dist/routing/index.js +3 -3
  261. package/dist/routing/interception.d.ts +1 -1
  262. package/dist/routing/interception.d.ts.map +1 -1
  263. package/dist/routing/link-codegen.d.ts +1 -1
  264. package/dist/routing/manifest-codegen.d.ts +1 -1
  265. package/dist/routing/scanner.d.ts +14 -1
  266. package/dist/routing/scanner.d.ts.map +1 -1
  267. package/dist/routing/schema-validation.d.ts +1 -1
  268. package/dist/routing/segment-classify.d.ts +1 -1
  269. package/dist/routing/segment-codegen.d.ts +1 -1
  270. package/dist/routing/segment-keys.d.ts +1 -1
  271. package/dist/routing/slot-placement.d.ts +1 -1
  272. package/dist/routing/walkers.d.ts +1 -1
  273. package/dist/rsc-runtime/transforms.d.ts +13 -0
  274. package/dist/rsc-runtime/transforms.d.ts.map +1 -0
  275. package/dist/schema-bridge.d.ts +1 -1
  276. package/dist/search-params/define.d.ts +3 -3
  277. package/dist/search-params/index.d.ts +3 -3
  278. package/dist/search-params/index.js.map +1 -1
  279. package/dist/search-params/wrappers.d.ts +1 -1
  280. package/dist/server/access-gate.d.ts +1 -1
  281. package/dist/server/action-client.d.ts +1 -1
  282. package/dist/server/action-handler.d.ts +5 -5
  283. package/dist/server/actions.d.ts +2 -2
  284. package/dist/server/als-registry.d.ts +8 -8
  285. package/dist/server/asset-headers.d.ts +1 -1
  286. package/dist/server/chain-url-parts.d.ts +3 -3
  287. package/dist/server/children-interception.d.ts +2 -2
  288. package/dist/server/cookie-context.d.ts +1 -1
  289. package/dist/server/cookie-parsing.d.ts +2 -2
  290. package/dist/server/default-logger.d.ts +1 -1
  291. package/dist/server/deny-boundary.d.ts +2 -2
  292. package/dist/server/deny-renderer.d.ts +5 -5
  293. package/dist/server/early-hints.d.ts +1 -1
  294. package/dist/server/error-boundary-wrapper.d.ts +2 -4
  295. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  296. package/dist/server/fallback-error.d.ts +5 -5
  297. package/dist/server/flight-injection-state.d.ts +1 -1
  298. package/dist/server/form-flash.d.ts +1 -1
  299. package/dist/server/html-injector-core.d.ts +2 -2
  300. package/dist/server/html-injectors.d.ts +1 -1
  301. package/dist/server/index.d.ts +18 -18
  302. package/dist/server/index.d.ts.map +1 -1
  303. package/dist/server/index.js +33 -32
  304. package/dist/server/index.js.map +1 -1
  305. package/dist/server/instrumentation.d.ts +1 -1
  306. package/dist/server/internal.d.ts +50 -50
  307. package/dist/server/internal.d.ts.map +1 -1
  308. package/dist/server/internal.js +1023 -1025
  309. package/dist/server/internal.js.map +1 -1
  310. package/dist/server/metadata-collector.d.ts +2 -2
  311. package/dist/server/metadata-platform.d.ts +2 -2
  312. package/dist/server/metadata-render.d.ts +2 -2
  313. package/dist/server/metadata-routes.d.ts +3 -3
  314. package/dist/server/metadata-social.d.ts +2 -2
  315. package/dist/server/metadata.d.ts +2 -2
  316. package/dist/server/middleware-runner.d.ts +1 -1
  317. package/dist/server/node-stream-transforms.d.ts +1 -1
  318. package/dist/server/param-coercion.d.ts +4 -4
  319. package/dist/server/pipeline-helpers.d.ts +3 -3
  320. package/dist/server/pipeline-interception.d.ts +1 -1
  321. package/dist/server/pipeline-metadata.d.ts +1 -1
  322. package/dist/server/pipeline-outcome.d.ts +2 -2
  323. package/dist/server/pipeline-phases.d.ts +3 -3
  324. package/dist/server/pipeline-phases.d.ts.map +1 -1
  325. package/dist/server/pipeline.d.ts +9 -9
  326. package/dist/server/prebuilt/cache-key.d.ts +1 -1
  327. package/dist/server/prebuilt/capture-state.d.ts +1 -1
  328. package/dist/server/prebuilt/key-discipline.d.ts +1 -1
  329. package/dist/server/prebuilt/manifest-tag-index.d.ts +1 -1
  330. package/dist/server/prebuilt/overlay.d.ts +2 -2
  331. package/dist/server/prebuilt/payload-source.d.ts +1 -1
  332. package/dist/server/prebuilt/slots.d.ts +1 -1
  333. package/dist/server/prebuilt/synthetic-store.d.ts +2 -2
  334. package/dist/server/prebuilt-builder.d.ts +2 -2
  335. package/dist/server/primitives.d.ts +2 -2
  336. package/dist/server/publish-params.d.ts +1 -1
  337. package/dist/server/request-context.d.ts +3 -3
  338. package/dist/server/route-element-builder.d.ts +16 -6
  339. package/dist/server/route-element-builder.d.ts.map +1 -1
  340. package/dist/server/route-handler.d.ts +1 -1
  341. package/dist/server/route-matcher.d.ts +4 -4
  342. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -1
  343. package/dist/server/rsc-entry/action-middleware-runner.d.ts +2 -2
  344. package/dist/server/rsc-entry/api-handler.d.ts +1 -1
  345. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  346. package/dist/server/rsc-entry/deny-fallback.d.ts +3 -3
  347. package/dist/server/rsc-entry/error-renderer.d.ts +4 -4
  348. package/dist/server/rsc-entry/helpers.d.ts +6 -6
  349. package/dist/server/rsc-entry/index.d.ts +7 -6
  350. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  351. package/dist/server/rsc-entry/render-route.d.ts +4 -4
  352. package/dist/server/rsc-entry/revalidate-renderer.d.ts +4 -4
  353. package/dist/server/rsc-entry/rsc-payload.d.ts +4 -4
  354. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  355. package/dist/server/rsc-entry/rsc-stream.d.ts +3 -3
  356. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  357. package/dist/server/rsc-entry/ssr-renderer.d.ts +7 -7
  358. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +5 -5
  359. package/dist/server/sitemap-generator.d.ts +2 -2
  360. package/dist/server/sitemap-handler.d.ts +1 -1
  361. package/dist/server/skippable-prefix.d.ts +3 -3
  362. package/dist/server/slot-interception.d.ts +2 -2
  363. package/dist/server/slot-resolver.d.ts +3 -7
  364. package/dist/server/slot-resolver.d.ts.map +1 -1
  365. package/dist/server/ssr-bridge-types.d.ts +2 -2
  366. package/dist/server/ssr-entry.d.ts +1 -1
  367. package/dist/server/static-generator.d.ts +1 -1
  368. package/dist/server/static-not-found.d.ts +1 -1
  369. package/dist/server/status-code-resolver.d.ts +1 -1
  370. package/dist/server/tracing.d.ts +3 -3
  371. package/dist/server/tree-builder.d.ts +3 -3
  372. package/dist/server/tree-match.d.ts +1 -1
  373. package/dist/server/types.d.ts +2 -2
  374. package/dist/server/utils/mdx-file.d.ts +2 -0
  375. package/dist/server/utils/mdx-file.d.ts.map +1 -1
  376. package/dist/server/workers-cache-bridge.d.ts +1 -1
  377. package/dist/shared/als-slots.d.ts +1 -1
  378. package/dist/shared/payload-root.d.ts +2 -2
  379. package/dist/shared/rsc-media-type.d.ts +12 -0
  380. package/dist/shared/rsc-media-type.d.ts.map +1 -1
  381. package/dist/shared/slot-params.d.ts +1 -1
  382. package/dist/shims/font-google.d.ts +1 -1
  383. package/dist/shims/font-google.js.map +1 -1
  384. package/dist/shims/font-local.d.ts +1 -1
  385. package/dist/shims/font-local.js.map +1 -1
  386. package/dist/shims/navigation-client.d.ts +4 -4
  387. package/dist/shims/navigation.d.ts +2 -2
  388. package/docs/api/34-api-config.mdx +9 -8
  389. package/docs/api/36-cli.mdx +23 -3
  390. package/docs/learn/11-error-handling.mdx +11 -0
  391. package/docs/more/01-advanced-routing.mdx +1 -0
  392. package/docs/more/04b-mdx.mdx +38 -18
  393. package/package.json +23 -18
  394. package/src/adapters/build-output-helper.ts +4 -4
  395. package/src/adapters/cloudflare-dev.ts +7 -1
  396. package/src/adapters/cloudflare-kv-cache.ts +11 -8
  397. package/src/adapters/cloudflare.ts +21 -15
  398. package/src/adapters/compress-module.ts +2 -2
  399. package/src/adapters/nitro-presets.ts +139 -0
  400. package/src/adapters/nitro-preview.ts +340 -0
  401. package/src/adapters/nitro.ts +100 -465
  402. package/src/adapters/shared.ts +1 -1
  403. package/src/analyze/chains.ts +411 -0
  404. package/src/analyze/classify.ts +258 -0
  405. package/src/analyze/crawl-entry.ts +68 -0
  406. package/src/analyze/crawl.ts +500 -0
  407. package/src/analyze/graph-cache.ts +332 -0
  408. package/src/analyze/graph-command.ts +762 -0
  409. package/src/analyze/live-graph.ts +232 -0
  410. package/src/analyze/poison-rules.ts +165 -0
  411. package/src/analyze/poison-scan.ts +162 -0
  412. package/src/analyze/scan.ts +149 -0
  413. package/src/cache/cache-api.ts +7 -7
  414. package/src/cache/index.ts +9 -9
  415. package/src/cache/redis-handler.ts +2 -2
  416. package/src/cache/stores/cloudflare-kv.ts +1 -1
  417. package/src/cache/stores/memory.ts +2 -2
  418. package/src/cache/stores/redis.ts +1 -1
  419. package/src/cache/stores/vercel.ts +1 -1
  420. package/src/cache/tag-aware-handler.ts +2 -2
  421. package/src/cache/timber-cache.ts +8 -8
  422. package/src/cdn/cloudflare-purge.ts +1 -1
  423. package/src/cdn/fastly-purge.ts +1 -1
  424. package/src/cdn/index.ts +10 -4
  425. package/src/cdn/workers-cache-purge.ts +6 -2
  426. package/src/cli-check.ts +53 -4
  427. package/src/cli-schema-sync.ts +3 -3
  428. package/src/cli.ts +50 -11
  429. package/src/client/browser-dev.ts +1 -1
  430. package/src/client/browser-entry/action-dispatch.ts +5 -5
  431. package/src/client/browser-entry/hmr.ts +1 -1
  432. package/src/client/browser-entry/hydrate.ts +9 -9
  433. package/src/client/browser-entry/index.ts +10 -10
  434. package/src/client/browser-entry/post-hydration.ts +5 -5
  435. package/src/client/browser-entry/router-init.ts +9 -9
  436. package/src/client/browser-entry/rsc-stream.ts +3 -3
  437. package/src/client/error-boundary.tsx +4 -4
  438. package/src/client/form.tsx +7 -2
  439. package/src/client/history.ts +2 -2
  440. package/src/client/index.ts +21 -18
  441. package/src/client/internal.ts +19 -19
  442. package/src/client/link.tsx +9 -9
  443. package/src/client/navigation-api.ts +1 -1
  444. package/src/client/navigation-commit.ts +5 -5
  445. package/src/client/navigation-context.ts +1 -1
  446. package/src/client/navigation-root.tsx +1 -1
  447. package/src/client/nuqs-adapter.tsx +2 -2
  448. package/src/client/params-context.ts +4 -4
  449. package/src/client/router-effects.ts +3 -3
  450. package/src/client/router-lifecycle.ts +2 -2
  451. package/src/client/router-pipeline.ts +10 -10
  452. package/src/client/router-ref.ts +2 -2
  453. package/src/client/router-skew.ts +2 -2
  454. package/src/client/router-types.ts +6 -6
  455. package/src/client/router.ts +13 -13
  456. package/src/client/rsc-fetch.ts +11 -16
  457. package/src/client/segment-cache.ts +2 -2
  458. package/src/client/segment-outlet.tsx +1 -1
  459. package/src/client/shallow-url.ts +1 -1
  460. package/src/client/slot-outlet.tsx +1 -1
  461. package/src/client/slot-provider.tsx +1 -1
  462. package/src/client/ssr-data.ts +3 -3
  463. package/src/client/stale-client.ts +1 -1
  464. package/src/client/state.ts +4 -4
  465. package/src/client/top-loader.tsx +1 -1
  466. package/src/client/unload-guard.ts +1 -1
  467. package/src/client/use-cookie.ts +2 -2
  468. package/src/client/use-pathname.ts +2 -2
  469. package/src/client/use-pending-navigation.ts +1 -1
  470. package/src/client/use-query-states.ts +3 -3
  471. package/src/client/use-router.ts +2 -2
  472. package/src/client/use-search-params.ts +3 -3
  473. package/src/client/use-segment-params.ts +6 -6
  474. package/src/client/use-selected-layout-segment.ts +2 -2
  475. package/src/codec.ts +2 -2
  476. package/src/config-types.ts +27 -7
  477. package/src/config-validation.ts +1 -1
  478. package/src/cookies/define-cookie.ts +6 -6
  479. package/src/cookies/index.ts +3 -3
  480. package/src/cookies/json-cookie.ts +1 -1
  481. package/src/dev-tools/404-page.ts +4 -4
  482. package/src/dev-tools/dev-page-shell.ts +1 -1
  483. package/src/dev-tools/error-page.ts +4 -4
  484. package/src/dev-tools/index.ts +12 -12
  485. package/src/dev-tools/instrumentation.ts +1 -1
  486. package/src/dev-tools/logs.ts +1 -1
  487. package/src/dev-tools/overlay.ts +3 -3
  488. package/src/dev-tools/terminal.ts +2 -2
  489. package/src/fonts/ast.ts +5 -5
  490. package/src/fonts/bundle.ts +5 -5
  491. package/src/fonts/css.ts +1 -1
  492. package/src/fonts/dev-middleware.ts +2 -2
  493. package/src/fonts/google.ts +2 -2
  494. package/src/fonts/local.ts +4 -4
  495. package/src/fonts/pipeline.ts +8 -8
  496. package/src/fonts/transform.ts +5 -5
  497. package/src/fonts/types.ts +1 -1
  498. package/src/fonts/virtual-modules.ts +1 -1
  499. package/src/index.ts +46 -37
  500. package/src/params/codec-registry.ts +1 -1
  501. package/src/params/define-schema.ts +2 -2
  502. package/src/params/index.ts +4 -4
  503. package/src/params/resolve-schema.ts +2 -2
  504. package/src/plugin-context.ts +10 -10
  505. package/src/plugins/adapter-build.ts +5 -5
  506. package/src/plugins/build-manifest.ts +4 -4
  507. package/src/plugins/build-report.ts +6 -6
  508. package/src/plugins/cache.ts +3 -3
  509. package/src/plugins/callsite-ast.ts +1 -1
  510. package/src/plugins/callsite-jsx.ts +2 -2
  511. package/src/plugins/chunks.ts +1 -1
  512. package/src/plugins/cloudflare-wasm.ts +1 -1
  513. package/src/plugins/content.ts +5 -1
  514. package/src/plugins/dev-discovery.ts +218 -0
  515. package/src/plugins/dev-server.ts +97 -12
  516. package/src/plugins/entries.ts +1 -1
  517. package/src/plugins/fonts.ts +17 -10
  518. package/src/plugins/graph-endpoint.ts +532 -0
  519. package/src/plugins/mdx.ts +73 -38
  520. package/src/plugins/prebuilt-capture.ts +3 -3
  521. package/src/plugins/prebuilt-options-analysis.ts +1 -1
  522. package/src/plugins/prebuilt.ts +7 -7
  523. package/src/plugins/prerender-sugar.ts +11 -19
  524. package/src/plugins/request-dep/analysis.ts +1 -1
  525. package/src/plugins/request-dep/index.ts +8 -8
  526. package/src/plugins/request-dep/origin.ts +1 -1
  527. package/src/plugins/routing.ts +12 -7
  528. package/src/plugins/server-bundle.ts +11 -3
  529. package/src/plugins/shims.ts +16 -31
  530. package/src/plugins/static-build.ts +10 -10
  531. package/src/routing/codegen-shared.ts +1 -1
  532. package/src/routing/codegen-write.ts +3 -3
  533. package/src/routing/codegen.ts +14 -5
  534. package/src/routing/collision-probe.ts +3 -3
  535. package/src/routing/collision-spaces.ts +3 -3
  536. package/src/routing/convention-lint.ts +136 -6
  537. package/src/routing/export-detect.ts +1 -1
  538. package/src/routing/index.ts +13 -13
  539. package/src/routing/interception.ts +41 -4
  540. package/src/routing/link-codegen.ts +3 -3
  541. package/src/routing/manifest-codegen.ts +2 -2
  542. package/src/routing/scanner.ts +33 -9
  543. package/src/routing/schema-validation.ts +4 -4
  544. package/src/routing/segment-classify.ts +2 -2
  545. package/src/routing/segment-codegen.ts +1 -1
  546. package/src/routing/segment-keys.ts +1 -1
  547. package/src/routing/slot-placement.ts +1 -1
  548. package/src/routing/walkers.ts +1 -1
  549. package/src/rsc-runtime/transforms.ts +13 -0
  550. package/src/rsc-runtime/vendor-types.d.ts +12 -0
  551. package/src/schema-bridge.ts +1 -1
  552. package/src/search-params/define.ts +8 -8
  553. package/src/search-params/index.ts +3 -3
  554. package/src/search-params/wrappers.ts +3 -3
  555. package/src/server/access-gate.tsx +6 -6
  556. package/src/server/action-client.ts +5 -5
  557. package/src/server/action-handler.ts +16 -16
  558. package/src/server/actions.ts +5 -5
  559. package/src/server/als-registry.ts +8 -8
  560. package/src/server/asset-headers.ts +2 -2
  561. package/src/server/chain-url-parts.ts +5 -5
  562. package/src/server/children-interception.ts +4 -4
  563. package/src/server/compress.ts +1 -1
  564. package/src/server/cookie-context.ts +4 -4
  565. package/src/server/cookie-parsing.ts +2 -2
  566. package/src/server/default-logger.ts +3 -3
  567. package/src/server/deny-boundary.ts +10 -10
  568. package/src/server/deny-renderer.ts +38 -25
  569. package/src/server/early-hints-sender.ts +2 -2
  570. package/src/server/early-hints.ts +2 -2
  571. package/src/server/error-boundary-wrapper.ts +4 -12
  572. package/src/server/fallback-error.ts +13 -13
  573. package/src/server/flight-injection-state.ts +1 -1
  574. package/src/server/form-flash.ts +2 -2
  575. package/src/server/html-injector-core.ts +4 -4
  576. package/src/server/html-injectors.ts +5 -5
  577. package/src/server/index.ts +18 -18
  578. package/src/server/instrumentation.ts +1 -1
  579. package/src/server/internal.ts +50 -50
  580. package/src/server/logger.ts +4 -4
  581. package/src/server/metadata-collector.ts +7 -7
  582. package/src/server/metadata-platform.ts +2 -2
  583. package/src/server/metadata-render.ts +4 -4
  584. package/src/server/metadata-routes.ts +3 -3
  585. package/src/server/metadata-social.ts +2 -2
  586. package/src/server/metadata.ts +2 -2
  587. package/src/server/middleware-runner.ts +1 -1
  588. package/src/server/node-stream-transforms.ts +4 -4
  589. package/src/server/param-coercion.ts +8 -8
  590. package/src/server/pipeline-helpers.ts +7 -7
  591. package/src/server/pipeline-interception.ts +2 -2
  592. package/src/server/pipeline-metadata.ts +1 -1
  593. package/src/server/pipeline-outcome.ts +8 -8
  594. package/src/server/pipeline-phases.ts +24 -28
  595. package/src/server/pipeline.ts +22 -22
  596. package/src/server/prebuilt/cache-key.ts +1 -1
  597. package/src/server/prebuilt/capture-state.ts +1 -1
  598. package/src/server/prebuilt/key-discipline.ts +1 -1
  599. package/src/server/prebuilt/manifest-tag-index.ts +1 -1
  600. package/src/server/prebuilt/overlay.ts +6 -6
  601. package/src/server/prebuilt/payload-source.ts +2 -2
  602. package/src/server/prebuilt/slots.ts +5 -5
  603. package/src/server/prebuilt/synthetic-store.ts +2 -2
  604. package/src/server/prebuilt-builder.ts +16 -16
  605. package/src/server/prebuilt-runtime.ts +12 -12
  606. package/src/server/primitives.ts +7 -7
  607. package/src/server/publish-params.ts +3 -3
  608. package/src/server/request-context.ts +7 -7
  609. package/src/server/route-element-builder.ts +108 -50
  610. package/src/server/route-handler.ts +4 -4
  611. package/src/server/route-matcher.ts +5 -5
  612. package/src/server/rsc-cache-key-guard.ts +3 -5
  613. package/src/server/rsc-entry/action-middleware-runner.ts +7 -7
  614. package/src/server/rsc-entry/api-handler.ts +18 -9
  615. package/src/server/rsc-entry/deny-fallback.ts +10 -10
  616. package/src/server/rsc-entry/error-renderer.ts +27 -27
  617. package/src/server/rsc-entry/helpers.ts +10 -10
  618. package/src/server/rsc-entry/index.ts +51 -47
  619. package/src/server/rsc-entry/render-route.ts +20 -20
  620. package/src/server/rsc-entry/revalidate-renderer.ts +12 -12
  621. package/src/server/rsc-entry/rsc-payload.ts +19 -15
  622. package/src/server/rsc-entry/rsc-stream.ts +8 -8
  623. package/src/server/rsc-entry/ssr-bridge.ts +3 -3
  624. package/src/server/rsc-entry/ssr-renderer.ts +23 -23
  625. package/src/server/rsc-entry/wrap-action-dispatch.ts +9 -9
  626. package/src/server/rsc-prop-warnings.ts +1 -1
  627. package/src/server/sensitive-fields.ts +1 -1
  628. package/src/server/server-timing.ts +1 -1
  629. package/src/server/sitemap-generator.ts +3 -3
  630. package/src/server/sitemap-handler.ts +3 -3
  631. package/src/server/skippable-prefix.ts +7 -7
  632. package/src/server/slot-interception.ts +5 -5
  633. package/src/server/slot-resolver.ts +20 -28
  634. package/src/server/ssr-bridge-types.ts +2 -2
  635. package/src/server/ssr-entry.ts +18 -18
  636. package/src/server/ssr-render.ts +4 -4
  637. package/src/server/ssr-wrappers.tsx +1 -1
  638. package/src/server/state-tree-diff.ts +1 -1
  639. package/src/server/static-generator.ts +6 -6
  640. package/src/server/static-not-found.ts +3 -3
  641. package/src/server/status-code-resolver.ts +1 -1
  642. package/src/server/tracing.ts +5 -5
  643. package/src/server/tree-builder.ts +4 -4
  644. package/src/server/tree-match.ts +1 -1
  645. package/src/server/types.ts +2 -2
  646. package/src/server/utils/mdx-file.ts +2 -2
  647. package/src/server/waituntil-bridge.ts +1 -1
  648. package/src/server/workers-cache-bridge.ts +2 -2
  649. package/src/shared/als-slots.ts +1 -1
  650. package/src/shared/payload-root.ts +2 -2
  651. package/src/shared/rsc-media-type.ts +16 -0
  652. package/src/shared/slot-params.ts +1 -1
  653. package/src/shims/font-google.ts +1 -1
  654. package/src/shims/font-local.ts +1 -1
  655. package/src/shims/navigation-client.ts +5 -5
  656. package/src/shims/navigation.ts +2 -2
  657. package/LICENSE +0 -8
  658. package/dist/_chunks/actions-BjbbNRFN.js.map +0 -1
  659. package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +0 -1
  660. package/dist/_chunks/cache-api-DllJ-Lyw.js.map +0 -1
  661. package/dist/_chunks/cli-check-DJZDc22E.js.map +0 -1
  662. package/dist/_chunks/convention-lint-CpteIpTm.js.map +0 -1
  663. package/dist/_chunks/dist-BA3u1z3W.js +0 -423
  664. package/dist/_chunks/dist-BA3u1z3W.js.map +0 -1
  665. package/dist/_chunks/mdx-file-C005ay-P.js.map +0 -1
  666. package/dist/_chunks/plugin-context-rCinWLiE.js.map +0 -1
  667. package/dist/_chunks/scanner-CAietmj4.js.map +0 -1
  668. package/dist/content/index.d.ts +0 -2
  669. package/dist/content/index.d.ts.map +0 -1
  670. package/dist/content/index.js +0 -0
  671. package/src/content/index.ts +0 -5
  672. package/src/shims/server-only-noop.js +0 -6
@@ -0,0 +1,386 @@
1
+ //#region src/cookies/validation.ts
2
+ /**
3
+ * Cookie name and value validation per RFC 6265 §4.1.1.
4
+ *
5
+ * This module is pure — no server or client imports — so it can be loaded
6
+ * by both `server/request-context.ts` (which guards `getCookies().set()`)
7
+ * and `client/use-cookie.ts` (which guards `useCookie()`'s setter). The
8
+ * shared validator gives both sides identical encoding contracts:
9
+ * **the framework never silently encodes — callers emit `cookie-octet`
10
+ * bytes or get a developer-facing error.**
11
+ *
12
+ * Why this matters: see ONGOING_SECURITY.md H-3 (TIM-868) and
13
+ * design/29-cookies.md §"Cookie Name and Value Validation".
14
+ */
15
+ /**
16
+ * RFC 7230 §3.2.6 token characters used as the cookie-name production in
17
+ * RFC 6265 §4.1.1. Anchored, non-empty match.
18
+ *
19
+ * Allowed: US-ASCII letters, digits, and `!#$%&'*+-.^_` `` ` `` `|~`.
20
+ * Disallowed: whitespace, controls, delimiters
21
+ * (`(` `)` `<` `>` `@` `,` `;` `:` `\` `"` `/` `[` `]` `?` `=` `{` `}`).
22
+ */
23
+ var COOKIE_NAME_RE = /^[!#$%&'*+\-.0-9A-Z^_`a-z|~]+$/;
24
+ /**
25
+ * Format a single byte for a clear error message — escape control bytes
26
+ * and non-ASCII as `0x..` and quote printables.
27
+ */
28
+ function describeChar(value, index) {
29
+ const code = value.charCodeAt(index);
30
+ if (code < 32 || code === 127 || code > 126) return `0x${code.toString(16).padStart(2, "0")}`;
31
+ return JSON.stringify(value[index]);
32
+ }
33
+ /**
34
+ * Validate a cookie name against RFC 6265 §4.1.1 / RFC 7230 token rules.
35
+ * Throws a developer-facing error naming the offending byte and its index.
36
+ */
37
+ function assertValidCookieName(name) {
38
+ if (typeof name !== "string" || name.length === 0) throw new Error("[timber] cookie name must be a non-empty string.");
39
+ if (!COOKIE_NAME_RE.test(name)) {
40
+ for (let i = 0; i < name.length; i++) if (!COOKIE_NAME_RE.test(name[i])) throw new Error(`[timber] invalid cookie name ${JSON.stringify(name)} — disallowed character ${describeChar(name, i)} at index ${i}. Cookie names must match the RFC 6265 §4.1.1 token grammar (US-ASCII letters, digits, and \`!#$%&'*+-.^_\`|~\`; no whitespace, controls, or delimiters).`);
41
+ throw new Error(`[timber] invalid cookie name ${JSON.stringify(name)} — must match RFC 6265 §4.1.1 token grammar.`);
42
+ }
43
+ }
44
+ /** Single-byte test for RFC 6265 §4.1.1 cookie-octet. */
45
+ function isCookieOctet(code) {
46
+ return code === 33 || code >= 35 && code <= 43 || code >= 45 && code <= 58 || code >= 60 && code <= 91 || code >= 93 && code <= 126;
47
+ }
48
+ /**
49
+ * Validate a cookie value against the RFC 6265 §4.1.1 `cookie-value`
50
+ * production:
51
+ *
52
+ * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
53
+ * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
54
+ *
55
+ * Both the bare `*cookie-octet` form and the DQUOTE-wrapped form are
56
+ * valid. The wrapped form is common in upstream `Set-Cookie` headers
57
+ * (e.g. `sid="abc"; Path=/`) and must be forwardable through
58
+ * `setFromHeaders` verbatim — stripping or rejecting the surrounding
59
+ * quotes would corrupt the on-the-wire bytes and break value semantics
60
+ * for the upstream service.
61
+ *
62
+ * Excluded bytes (in either form): CTL, whitespace (CR/LF/TAB/SP),
63
+ * interior DQUOTE, comma, semicolon, backslash, DEL, and anything
64
+ * non-ASCII. The smuggling primitive (`;`) is rejected regardless of
65
+ * wrapping.
66
+ *
67
+ * Throws a developer-facing error naming the offending byte and its
68
+ * index. Callers passing user-controlled data through the default
69
+ * `set()` path don't need to call this — `set()` auto-encodes via
70
+ * `encodeURIComponent`, whose output is always valid cookie-octet.
71
+ * This validator is for the `{ raw: true }` opt-out and for
72
+ * `setFromHeaders` forwarding.
73
+ */
74
+ /**
75
+ * Characters that must not appear in path or domain cookie attributes.
76
+ * Semicolons delimit cookie attributes on the wire, so allowing `;` in
77
+ * path or domain would inject extra attributes. CR/LF enable HTTP header
78
+ * injection.
79
+ */
80
+ var ATTR_INJECTION_RE = /[;\r\n]/;
81
+ var VALID_SAME_SITE = /* @__PURE__ */ new Set([
82
+ "strict",
83
+ "lax",
84
+ "none"
85
+ ]);
86
+ /**
87
+ * Validate cookie option attributes at runtime to prevent Set-Cookie
88
+ * header injection through unsanitized option values.
89
+ *
90
+ * TypeScript types enforce correct shapes at compile time, but at runtime
91
+ * (e.g. from untyped libraries or user-controlled config) invalid values
92
+ * could inject additional Set-Cookie attributes.
93
+ */
94
+ function assertValidCookieOptions(options) {
95
+ if (options.sameSite !== void 0) {
96
+ const lower = options.sameSite.toLowerCase();
97
+ if (!VALID_SAME_SITE.has(lower)) throw new Error(`[timber] invalid cookie sameSite value ${JSON.stringify(options.sameSite)} — must be 'strict', 'lax', or 'none'.`);
98
+ }
99
+ if (options.path !== void 0 && ATTR_INJECTION_RE.test(options.path)) throw new Error(`[timber] invalid cookie path ${JSON.stringify(options.path)} — path must not contain ';', CR, or LF (Set-Cookie header injection).`);
100
+ if (options.domain !== void 0 && ATTR_INJECTION_RE.test(options.domain)) throw new Error(`[timber] invalid cookie domain ${JSON.stringify(options.domain)} — domain must not contain ';', CR, or LF (Set-Cookie header injection).`);
101
+ if (options.maxAge !== void 0 && (typeof options.maxAge !== "number" || !Number.isFinite(options.maxAge))) throw new Error(`[timber] invalid cookie maxAge ${JSON.stringify(options.maxAge)} — maxAge must be a finite number.`);
102
+ }
103
+ function assertValidCookieValue(name, value) {
104
+ if (typeof value !== "string") throw new Error(`[timber] cookie ${JSON.stringify(name)}: cookie value must be a string.`);
105
+ const wrapped = value.length >= 2 && value.charCodeAt(0) === 34 && value.charCodeAt(value.length - 1) === 34;
106
+ const start = wrapped ? 1 : 0;
107
+ const end = wrapped ? value.length - 1 : value.length;
108
+ for (let i = start; i < end; i++) if (!isCookieOctet(value.charCodeAt(i))) throw new Error(`[timber] cookie ${JSON.stringify(name)}: invalid cookie value — disallowed character ${describeChar(value, i)} at index ${i}. Cookie values must contain only RFC 6265 §4.1.1 cookie-octet bytes (US-ASCII printable, excluding whitespace, \`"\`, \`,\`, \`;\`, and \`\\\`), optionally enclosed in a single DQUOTE pair. Encode the value (e.g. encodeURIComponent or jsonCookieCodec) before storing it.`);
109
+ }
110
+ //#endregion
111
+ //#region ../../node_modules/.pnpm/cookie@2.0.1/node_modules/cookie/dist/index.js
112
+ /**
113
+ * RegExp to match cookie-name in RFC 6265 sec 4.1.1
114
+ * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
115
+ * which has been replaced by the token definition in RFC 7230 appendix B.
116
+ *
117
+ * cookie-name = token
118
+ * token = 1*tchar
119
+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" /
120
+ * "*" / "+" / "-" / "." / "^" / "_" /
121
+ * "`" / "|" / "~" / DIGIT / ALPHA
122
+ *
123
+ * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191
124
+ * Allow same range as cookie value, except `=`, which delimits end of name.
125
+ */
126
+ var cookieNameRegExp = /^[\u0021-\u003A\u003C\u003E-\u007E]+$/;
127
+ /**
128
+ * RegExp to match cookie-value in RFC 6265 sec 4.1.1
129
+ *
130
+ * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
131
+ * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
132
+ * ; US-ASCII characters excluding CTLs,
133
+ * ; whitespace DQUOTE, comma, semicolon,
134
+ * ; and backslash
135
+ *
136
+ * Allowing more characters: https://github.com/jshttp/cookie/issues/191
137
+ * Comma, backslash, and DQUOTE are not part of the parsing algorithm.
138
+ */
139
+ var cookieValueRegExp = /^[\u0021-\u003A\u003C-\u007E]*$/;
140
+ /**
141
+ * RegExp to match domain-value in RFC 6265 sec 4.1.1
142
+ *
143
+ * domain-value = <subdomain>
144
+ * ; defined in [RFC1034], Section 3.5, as
145
+ * ; enhanced by [RFC1123], Section 2.1
146
+ * <subdomain> = <label> | <subdomain> "." <label>
147
+ * <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]
148
+ * Labels must be 63 characters or less.
149
+ * 'let-dig' not 'letter' in the first char, per RFC1123
150
+ * <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
151
+ * <let-dig-hyp> = <let-dig> | "-"
152
+ * <let-dig> = <letter> | <digit>
153
+ * <letter> = any one of the 52 alphabetic characters A through Z in
154
+ * upper case and a through z in lower case
155
+ * <digit> = any one of the ten digits 0 through 9
156
+ *
157
+ * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
158
+ *
159
+ * > (Note that a leading %x2E ("."), if present, is ignored even though that
160
+ * character is not permitted, but a trailing %x2E ("."), if present, will
161
+ * cause the user agent to ignore the attribute.)
162
+ */
163
+ var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
164
+ /**
165
+ * RegExp to match path-value in RFC 6265 sec 4.1.1
166
+ *
167
+ * path-value = <any CHAR except CTLs or ";">
168
+ * CHAR = %x01-7F
169
+ * ; defined in RFC 5234 appendix B.1
170
+ */
171
+ var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
172
+ /**
173
+ * RegExp to match max-age-value in RFC 6265 sec 5.6.2
174
+ */
175
+ var maxAgeRegExp = /^-?\d+$/;
176
+ /**
177
+ * RegExp to match RFC 6265 cookie-octet values (without % to preserve roundtrip) that need no URL encoding.
178
+ */
179
+ var cookieOctetRegExp = /^[!#$&'()*+\-.\/0-9:<=>?@A-Z[\]\^_`a-z{|}~]*$/;
180
+ var NullObject = /* @__PURE__ */ (() => {
181
+ const C = function() {};
182
+ C.prototype = Object.create(null);
183
+ return C;
184
+ })();
185
+ /**
186
+ * Parse a `Cookie` header.
187
+ *
188
+ * Parse the given cookie header string into an object
189
+ * The object has the various cookies as keys(names) => values
190
+ */
191
+ function parseCookie(str, options) {
192
+ const obj = new NullObject();
193
+ const len = str.length;
194
+ if (len < 2) return obj;
195
+ const dec = options?.decode || decode;
196
+ let index = 0;
197
+ do {
198
+ const eqIdx = eqIndex(str, index, len);
199
+ if (eqIdx === len) break;
200
+ const endIdx = endIndex(str, index, len);
201
+ if (eqIdx > endIdx) {
202
+ index = str.lastIndexOf(";", eqIdx - 1) + 1;
203
+ continue;
204
+ }
205
+ const key = valueSlice(str, index, eqIdx);
206
+ if (obj[key] === void 0) obj[key] = dec(valueSlice(str, eqIdx + 1, endIdx));
207
+ index = endIdx + 1;
208
+ } while (index < len);
209
+ return obj;
210
+ }
211
+ /**
212
+ * Serialize data into a cookie header.
213
+ *
214
+ * Serialize a name value pair into a cookie string suitable for
215
+ * http headers. An optional options object specifies cookie parameters.
216
+ *
217
+ * stringifySetCookie({ name: 'foo', value: 'bar', httpOnly: true })
218
+ * => "foo=bar; HttpOnly"
219
+ */
220
+ function stringifySetCookie(cookie, options) {
221
+ const enc = options?.encode || defaultEncode;
222
+ if (!cookieNameRegExp.test(cookie.name)) throw new TypeError(`argument name is invalid: ${cookie.name}`);
223
+ const value = cookie.value == null ? "" : enc(cookie.value);
224
+ if (!cookieValueRegExp.test(value)) throw new TypeError(`argument val is invalid: ${cookie.value}`);
225
+ let str = cookie.name + "=" + value;
226
+ if (cookie.maxAge !== void 0) {
227
+ if (!Number.isInteger(cookie.maxAge)) throw new TypeError(`option maxAge is invalid: ${cookie.maxAge}`);
228
+ str += "; Max-Age=" + cookie.maxAge;
229
+ }
230
+ if (cookie.domain) {
231
+ if (!domainValueRegExp.test(cookie.domain)) throw new TypeError(`option domain is invalid: ${cookie.domain}`);
232
+ str += "; Domain=" + cookie.domain;
233
+ }
234
+ if (cookie.path) {
235
+ if (!pathValueRegExp.test(cookie.path)) throw new TypeError(`option path is invalid: ${cookie.path}`);
236
+ str += "; Path=" + cookie.path;
237
+ }
238
+ if (cookie.expires) {
239
+ if (!Number.isFinite(cookie.expires.valueOf())) throw new TypeError(`option expires is invalid: ${cookie.expires}`);
240
+ str += "; Expires=" + cookie.expires.toUTCString();
241
+ }
242
+ if (cookie.httpOnly) str += "; HttpOnly";
243
+ if (cookie.secure) str += "; Secure";
244
+ if (cookie.partitioned) str += "; Partitioned";
245
+ if (cookie.priority) switch (typeof cookie.priority === "string" ? cookie.priority.toLowerCase() : void 0) {
246
+ case "low":
247
+ str += "; Priority=Low";
248
+ break;
249
+ case "medium":
250
+ str += "; Priority=Medium";
251
+ break;
252
+ case "high":
253
+ str += "; Priority=High";
254
+ break;
255
+ default: throw new TypeError(`option priority is invalid: ${cookie.priority}`);
256
+ }
257
+ if (cookie.sameSite) switch (typeof cookie.sameSite === "string" ? cookie.sameSite.toLowerCase() : cookie.sameSite) {
258
+ case true:
259
+ case "strict":
260
+ str += "; SameSite=Strict";
261
+ break;
262
+ case "lax":
263
+ str += "; SameSite=Lax";
264
+ break;
265
+ case "none":
266
+ str += "; SameSite=None";
267
+ break;
268
+ default: throw new TypeError(`option sameSite is invalid: ${cookie.sameSite}`);
269
+ }
270
+ return str;
271
+ }
272
+ /**
273
+ * Deserialize a `Set-Cookie` header into an object.
274
+ *
275
+ * parseSetCookie('foo=bar; HttpOnly')
276
+ * => { name: 'foo', value: 'bar', httpOnly: true }
277
+ */
278
+ function parseSetCookie(str, options) {
279
+ const dec = options?.decode || decode;
280
+ const len = str.length;
281
+ const endIdx = endIndex(str, 0, len);
282
+ let eqIdx = eqIndex(str, 0, len);
283
+ const setCookie = eqIdx < endIdx ? {
284
+ name: valueSlice(str, 0, eqIdx),
285
+ value: dec(valueSlice(str, eqIdx + 1, endIdx))
286
+ } : {
287
+ name: "",
288
+ value: dec(valueSlice(str, 0, endIdx))
289
+ };
290
+ let index = endIdx + 1;
291
+ while (index < len) {
292
+ const endIdx = endIndex(str, index, len);
293
+ if (eqIdx < index) eqIdx = eqIndex(str, index, len);
294
+ const attr = eqIdx < endIdx ? valueSlice(str, index, eqIdx) : valueSlice(str, index, endIdx);
295
+ const val = eqIdx < endIdx ? valueSlice(str, eqIdx + 1, endIdx) : void 0;
296
+ switch (attr.toLowerCase()) {
297
+ case "httponly":
298
+ setCookie.httpOnly = true;
299
+ break;
300
+ case "secure":
301
+ setCookie.secure = true;
302
+ break;
303
+ case "partitioned":
304
+ setCookie.partitioned = true;
305
+ break;
306
+ case "domain":
307
+ setCookie.domain = val;
308
+ break;
309
+ case "path":
310
+ setCookie.path = val;
311
+ break;
312
+ case "max-age":
313
+ if (val && maxAgeRegExp.test(val)) setCookie.maxAge = Number(val);
314
+ break;
315
+ case "expires":
316
+ if (!val) break;
317
+ const date = new Date(val);
318
+ if (Number.isFinite(date.valueOf())) setCookie.expires = date;
319
+ break;
320
+ case "priority":
321
+ if (!val) break;
322
+ const priority = val.toLowerCase();
323
+ if (priority === "low" || priority === "medium" || priority === "high") setCookie.priority = priority;
324
+ break;
325
+ case "samesite":
326
+ if (!val) break;
327
+ const sameSite = val.toLowerCase();
328
+ if (sameSite === "lax" || sameSite === "strict" || sameSite === "none") setCookie.sameSite = sameSite;
329
+ }
330
+ index = endIdx + 1;
331
+ }
332
+ return setCookie;
333
+ }
334
+ /**
335
+ * Find the next `;` character, or return `len`.
336
+ */
337
+ function endIndex(str, min, len) {
338
+ const index = str.indexOf(";", min);
339
+ return index === -1 ? len : index;
340
+ }
341
+ /**
342
+ * Find the next `=` character, or return `len`.
343
+ */
344
+ function eqIndex(str, min, len) {
345
+ const index = str.indexOf("=", min);
346
+ return index === -1 ? len : index;
347
+ }
348
+ /**
349
+ * Slice out a value between startPod to max.
350
+ */
351
+ function valueSlice(str, min, max) {
352
+ if (min === max) return "";
353
+ let start = min;
354
+ let end = max;
355
+ do {
356
+ const code = str.charCodeAt(start);
357
+ if (code !== 32 && code !== 9) break;
358
+ } while (++start < end);
359
+ while (end > start) {
360
+ const code = str.charCodeAt(end - 1);
361
+ if (code !== 32 && code !== 9) break;
362
+ end--;
363
+ }
364
+ return str.slice(start, end);
365
+ }
366
+ /**
367
+ * URL-decode string value. Optimized to skip native call when no %.
368
+ */
369
+ function decode(str) {
370
+ if (str.indexOf("%") === -1) return str;
371
+ try {
372
+ return decodeURIComponent(str);
373
+ } catch (e) {
374
+ return str;
375
+ }
376
+ }
377
+ /**
378
+ * URL-encode string value. Optimized to skip native call for roundtrip-safe cookie-octet values.
379
+ */
380
+ function defaultEncode(str) {
381
+ return cookieOctetRegExp.test(str) ? str : encodeURIComponent(str);
382
+ }
383
+ //#endregion
384
+ export { assertValidCookieOptions as a, assertValidCookieName as i, parseSetCookie as n, assertValidCookieValue as o, stringifySetCookie as r, parseCookie as t };
385
+
386
+ //# sourceMappingURL=dist-DtrJyBbw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dist-DtrJyBbw.js","names":[],"sources":["../../src/cookies/validation.ts","../../../../node_modules/.pnpm/cookie@2.0.1/node_modules/cookie/dist/index.js"],"sourcesContent":["/**\n * Cookie name and value validation per RFC 6265 §4.1.1.\n *\n * This module is pure — no server or client imports — so it can be loaded\n * by both `server/request-context.ts` (which guards `getCookies().set()`)\n * and `client/use-cookie.ts` (which guards `useCookie()`'s setter). The\n * shared validator gives both sides identical encoding contracts:\n * **the framework never silently encodes — callers emit `cookie-octet`\n * bytes or get a developer-facing error.**\n *\n * Why this matters: see ONGOING_SECURITY.md H-3 (TIM-868) and\n * design/29-cookies.md §\"Cookie Name and Value Validation\".\n */\n\n// ─── RFC 6265 cookie-octet ────────────────────────────────────────────────\n//\n// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E\n//\n// Equivalently: US-ASCII printable bytes excluding whitespace, `\"` (0x22),\n// `,` (0x2C), `;` (0x3B), `\\` (0x5C), and DEL (0x7F).\n\n/**\n * RFC 7230 §3.2.6 token characters used as the cookie-name production in\n * RFC 6265 §4.1.1. Anchored, non-empty match.\n *\n * Allowed: US-ASCII letters, digits, and `!#$%&'*+-.^_` `` ` `` `|~`.\n * Disallowed: whitespace, controls, delimiters\n * (`(` `)` `<` `>` `@` `,` `;` `:` `\\` `\"` `/` `[` `]` `?` `=` `{` `}`).\n */\nconst COOKIE_NAME_RE = /^[!#$%&'*+\\-.0-9A-Z^_`a-z|~]+$/;\n\n/**\n * Format a single byte for a clear error message — escape control bytes\n * and non-ASCII as `0x..` and quote printables.\n */\nfunction describeChar(value: string, index: number): string {\n const code = value.charCodeAt(index);\n if (code < 0x20 || code === 0x7f || code > 0x7e) {\n return `0x${code.toString(16).padStart(2, '0')}`;\n }\n return JSON.stringify(value[index]);\n}\n\n/**\n * Validate a cookie name against RFC 6265 §4.1.1 / RFC 7230 token rules.\n * Throws a developer-facing error naming the offending byte and its index.\n */\nexport function assertValidCookieName(name: string): void {\n if (typeof name !== 'string' || name.length === 0) {\n throw new Error('[timber] cookie name must be a non-empty string.');\n }\n if (!COOKIE_NAME_RE.test(name)) {\n for (let i = 0; i < name.length; i++) {\n if (!COOKIE_NAME_RE.test(name[i])) {\n throw new Error(\n `[timber] invalid cookie name ${JSON.stringify(name)} — ` +\n `disallowed character ${describeChar(name, i)} at index ${i}. ` +\n `Cookie names must match the RFC 6265 §4.1.1 token grammar (US-ASCII letters, digits, ` +\n `and \\`!#$%&'*+-.^_\\`|~\\`; no whitespace, controls, or delimiters).`\n );\n }\n }\n throw new Error(\n `[timber] invalid cookie name ${JSON.stringify(name)} — ` +\n `must match RFC 6265 §4.1.1 token grammar.`\n );\n }\n}\n\n/** Single-byte test for RFC 6265 §4.1.1 cookie-octet. */\nfunction isCookieOctet(code: number): boolean {\n return (\n code === 0x21 ||\n (code >= 0x23 && code <= 0x2b) ||\n (code >= 0x2d && code <= 0x3a) ||\n (code >= 0x3c && code <= 0x5b) ||\n (code >= 0x5d && code <= 0x7e)\n );\n}\n\n/**\n * Validate a cookie value against the RFC 6265 §4.1.1 `cookie-value`\n * production:\n *\n * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )\n * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E\n *\n * Both the bare `*cookie-octet` form and the DQUOTE-wrapped form are\n * valid. The wrapped form is common in upstream `Set-Cookie` headers\n * (e.g. `sid=\"abc\"; Path=/`) and must be forwardable through\n * `setFromHeaders` verbatim — stripping or rejecting the surrounding\n * quotes would corrupt the on-the-wire bytes and break value semantics\n * for the upstream service.\n *\n * Excluded bytes (in either form): CTL, whitespace (CR/LF/TAB/SP),\n * interior DQUOTE, comma, semicolon, backslash, DEL, and anything\n * non-ASCII. The smuggling primitive (`;`) is rejected regardless of\n * wrapping.\n *\n * Throws a developer-facing error naming the offending byte and its\n * index. Callers passing user-controlled data through the default\n * `set()` path don't need to call this — `set()` auto-encodes via\n * `encodeURIComponent`, whose output is always valid cookie-octet.\n * This validator is for the `{ raw: true }` opt-out and for\n * `setFromHeaders` forwarding.\n */\n// ─── Cookie attribute validation ──────────────────────────────────────────\n\n/**\n * Characters that must not appear in path or domain cookie attributes.\n * Semicolons delimit cookie attributes on the wire, so allowing `;` in\n * path or domain would inject extra attributes. CR/LF enable HTTP header\n * injection.\n */\nconst ATTR_INJECTION_RE = /[;\\r\\n]/;\n\nconst VALID_SAME_SITE = new Set(['strict', 'lax', 'none']);\n\n/**\n * Validate cookie option attributes at runtime to prevent Set-Cookie\n * header injection through unsanitized option values.\n *\n * TypeScript types enforce correct shapes at compile time, but at runtime\n * (e.g. from untyped libraries or user-controlled config) invalid values\n * could inject additional Set-Cookie attributes.\n */\nexport function assertValidCookieOptions(options: {\n sameSite?: string;\n path?: string;\n domain?: string;\n maxAge?: number;\n}): void {\n if (options.sameSite !== undefined) {\n const lower = options.sameSite.toLowerCase();\n if (!VALID_SAME_SITE.has(lower)) {\n throw new Error(\n `[timber] invalid cookie sameSite value ${JSON.stringify(options.sameSite)} — ` +\n `must be 'strict', 'lax', or 'none'.`\n );\n }\n }\n if (options.path !== undefined && ATTR_INJECTION_RE.test(options.path)) {\n throw new Error(\n `[timber] invalid cookie path ${JSON.stringify(options.path)} — ` +\n `path must not contain ';', CR, or LF (Set-Cookie header injection).`\n );\n }\n if (options.domain !== undefined && ATTR_INJECTION_RE.test(options.domain)) {\n throw new Error(\n `[timber] invalid cookie domain ${JSON.stringify(options.domain)} — ` +\n `domain must not contain ';', CR, or LF (Set-Cookie header injection).`\n );\n }\n if (\n options.maxAge !== undefined &&\n (typeof options.maxAge !== 'number' || !Number.isFinite(options.maxAge))\n ) {\n throw new Error(\n `[timber] invalid cookie maxAge ${JSON.stringify(options.maxAge)} — ` +\n `maxAge must be a finite number.`\n );\n }\n}\n\nexport function assertValidCookieValue(name: string, value: string): void {\n if (typeof value !== 'string') {\n throw new Error(`[timber] cookie ${JSON.stringify(name)}: cookie value must be a string.`);\n }\n // Detect the DQUOTE-wrapped form: at least two characters and both\n // endpoints are `\"`. The interior must be pure cookie-octet (no\n // interior DQUOTEs allowed — the grammar says *cookie-octet, and\n // cookie-octet excludes 0x22).\n const wrapped =\n value.length >= 2 &&\n value.charCodeAt(0) === 0x22 &&\n value.charCodeAt(value.length - 1) === 0x22;\n const start = wrapped ? 1 : 0;\n const end = wrapped ? value.length - 1 : value.length;\n for (let i = start; i < end; i++) {\n const code = value.charCodeAt(i);\n if (!isCookieOctet(code)) {\n throw new Error(\n `[timber] cookie ${JSON.stringify(name)}: invalid cookie value — ` +\n `disallowed character ${describeChar(value, i)} at index ${i}. ` +\n `Cookie values must contain only RFC 6265 §4.1.1 cookie-octet bytes ` +\n `(US-ASCII printable, excluding whitespace, \\`\"\\`, \\`,\\`, \\`;\\`, and \\`\\\\\\`), ` +\n `optionally enclosed in a single DQUOTE pair. ` +\n `Encode the value (e.g. encodeURIComponent or jsonCookieCodec) before storing it.`\n );\n }\n }\n}\n","/**\n * RegExp to match cookie-name in RFC 6265 sec 4.1.1\n * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2\n * which has been replaced by the token definition in RFC 7230 appendix B.\n *\n * cookie-name = token\n * token = 1*tchar\n * tchar = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" /\n * \"*\" / \"+\" / \"-\" / \".\" / \"^\" / \"_\" /\n * \"`\" / \"|\" / \"~\" / DIGIT / ALPHA\n *\n * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191\n * Allow same range as cookie value, except `=`, which delimits end of name.\n */\nconst cookieNameRegExp = /^[\\u0021-\\u003A\\u003C\\u003E-\\u007E]+$/;\n/**\n * RegExp to match cookie-value in RFC 6265 sec 4.1.1\n *\n * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )\n * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E\n * ; US-ASCII characters excluding CTLs,\n * ; whitespace DQUOTE, comma, semicolon,\n * ; and backslash\n *\n * Allowing more characters: https://github.com/jshttp/cookie/issues/191\n * Comma, backslash, and DQUOTE are not part of the parsing algorithm.\n */\nconst cookieValueRegExp = /^[\\u0021-\\u003A\\u003C-\\u007E]*$/;\n/**\n * RegExp to match domain-value in RFC 6265 sec 4.1.1\n *\n * domain-value = <subdomain>\n * ; defined in [RFC1034], Section 3.5, as\n * ; enhanced by [RFC1123], Section 2.1\n * <subdomain> = <label> | <subdomain> \".\" <label>\n * <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]\n * Labels must be 63 characters or less.\n * 'let-dig' not 'letter' in the first char, per RFC1123\n * <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>\n * <let-dig-hyp> = <let-dig> | \"-\"\n * <let-dig> = <letter> | <digit>\n * <letter> = any one of the 52 alphabetic characters A through Z in\n * upper case and a through z in lower case\n * <digit> = any one of the ten digits 0 through 9\n *\n * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173\n *\n * > (Note that a leading %x2E (\".\"), if present, is ignored even though that\n * character is not permitted, but a trailing %x2E (\".\"), if present, will\n * cause the user agent to ignore the attribute.)\n */\nconst domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;\n/**\n * RegExp to match path-value in RFC 6265 sec 4.1.1\n *\n * path-value = <any CHAR except CTLs or \";\">\n * CHAR = %x01-7F\n * ; defined in RFC 5234 appendix B.1\n */\nconst pathValueRegExp = /^[\\u0020-\\u003A\\u003D-\\u007E]*$/;\n/**\n * RegExp to match max-age-value in RFC 6265 sec 5.6.2\n */\nconst maxAgeRegExp = /^-?\\d+$/;\n/**\n * RegExp to match RFC 6265 cookie-octet values (without % to preserve roundtrip) that need no URL encoding.\n */\nconst cookieOctetRegExp = /^[!#$&'()*+\\-.\\/0-9:<=>?@A-Z[\\]\\^_`a-z{|}~]*$/;\nconst NullObject = /* @__PURE__ */ (() => {\n const C = function () { };\n C.prototype = Object.create(null);\n return C;\n})();\n/**\n * Parse a `Cookie` header.\n *\n * Parse the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function parseCookie(str, options) {\n const obj = new NullObject();\n const len = str.length;\n // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.\n if (len < 2)\n return obj;\n const dec = options?.decode || decode;\n let index = 0;\n do {\n const eqIdx = eqIndex(str, index, len);\n if (eqIdx === len)\n break; // No more cookie pairs.\n const endIdx = endIndex(str, index, len);\n if (eqIdx > endIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n const key = valueSlice(str, index, eqIdx);\n // only assign once\n if (obj[key] === undefined) {\n obj[key] = dec(valueSlice(str, eqIdx + 1, endIdx));\n }\n index = endIdx + 1;\n } while (index < len);\n return obj;\n}\n/**\n * Stringifies an object into an HTTP `Cookie` header.\n */\nexport function stringifyCookie(cookie, options) {\n const enc = options?.encode || defaultEncode;\n const keys = Object.keys(cookie);\n let str = \"\";\n for (let i = 0; i < keys.length; i++) {\n const name = keys[i];\n const val = cookie[name];\n if (val === undefined)\n continue;\n if (!cookieNameRegExp.test(name)) {\n throw new TypeError(`cookie name is invalid: ${name}`);\n }\n const value = enc(val);\n if (!cookieValueRegExp.test(value)) {\n throw new TypeError(`cookie val is invalid: ${val}`);\n }\n if (str)\n str += \"; \";\n str += name + \"=\" + value;\n }\n return str;\n}\n/**\n * Serialize data into a cookie header.\n *\n * Serialize a name value pair into a cookie string suitable for\n * http headers. An optional options object specifies cookie parameters.\n *\n * stringifySetCookie({ name: 'foo', value: 'bar', httpOnly: true })\n * => \"foo=bar; HttpOnly\"\n */\nexport function stringifySetCookie(cookie, options) {\n const enc = options?.encode || defaultEncode;\n if (!cookieNameRegExp.test(cookie.name)) {\n throw new TypeError(`argument name is invalid: ${cookie.name}`);\n }\n const value = cookie.value == null ? \"\" : enc(cookie.value);\n if (!cookieValueRegExp.test(value)) {\n throw new TypeError(`argument val is invalid: ${cookie.value}`);\n }\n let str = cookie.name + \"=\" + value;\n if (cookie.maxAge !== undefined) {\n if (!Number.isInteger(cookie.maxAge)) {\n throw new TypeError(`option maxAge is invalid: ${cookie.maxAge}`);\n }\n str += \"; Max-Age=\" + cookie.maxAge;\n }\n if (cookie.domain) {\n if (!domainValueRegExp.test(cookie.domain)) {\n throw new TypeError(`option domain is invalid: ${cookie.domain}`);\n }\n str += \"; Domain=\" + cookie.domain;\n }\n if (cookie.path) {\n if (!pathValueRegExp.test(cookie.path)) {\n throw new TypeError(`option path is invalid: ${cookie.path}`);\n }\n str += \"; Path=\" + cookie.path;\n }\n if (cookie.expires) {\n if (!Number.isFinite(cookie.expires.valueOf())) {\n throw new TypeError(`option expires is invalid: ${cookie.expires}`);\n }\n str += \"; Expires=\" + cookie.expires.toUTCString();\n }\n if (cookie.httpOnly) {\n str += \"; HttpOnly\";\n }\n if (cookie.secure) {\n str += \"; Secure\";\n }\n if (cookie.partitioned) {\n str += \"; Partitioned\";\n }\n if (cookie.priority) {\n const priority = typeof cookie.priority === \"string\"\n ? cookie.priority.toLowerCase()\n : undefined;\n switch (priority) {\n case \"low\":\n str += \"; Priority=Low\";\n break;\n case \"medium\":\n str += \"; Priority=Medium\";\n break;\n case \"high\":\n str += \"; Priority=High\";\n break;\n default:\n throw new TypeError(`option priority is invalid: ${cookie.priority}`);\n }\n }\n if (cookie.sameSite) {\n const sameSite = typeof cookie.sameSite === \"string\"\n ? cookie.sameSite.toLowerCase()\n : cookie.sameSite;\n switch (sameSite) {\n case true:\n case \"strict\":\n str += \"; SameSite=Strict\";\n break;\n case \"lax\":\n str += \"; SameSite=Lax\";\n break;\n case \"none\":\n str += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(`option sameSite is invalid: ${cookie.sameSite}`);\n }\n }\n return str;\n}\n/**\n * Deserialize a `Set-Cookie` header into an object.\n *\n * parseSetCookie('foo=bar; HttpOnly')\n * => { name: 'foo', value: 'bar', httpOnly: true }\n */\nexport function parseSetCookie(str, options) {\n const dec = options?.decode || decode;\n const len = str.length;\n const endIdx = endIndex(str, 0, len);\n let eqIdx = eqIndex(str, 0, len);\n const setCookie = eqIdx < endIdx\n ? {\n name: valueSlice(str, 0, eqIdx),\n value: dec(valueSlice(str, eqIdx + 1, endIdx)),\n }\n : { name: \"\", value: dec(valueSlice(str, 0, endIdx)) };\n let index = endIdx + 1;\n while (index < len) {\n const endIdx = endIndex(str, index, len);\n if (eqIdx < index)\n eqIdx = eqIndex(str, index, len);\n const attr = eqIdx < endIdx\n ? valueSlice(str, index, eqIdx)\n : valueSlice(str, index, endIdx);\n const val = eqIdx < endIdx ? valueSlice(str, eqIdx + 1, endIdx) : undefined;\n switch (attr.toLowerCase()) {\n case \"httponly\":\n setCookie.httpOnly = true;\n break;\n case \"secure\":\n setCookie.secure = true;\n break;\n case \"partitioned\":\n setCookie.partitioned = true;\n break;\n case \"domain\":\n setCookie.domain = val;\n break;\n case \"path\":\n setCookie.path = val;\n break;\n case \"max-age\":\n if (val && maxAgeRegExp.test(val))\n setCookie.maxAge = Number(val);\n break;\n case \"expires\":\n if (!val)\n break;\n const date = new Date(val);\n if (Number.isFinite(date.valueOf()))\n setCookie.expires = date;\n break;\n case \"priority\":\n if (!val)\n break;\n const priority = val.toLowerCase();\n if (priority === \"low\" ||\n priority === \"medium\" ||\n priority === \"high\") {\n setCookie.priority = priority;\n }\n break;\n case \"samesite\":\n if (!val)\n break;\n const sameSite = val.toLowerCase();\n if (sameSite === \"lax\" ||\n sameSite === \"strict\" ||\n sameSite === \"none\") {\n setCookie.sameSite = sameSite;\n }\n break;\n }\n index = endIdx + 1;\n }\n return setCookie;\n}\n/**\n * Find the next `;` character, or return `len`.\n */\nfunction endIndex(str, min, len) {\n const index = str.indexOf(\";\", min);\n return index === -1 ? len : index;\n}\n/**\n * Find the next `=` character, or return `len`.\n */\nfunction eqIndex(str, min, len) {\n const index = str.indexOf(\"=\", min);\n return index === -1 ? len : index;\n}\n/**\n * Slice out a value between startPod to max.\n */\nfunction valueSlice(str, min, max) {\n if (min === max)\n return \"\";\n let start = min;\n let end = max;\n do {\n const code = str.charCodeAt(start);\n if (code !== 32 /* */ && code !== 9 /* \\t */)\n break;\n } while (++start < end);\n while (end > start) {\n const code = str.charCodeAt(end - 1);\n if (code !== 32 /* */ && code !== 9 /* \\t */)\n break;\n end--;\n }\n return str.slice(start, end);\n}\n/**\n * URL-decode string value. Optimized to skip native call when no %.\n */\nfunction decode(str) {\n if (str.indexOf(\"%\") === -1)\n return str;\n try {\n return decodeURIComponent(str);\n }\n catch (e) {\n return str;\n }\n}\n/**\n * URL-encode string value. Optimized to skip native call for roundtrip-safe cookie-octet values.\n */\nfunction defaultEncode(str) {\n return cookieOctetRegExp.test(str) ? str : encodeURIComponent(str);\n}\n//# sourceMappingURL=index.js.map"],"x_google_ignoreList":[1],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"error-boundary-D-ODYX41.js","names":[],"sources":["../../src/client/unload-guard.ts","../../src/client/stale-client.ts","../../src/client/error-boundary.tsx"],"sourcesContent":["/**\n * Page unload detection — suppresses spurious errors during page refresh/navigation.\n *\n * When the user refreshes the page or navigates away while React is still\n * streaming Suspense content, the aborted connection causes streaming errors.\n * These are not application errors — they're a side effect of the browser\n * tearing down the connection. This module tracks whether the page is being\n * unloaded so error boundaries and error handlers can suppress abort-related\n * errors during the unload window.\n *\n * This is the single owner of \"is this document going away\". Anything that\n * needs the answer imports `isPageUnloading()` — an unload flag maintained a\n * second time somewhere else is a flag that will drift out of agreement with\n * this one (TIM-1260).\n *\n * Mutable state is delegated to client/state.ts for singleton guarantees.\n * See design/18-build-system.md §\"Singleton State Registry\"\n *\n * See design/10-error-handling.md §\"Known limitation: deny() inside Suspense and hydration\"\n */\n\nimport { unloading, _setUnloading } from './state.js';\n\n/**\n * Departure is *committed*: `pagehide` has fired, or this document has called\n * reload() on itself. `beforeunload` alone doesn't qualify — it is\n * speculative, and the user can still cancel out of it.\n */\nlet committed = false;\n\nif (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n _setUnloading(true);\n\n // An app with an unsaved-changes prompt can have this cancelled. Nothing\n // fires to say so, so the only signal is that the page is still running\n // afterwards — and timers are blocked while the modal is up, so this task\n // cannot run until the user has chosen. If they left, `pagehide` has\n // already committed and this is a no-op.\n setTimeout(() => {\n if (!committed) _setUnloading(false);\n }, 0);\n });\n\n // pagehide is the committed-departure event, and fires for both navigations\n // and bfcache entry. Safari in particular may skip beforeunload entirely.\n window.addEventListener('pagehide', () => {\n committed = true;\n _setUnloading(true);\n });\n\n window.addEventListener('pageshow', (event) => {\n // A bfcache restore un-does the teardown `pagehide` announced: the same\n // document is alive again, with this module's state intact. Without the\n // reset, every consumer would go on suppressing errors on a live page.\n if (event.persisted) {\n committed = false;\n _setUnloading(false);\n }\n });\n}\n\n/**\n * Returns true if the page is currently being unloaded (user refreshed\n * or navigated away). Error boundaries should suppress errors in this state.\n */\nexport function isPageUnloading(): boolean {\n return unloading;\n}\n","/**\n * Stale Client — knowing when this bundle has been superseded.\n *\n * Layer 1 of version skew handling (see design/33-version-skew.md) is\n * proactive: the server compares `X-Timber-Deployment-Id` against the current\n * build and answers a stale client with `X-Timber-Reload: 1`. That covers\n * every RSC navigation and every server action — as long as there is a server\n * in the request path.\n *\n * This module is the reactive half, plus the state both halves feed. It\n * recognizes the two error shapes a stale client produces on its own:\n *\n * 1. **Stale client references** — React's Flight client throws\n * \"Could not find the module …\" when an RSC payload names a client module\n * ID that isn't in this bundle's manifest.\n * 2. **Chunk load failures** — a content-hashed chunk that no longer exists on\n * the CDN fails to `import()`. Every engine words this differently.\n *\n * It matters most for `output: 'static'`, where there is no server to send the\n * reload header and this is the *only* skew detection that can run.\n *\n * **Nothing here reloads the page.** A stale client is recorded, not acted on;\n * the router turns the next user-initiated navigation into a full document\n * load. See design/33-version-skew.md §\"Recovery on the next navigation\" for\n * why — a self-issued `location.reload()` cannot tell a recovery from a bounce\n * between two live deployments, and mid-rollout it produces exactly that loop.\n *\n * See TIM-1260, TIM-1275.\n */\n\n// The only import: the shared unload state. Kept minimal because this module\n// is reached from the error boundary, a `'use client'` component evaluated in\n// the SSR graph too — a dependency on the client fetch layer would drag that\n// graph along with it.\nimport { isPageUnloading } from './unload-guard.js';\n\n// ─── Error Shapes ────────────────────────────────────────────────\n\n/**\n * Substrings that identify a failed dynamic import, lowercased for\n * case-insensitive matching. Engines and bundlers each word this\n * differently and none of them expose a stable error code.\n */\nconst CHUNK_LOAD_PATTERNS = [\n // Chromium\n 'failed to fetch dynamically imported module',\n // Firefox\n 'error loading dynamically imported module',\n // Safari\n 'importing a module script failed',\n // Vite's preload helper, for the stylesheet of a lazily-imported chunk\n 'unable to preload css for',\n];\n\n/** Substring React's Flight client uses when a client module ID is unknown. */\nconst STALE_REFERENCE_PATTERN = 'could not find the module';\n\n/**\n * Pull a comparable message out of an unknown thrown value. Rejections cross\n * enough boundaries (event handlers, `unhandledrejection`, Vite's preload\n * event) that the value is not reliably an `Error`.\n */\nfunction messageOf(error: unknown): string {\n if (typeof error === 'string') return error.toLowerCase();\n if (error instanceof Error) return error.message.toLowerCase();\n if (error && typeof error === 'object' && 'message' in error) {\n const message = (error as { message: unknown }).message;\n if (typeof message === 'string') return message.toLowerCase();\n }\n return '';\n}\n\n/**\n * True when the error is React's \"client reference not in this manifest\"\n * failure — the payload was produced by a build this bundle doesn't match.\n */\nexport function isStaleClientReference(error: unknown): boolean {\n return messageOf(error).includes(STALE_REFERENCE_PATTERN);\n}\n\n/**\n * True when the error is a failed dynamic import or CSS preload — the\n * content-hashed chunk this bundle asks for is gone from the CDN.\n */\nexport function isChunkLoadError(error: unknown): boolean {\n if (error instanceof Error && error.name === 'ChunkLoadError') return true;\n const message = messageOf(error);\n return CHUNK_LOAD_PATTERNS.some((pattern) => message.includes(pattern));\n}\n\n// ─── Staleness ───────────────────────────────────────────────────\n\n/**\n * True once this client is known to be running against a superseded\n * deployment. One-way: a document that has gone stale cannot come back, since\n * the only way to get fresh code is to load a new document.\n *\n * In-memory on purpose. Persisting it would be wrong — the next document gets\n * whatever build the server hands it, and if that one is stale too it will\n * find out the same way.\n */\nlet stale = false;\n\n/**\n * True once {@link initStaleClient} has seen a deployment ID — i.e. this is a\n * production build. False in dev, where nothing is ever stale: HMR owns code\n * updates, and a failed dynamic import is a real error the developer needs to\n * see rather than something a page load fixes.\n */\nlet deployed = false;\n\n/** Whether this client has been superseded by a newer deployment. */\nexport function isClientStale(): boolean {\n return stale;\n}\n\n/**\n * Record that the origin has told us this client is stale — the `X-Timber-Reload`\n * header on an RSC or action response. Authoritative, so it is not gated on\n * anything: a dev server never sends the header in the first place.\n */\nexport function markClientStale(): void {\n stale = true;\n}\n\n/**\n * Record staleness if `error` is one of the shapes a superseded bundle\n * produces. Returns whether it did, so a caller mid-navigation can decide to\n * hard-navigate instead of surfacing the error.\n *\n * Inference, unlike {@link markClientStale}, so it is gated on being a\n * production build. This is the single place that gate lives — call sites\n * cannot see each other, and \"remember to gate the next one too\" is not a\n * guarantee.\n */\nexport function markStaleFromError(error: unknown): boolean {\n if (!deployed) return false;\n\n // A document being torn down aborts its in-flight dynamic imports, and an\n // aborted import reads exactly like a chunk the CDN has dropped. That is not\n // evidence of staleness, and the bit outlives the teardown that produced it:\n // a document entering the back-forward cache is frozen, not destroyed, so a\n // false positive recorded on the way out would cost the *restored* page its\n // client-side navigation for good. `unload-guard.ts` clears its own flag on\n // a persisted `pageshow`; this one is one-way by design, so it has to not be\n // set in the first place.\n if (isPageUnloading()) return false;\n\n if (!isStaleClientReference(error) && !isChunkLoadError(error)) return false;\n stale = true;\n return true;\n}\n\n// ─── Initialization ──────────────────────────────────────────────\n\n/**\n * The underlying error Vite attaches to a `vite:preloadError` event.\n *\n * Narrowed at runtime rather than cast: the property is Vite's, not ours, and\n * a shape change should fall back to matching the event itself rather than\n * silently reading `undefined` forever.\n */\nfunction preloadErrorPayload(event: Event): unknown {\n return 'payload' in event ? (event as Event & { payload: unknown }).payload : event;\n}\n\n/**\n * Arm the module, and register the listeners that catch stale-client errors\n * never passing through the router: a lazily imported client component, a\n * preloaded stylesheet, anything that rejects outside a navigation.\n *\n * No-op when `deploymentId` is null — that is dev. Called from the browser\n * entry before hydration, so it precedes any render or navigation that could\n * throw.\n */\nexport function initStaleClient(deploymentId: string | null): void {\n if (!deploymentId) return;\n deployed = true;\n\n // Vite dispatches this for failed chunk/CSS preloads. Note what is *not*\n // here: `preventDefault()`. Recording staleness is not recovering from this\n // error — the page is still broken until the user navigates — so Vite must\n // go on rethrowing it rather than have it silently swallowed.\n window.addEventListener('vite:preloadError', (event) => {\n markStaleFromError(preloadErrorPayload(event));\n });\n\n window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => {\n markStaleFromError(event.reason);\n });\n}\n","'use client';\n\n/**\n * Framework-injected React error boundary.\n *\n * Catches errors thrown by children and renders a fallback component\n * with the appropriate props based on error type:\n * - DenySignal (4xx) → { status, dangerouslyPassData }\n * - RenderError (5xx) → { error, digest, reset }\n * - Unhandled error → { error, digest: null, reset }\n *\n * The `status` prop controls which errors this boundary catches:\n * - Specific code (e.g. 403) → only that status\n * - Category (400) → any 4xx\n * - Category (500) → any 5xx\n * - Omitted → catches everything (error.tsx behavior)\n *\n * See design/10-error-handling.md §\"Status-Code Files\"\n */\n\nimport { Component, createElement, type ReactNode } from 'react';\nimport { getSsrData } from './ssr-data.js';\nimport { getRouterOrNull } from './router-ref.js';\nimport { markStaleFromError } from './stale-client.js';\n// Page unload detection: when the page is being torn down, error boundaries\n// suppress activation — the error is from the aborted connection, not the\n// application. unload-guard.ts is the single owner of that state; this module\n// used to keep its own copy, which drifted (TIM-1260).\nimport { isPageUnloading } from './unload-guard.js';\n\n// ─── Digest Types ────────────────────────────────────────────────────────────\n\n/** Structured digest returned by RSC onError for DenySignal. */\ninterface DenyDigest {\n type: 'deny';\n status: number;\n data: unknown;\n /**\n * Segment key of the segment that owns the matched deny page, present when\n * an in-tree catch site matched a file it may not render at its own\n * position and re-threw to reach the owner. See TIM-1356.\n */\n ownerKey?: string;\n}\n\n/** Structured digest returned by RSC onError for RenderError. */\ninterface RenderErrorDigest {\n type: 'render-error';\n code: string;\n data: unknown;\n status: number;\n}\n\n/** Structured digest returned by RSC onError for RedirectSignal. */\ninterface RedirectDigest {\n type: 'redirect';\n location: string;\n status: number;\n}\n\ntype ParsedDigest = DenyDigest | RenderErrorDigest | RedirectDigest;\n\n// ─── Props & State ───────────────────────────────────────────────────────────\n\nexport interface TimberErrorBoundaryProps {\n /** The component to render when an error is caught. */\n fallbackComponent?: (...args: unknown[]) => ReactNode;\n /**\n * Pre-rendered fallback element. Used for MDX status files which are server\n * components and cannot be passed as function props across the RSC→client\n * boundary. When set, rendered directly instead of calling fallbackComponent.\n *\n * See design/10-error-handling.md §\"Status-Code File Variants\" — MDX status\n * files are server components by default (zero client JS).\n */\n fallbackElement?: ReactNode;\n /**\n * Status code filter. If set, only catches errors matching this status.\n * 400 = any 4xx, 500 = any 5xx, specific number = exact match.\n */\n status?: number;\n /**\n * When true, this boundary wraps a parallel slot. Slot denials are\n * graceful degradation — they must NOT change the HTTP status code.\n */\n isSlotBoundary?: boolean;\n /**\n * Segment key of the segment that declared this boundary. Only meaningful\n * against a deny digest carrying an `ownerKey`. See the decline rule in\n * `render()` and TIM-1356.\n */\n segmentKey?: string;\n children: ReactNode;\n}\n\ninterface TimberErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n// Module-level guard: the first boundary to catch a given redirect digest\n// schedules the navigation and marks it handled here. Subsequent renders\n// (React retries the error-boundary render path multiple times in dev, and\n// outer boundaries that also see the error) become no-ops, preventing\n// duplicate router.navigate() calls.\nconst _handledRedirects = new WeakSet<object>();\n\n// Companion guard keyed by location: client-render redirect() (the\n// next/navigation shim) throws a FRESH error instance on every render\n// attempt, and React replays the errored render — so the WeakSet alone\n// would schedule the navigation twice. While a navigation to a location\n// is pending, further redirect errors for the same location are no-ops.\nlet _pendingRedirectLocation: string | null = null;\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport class TimberErrorBoundary extends Component<\n TimberErrorBoundaryProps,\n TimberErrorBoundaryState\n> {\n constructor(props: TimberErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): TimberErrorBoundaryState {\n // Suppress error boundaries during page unload (refresh/navigate away).\n // The aborted connection causes React's streaming hydration to error,\n // but the page is about to be replaced — showing an error boundary\n // would be a jarring flash for the user.\n if (isPageUnloading()) {\n return { hasError: false, error: null };\n }\n\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error): void {\n // A stale bundle most often surfaces here rather than as a rejected\n // navigation: a client reference missing from this build's manifest, or\n // a lazily-imported chunk the CDN no longer has, thrown during render.\n //\n // Recording it is all that happens — this boundary still renders its\n // fallback, and the recovery is the user's next navigation, which the\n // router turns into a full document load. Reloading from here would be a\n // page load the user did not ask for, on a page that may be mid-rollout\n // and would come back just as stale (TIM-1275).\n markStaleFromError(error);\n }\n\n componentDidUpdate(prevProps: TimberErrorBoundaryProps): void {\n // Reset error state when children change (e.g. client-side navigation).\n // Without this, navigating from one error page to another keeps the\n // stale error — getDerivedStateFromError doesn't re-fire for new children.\n if (this.state.hasError && prevProps.children !== this.props.children) {\n this.setState({ hasError: false, error: null });\n }\n }\n\n /** Reset the error state so children re-render. */\n private reset = () => {\n this.setState({ hasError: false, error: null });\n };\n\n render(): ReactNode {\n if (!this.state.hasError || !this.state.error) {\n return this.props.children;\n }\n\n const error = this.state.error;\n const parsed = parseDigest(error);\n\n // RedirectSignal handling splits by environment:\n //\n // - SSR (no window): re-throw so the Fizz shell fails and the server\n // pipeline catch block can produce a proper HTTP 3xx response. See\n // design/04-authorization.md.\n //\n // - Client (window exists): a RedirectSignal that leaked into the RSC\n // Flight payload during client navigation would otherwise bubble past\n // every error boundary to `window.onerror`, which in dev triggers the\n // Vite error overlay (false positive — navigation itself works).\n // Instead, ask the router to perform an SPA navigation to the target\n // and render nothing while it takes over. The router's own catch path\n // handles cross-origin / hard navigations. See TIM-838.\n if (parsed?.type === 'redirect') {\n if (typeof window === 'undefined') {\n throw error;\n }\n // Dedupe: React may render the error-boundary fallback path more\n // than once for a single caught error (dev-mode double render, and\n // additional boundaries above us in the tree). Only schedule the\n // navigation on the first render that sees this error instance.\n const alreadyHandled =\n _handledRedirects.has(error) || _pendingRedirectLocation === parsed.location;\n if (!alreadyHandled) {\n _handledRedirects.add(error);\n const router = getRouterOrNull();\n if (router) {\n _pendingRedirectLocation = parsed.location;\n // Schedule the navigation outside the render phase to avoid\n // setState-during-render warnings from router state updates.\n queueMicrotask(() => {\n router\n .navigate(parsed.location, { replace: true })\n .catch(() => {\n // Fall back to a hard navigation if the soft navigation fails.\n window.location.href = parsed.location;\n })\n .finally(() => {\n _pendingRedirectLocation = null;\n });\n });\n } else {\n // No router available (shouldn't happen post-bootstrap) — fall\n // back to a hard navigation so the user still ends up at the\n // target.\n window.location.href = parsed.location;\n }\n }\n return null;\n }\n\n // Owner-addressed denies: an in-tree catch site already resolved the\n // fallback chain and matched a file it may not render at its own\n // position, so it re-threw to reach the segment that owns that file.\n // Every boundary but that one declines — otherwise the nearest boundary\n // whose status filter happens to match catches first and renders the\n // deny page at its own depth, wrapped in the layouts the hoist existed\n // to skip, and from a different file than the chain chose. (Boundary\n // nesting is per-segment `{status} → category → error`; the 4xx chain\n // runs status files across ALL segments before any error.tsx, so a\n // leaf error.tsx would otherwise beat a root 404.tsx.)\n //\n // Declining is the default: an unkeyed boundary — a slot boundary, or\n // one from a construction site that builds no deny chains — never\n // claims a deny addressed to a segment. See TIM-1356.\n // `typeof === 'string'`, not a null check: the digest is untrusted JSON —\n // `parseDigest` validates only `type`, and any component can set\n // `error.digest` itself. A non-string `ownerKey` is unequal to every\n // boundary's key, so a truthiness test would let one error decline its\n // way past the entire tree and blank the page, where it would otherwise\n // have hit the nearest matching boundary.\n if (\n parsed?.type === 'deny' &&\n typeof parsed.ownerKey === 'string' &&\n parsed.ownerKey !== this.props.segmentKey\n ) {\n throw error;\n }\n\n // If this boundary has a status filter, check whether the error matches.\n // Non-matching errors re-throw so an outer boundary can catch them.\n if (this.props.status != null) {\n const errorStatus = getErrorStatus(parsed, error);\n if (errorStatus == null || !statusMatches(this.props.status, errorStatus)) {\n // Re-throw: this boundary doesn't handle this error.\n throw error;\n }\n }\n\n // Report DenySignal handling so the pipeline skips the redundant\n // renderDenyPage() re-render — but ONLY when this boundary can fully\n // handle the deny in-tree:\n //\n // ✅ TSX boundaries (fallbackComponent) — can receive runtime props\n // (status, dangerouslyPassData) dynamically in render()\n // ❌ MDX boundaries (fallbackElement) — pre-rendered at tree-build time,\n // cannot receive runtime deny props. Must fall through to re-render.\n //\n // For qualifying segment boundaries: also set the HTTP status code from\n // the DenySignal so the Response has the correct 4xx status. This runs\n // synchronously during Fizz rendering, BEFORE onShellReady.\n //\n // For slot boundaries: set _denyHandledByBoundary but do NOT change\n // statusCode — slot denials are graceful degradation.\n //\n // See TIM-664, LOCAL-298.\n if (parsed?.type === 'deny') {\n const canHandleInTree = this.props.fallbackElement == null;\n\n if (canHandleInTree || this.props.isSlotBoundary) {\n const ssrData = getSsrData();\n if (ssrData?._navContext) {\n ssrData._navContext._denyHandledByBoundary = true;\n if (!this.props.isSlotBoundary) {\n ssrData._navContext.statusCode = parsed.status;\n }\n }\n }\n }\n\n // Pre-rendered fallback element (MDX status files) — render directly.\n // MDX components are server components that cannot be passed as function\n // props across the RSC→client boundary. Instead, they are pre-rendered\n // as elements in the RSC environment and passed here as fallbackElement.\n if (this.props.fallbackElement != null) {\n return this.props.fallbackElement;\n }\n\n // Render the fallback component with the right props shape.\n if (parsed?.type === 'deny') {\n // Status-code file boundaries (404.tsx, 4xx.tsx, …) get the documented\n // 4xx props. error.tsx boundaries (no status filter) get their\n // documented { error, digest, reset } contract — plus the deny extras\n // for dual-shape implementations. Without the error prop, an error.tsx\n // reading error.message crashes on deny fall-through. See TIM-1081.\n if (this.props.status != null) {\n return createElement(this.props.fallbackComponent as never, {\n status: parsed.status,\n dangerouslyPassData: parsed.data,\n });\n }\n return createElement(this.props.fallbackComponent as never, {\n error: denyError(parsed.status, error),\n digest: null,\n reset: this.reset,\n status: parsed.status,\n dangerouslyPassData: parsed.data,\n });\n }\n\n // 5xx / RenderError / unhandled error\n const digest =\n parsed?.type === 'render-error' ? { code: parsed.code, data: parsed.data } : null;\n\n return createElement(this.props.fallbackComponent as never, {\n error,\n digest,\n reset: this.reset,\n });\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Parse the structured digest from the error.\n * React sets `error.digest` from the string returned by RSC's onError.\n */\nfunction parseDigest(error: Error): ParsedDigest | null {\n const raw = (error as { digest?: string }).digest;\n if (typeof raw !== 'string') return null;\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && typeof parsed.type === 'string') {\n return parsed as ParsedDigest;\n }\n } catch (e) {\n console.debug('[timber] error digest is not valid JSON:', e instanceof Error ? e.message : e);\n }\n return null;\n}\n\n/**\n * The Error an `error.tsx` serving a deny should receive.\n *\n * The error that actually arrives here is React's, not the framework's: a\n * server-thrown error crossing Flight has its message and name replaced with\n * a generic redacted string in production, by design. An `error.tsx` written\n * per the docs branches on `error.message` — so handing it the redacted error\n * gives it nothing to branch on, while the in-tree path hands the same file a\n * `DenySignal` named error reading `Access denied with status <N>` (see\n * `renderDenyEntry`). This reconstructs that shape from the digest, which is\n * where the status already is.\n *\n * Derived from the status alone — no stack, no server data — so it is safe on\n * the client for the same reason the digest is. See design/13-security.md\n * §\"Errors don't leak\", TIM-1081.\n */\nfunction denyError(status: number, original: Error): Error {\n // A dev build may have preserved something more useful than the redaction.\n if (original.name === 'DenySignal') return original;\n const error = new Error(`Access denied with status ${status}`);\n error.name = 'DenySignal';\n return error;\n}\n\n/**\n * Extract the HTTP status code from a parsed digest or error message.\n * Falls back to message pattern matching for errors without a digest.\n */\nfunction getErrorStatus(parsed: ParsedDigest | null, error: Error): number | null {\n if (parsed?.type === 'deny') return parsed.status;\n if (parsed?.type === 'render-error') return parsed.status;\n if (parsed?.type === 'redirect') return parsed.status;\n\n // Fallback: parse DenySignal message pattern for errors that lost their digest\n const match = error.message.match(/^Access denied with status (\\d+)$/);\n if (match) return parseInt(match[1], 10);\n\n // Unhandled errors are implicitly 500\n return 500;\n}\n\n/**\n * Check whether an error's status matches the boundary's status filter.\n * Category markers (400, 500) match any status in that range.\n */\nfunction statusMatches(boundaryStatus: number, errorStatus: number): boolean {\n // Category catch-all: 400 matches any 4xx, 500 matches any 5xx\n if (boundaryStatus === 400) return errorStatus >= 400 && errorStatus <= 499;\n if (boundaryStatus === 500) return errorStatus >= 500 && errorStatus <= 599;\n // Exact match\n return boundaryStatus === errorStatus;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"error-boundary-D-ODYX41.js","names":[],"sources":["../../src/client/unload-guard.ts","../../src/client/stale-client.ts","../../src/client/error-boundary.tsx"],"sourcesContent":["/**\n * Page unload detection — suppresses spurious errors during page refresh/navigation.\n *\n * When the user refreshes the page or navigates away while React is still\n * streaming Suspense content, the aborted connection causes streaming errors.\n * These are not application errors — they're a side effect of the browser\n * tearing down the connection. This module tracks whether the page is being\n * unloaded so error boundaries and error handlers can suppress abort-related\n * errors during the unload window.\n *\n * This is the single owner of \"is this document going away\". Anything that\n * needs the answer imports `isPageUnloading()` — an unload flag maintained a\n * second time somewhere else is a flag that will drift out of agreement with\n * this one (TIM-1260).\n *\n * Mutable state is delegated to client/state.ts for singleton guarantees.\n * See design/18-build-system.md §\"Singleton State Registry\"\n *\n * See design/10-error-handling.md §\"Known limitation: deny() inside Suspense and hydration\"\n */\n\nimport { unloading, _setUnloading } from './state.ts';\n\n/**\n * Departure is *committed*: `pagehide` has fired, or this document has called\n * reload() on itself. `beforeunload` alone doesn't qualify — it is\n * speculative, and the user can still cancel out of it.\n */\nlet committed = false;\n\nif (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n _setUnloading(true);\n\n // An app with an unsaved-changes prompt can have this cancelled. Nothing\n // fires to say so, so the only signal is that the page is still running\n // afterwards — and timers are blocked while the modal is up, so this task\n // cannot run until the user has chosen. If they left, `pagehide` has\n // already committed and this is a no-op.\n setTimeout(() => {\n if (!committed) _setUnloading(false);\n }, 0);\n });\n\n // pagehide is the committed-departure event, and fires for both navigations\n // and bfcache entry. Safari in particular may skip beforeunload entirely.\n window.addEventListener('pagehide', () => {\n committed = true;\n _setUnloading(true);\n });\n\n window.addEventListener('pageshow', (event) => {\n // A bfcache restore un-does the teardown `pagehide` announced: the same\n // document is alive again, with this module's state intact. Without the\n // reset, every consumer would go on suppressing errors on a live page.\n if (event.persisted) {\n committed = false;\n _setUnloading(false);\n }\n });\n}\n\n/**\n * Returns true if the page is currently being unloaded (user refreshed\n * or navigated away). Error boundaries should suppress errors in this state.\n */\nexport function isPageUnloading(): boolean {\n return unloading;\n}\n","/**\n * Stale Client — knowing when this bundle has been superseded.\n *\n * Layer 1 of version skew handling (see design/33-version-skew.md) is\n * proactive: the server compares `X-Timber-Deployment-Id` against the current\n * build and answers a stale client with `X-Timber-Reload: 1`. That covers\n * every RSC navigation and every server action — as long as there is a server\n * in the request path.\n *\n * This module is the reactive half, plus the state both halves feed. It\n * recognizes the two error shapes a stale client produces on its own:\n *\n * 1. **Stale client references** — React's Flight client throws\n * \"Could not find the module …\" when an RSC payload names a client module\n * ID that isn't in this bundle's manifest.\n * 2. **Chunk load failures** — a content-hashed chunk that no longer exists on\n * the CDN fails to `import()`. Every engine words this differently.\n *\n * It matters most for `output: 'static'`, where there is no server to send the\n * reload header and this is the *only* skew detection that can run.\n *\n * **Nothing here reloads the page.** A stale client is recorded, not acted on;\n * the router turns the next user-initiated navigation into a full document\n * load. See design/33-version-skew.md §\"Recovery on the next navigation\" for\n * why — a self-issued `location.reload()` cannot tell a recovery from a bounce\n * between two live deployments, and mid-rollout it produces exactly that loop.\n *\n * See TIM-1260, TIM-1275.\n */\n\n// The only import: the shared unload state. Kept minimal because this module\n// is reached from the error boundary, a `'use client'` component evaluated in\n// the SSR graph too — a dependency on the client fetch layer would drag that\n// graph along with it.\nimport { isPageUnloading } from './unload-guard.ts';\n\n// ─── Error Shapes ────────────────────────────────────────────────\n\n/**\n * Substrings that identify a failed dynamic import, lowercased for\n * case-insensitive matching. Engines and bundlers each word this\n * differently and none of them expose a stable error code.\n */\nconst CHUNK_LOAD_PATTERNS = [\n // Chromium\n 'failed to fetch dynamically imported module',\n // Firefox\n 'error loading dynamically imported module',\n // Safari\n 'importing a module script failed',\n // Vite's preload helper, for the stylesheet of a lazily-imported chunk\n 'unable to preload css for',\n];\n\n/** Substring React's Flight client uses when a client module ID is unknown. */\nconst STALE_REFERENCE_PATTERN = 'could not find the module';\n\n/**\n * Pull a comparable message out of an unknown thrown value. Rejections cross\n * enough boundaries (event handlers, `unhandledrejection`, Vite's preload\n * event) that the value is not reliably an `Error`.\n */\nfunction messageOf(error: unknown): string {\n if (typeof error === 'string') return error.toLowerCase();\n if (error instanceof Error) return error.message.toLowerCase();\n if (error && typeof error === 'object' && 'message' in error) {\n const message = (error as { message: unknown }).message;\n if (typeof message === 'string') return message.toLowerCase();\n }\n return '';\n}\n\n/**\n * True when the error is React's \"client reference not in this manifest\"\n * failure — the payload was produced by a build this bundle doesn't match.\n */\nexport function isStaleClientReference(error: unknown): boolean {\n return messageOf(error).includes(STALE_REFERENCE_PATTERN);\n}\n\n/**\n * True when the error is a failed dynamic import or CSS preload — the\n * content-hashed chunk this bundle asks for is gone from the CDN.\n */\nexport function isChunkLoadError(error: unknown): boolean {\n if (error instanceof Error && error.name === 'ChunkLoadError') return true;\n const message = messageOf(error);\n return CHUNK_LOAD_PATTERNS.some((pattern) => message.includes(pattern));\n}\n\n// ─── Staleness ───────────────────────────────────────────────────\n\n/**\n * True once this client is known to be running against a superseded\n * deployment. One-way: a document that has gone stale cannot come back, since\n * the only way to get fresh code is to load a new document.\n *\n * In-memory on purpose. Persisting it would be wrong — the next document gets\n * whatever build the server hands it, and if that one is stale too it will\n * find out the same way.\n */\nlet stale = false;\n\n/**\n * True once {@link initStaleClient} has seen a deployment ID — i.e. this is a\n * production build. False in dev, where nothing is ever stale: HMR owns code\n * updates, and a failed dynamic import is a real error the developer needs to\n * see rather than something a page load fixes.\n */\nlet deployed = false;\n\n/** Whether this client has been superseded by a newer deployment. */\nexport function isClientStale(): boolean {\n return stale;\n}\n\n/**\n * Record that the origin has told us this client is stale — the `X-Timber-Reload`\n * header on an RSC or action response. Authoritative, so it is not gated on\n * anything: a dev server never sends the header in the first place.\n */\nexport function markClientStale(): void {\n stale = true;\n}\n\n/**\n * Record staleness if `error` is one of the shapes a superseded bundle\n * produces. Returns whether it did, so a caller mid-navigation can decide to\n * hard-navigate instead of surfacing the error.\n *\n * Inference, unlike {@link markClientStale}, so it is gated on being a\n * production build. This is the single place that gate lives — call sites\n * cannot see each other, and \"remember to gate the next one too\" is not a\n * guarantee.\n */\nexport function markStaleFromError(error: unknown): boolean {\n if (!deployed) return false;\n\n // A document being torn down aborts its in-flight dynamic imports, and an\n // aborted import reads exactly like a chunk the CDN has dropped. That is not\n // evidence of staleness, and the bit outlives the teardown that produced it:\n // a document entering the back-forward cache is frozen, not destroyed, so a\n // false positive recorded on the way out would cost the *restored* page its\n // client-side navigation for good. `unload-guard.ts` clears its own flag on\n // a persisted `pageshow`; this one is one-way by design, so it has to not be\n // set in the first place.\n if (isPageUnloading()) return false;\n\n if (!isStaleClientReference(error) && !isChunkLoadError(error)) return false;\n stale = true;\n return true;\n}\n\n// ─── Initialization ──────────────────────────────────────────────\n\n/**\n * The underlying error Vite attaches to a `vite:preloadError` event.\n *\n * Narrowed at runtime rather than cast: the property is Vite's, not ours, and\n * a shape change should fall back to matching the event itself rather than\n * silently reading `undefined` forever.\n */\nfunction preloadErrorPayload(event: Event): unknown {\n return 'payload' in event ? (event as Event & { payload: unknown }).payload : event;\n}\n\n/**\n * Arm the module, and register the listeners that catch stale-client errors\n * never passing through the router: a lazily imported client component, a\n * preloaded stylesheet, anything that rejects outside a navigation.\n *\n * No-op when `deploymentId` is null — that is dev. Called from the browser\n * entry before hydration, so it precedes any render or navigation that could\n * throw.\n */\nexport function initStaleClient(deploymentId: string | null): void {\n if (!deploymentId) return;\n deployed = true;\n\n // Vite dispatches this for failed chunk/CSS preloads. Note what is *not*\n // here: `preventDefault()`. Recording staleness is not recovering from this\n // error — the page is still broken until the user navigates — so Vite must\n // go on rethrowing it rather than have it silently swallowed.\n window.addEventListener('vite:preloadError', (event) => {\n markStaleFromError(preloadErrorPayload(event));\n });\n\n window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => {\n markStaleFromError(event.reason);\n });\n}\n","'use client';\n\n/**\n * Framework-injected React error boundary.\n *\n * Catches errors thrown by children and renders a fallback component\n * with the appropriate props based on error type:\n * - DenySignal (4xx) → { status, dangerouslyPassData }\n * - RenderError (5xx) → { error, digest, reset }\n * - Unhandled error → { error, digest: null, reset }\n *\n * The `status` prop controls which errors this boundary catches:\n * - Specific code (e.g. 403) → only that status\n * - Category (400) → any 4xx\n * - Category (500) → any 5xx\n * - Omitted → catches everything (error.tsx behavior)\n *\n * See design/10-error-handling.md §\"Status-Code Files\"\n */\n\nimport { Component, createElement, type ReactNode } from 'react';\nimport { getSsrData } from './ssr-data.ts';\nimport { getRouterOrNull } from './router-ref.ts';\nimport { markStaleFromError } from './stale-client.ts';\n// Page unload detection: when the page is being torn down, error boundaries\n// suppress activation — the error is from the aborted connection, not the\n// application. unload-guard.ts is the single owner of that state; this module\n// used to keep its own copy, which drifted (TIM-1260).\nimport { isPageUnloading } from './unload-guard.ts';\n\n// ─── Digest Types ────────────────────────────────────────────────────────────\n\n/** Structured digest returned by RSC onError for DenySignal. */\ninterface DenyDigest {\n type: 'deny';\n status: number;\n data: unknown;\n /**\n * Segment key of the segment that owns the matched deny page, present when\n * an in-tree catch site matched a file it may not render at its own\n * position and re-threw to reach the owner. See TIM-1356.\n */\n ownerKey?: string;\n}\n\n/** Structured digest returned by RSC onError for RenderError. */\ninterface RenderErrorDigest {\n type: 'render-error';\n code: string;\n data: unknown;\n status: number;\n}\n\n/** Structured digest returned by RSC onError for RedirectSignal. */\ninterface RedirectDigest {\n type: 'redirect';\n location: string;\n status: number;\n}\n\ntype ParsedDigest = DenyDigest | RenderErrorDigest | RedirectDigest;\n\n// ─── Props & State ───────────────────────────────────────────────────────────\n\nexport interface TimberErrorBoundaryProps {\n /** The component to render when an error is caught. */\n fallbackComponent?: (...args: unknown[]) => ReactNode;\n /**\n * Pre-rendered fallback element. Used for MDX status files which are server\n * components and cannot be passed as function props across the RSC→client\n * boundary. When set, rendered directly instead of calling fallbackComponent.\n *\n * See design/10-error-handling.md §\"Status-Code File Variants\" — MDX status\n * files are server components by default (zero client JS).\n */\n fallbackElement?: ReactNode;\n /**\n * Status code filter. If set, only catches errors matching this status.\n * 400 = any 4xx, 500 = any 5xx, specific number = exact match.\n */\n status?: number;\n /**\n * When true, this boundary wraps a parallel slot. Slot denials are\n * graceful degradation — they must NOT change the HTTP status code.\n */\n isSlotBoundary?: boolean;\n /**\n * Segment key of the segment that declared this boundary. Only meaningful\n * against a deny digest carrying an `ownerKey`. See the decline rule in\n * `render()` and TIM-1356.\n */\n segmentKey?: string;\n children: ReactNode;\n}\n\ninterface TimberErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n// Module-level guard: the first boundary to catch a given redirect digest\n// schedules the navigation and marks it handled here. Subsequent renders\n// (React retries the error-boundary render path multiple times in dev, and\n// outer boundaries that also see the error) become no-ops, preventing\n// duplicate router.navigate() calls.\nconst _handledRedirects = new WeakSet<object>();\n\n// Companion guard keyed by location: client-render redirect() (the\n// next/navigation shim) throws a FRESH error instance on every render\n// attempt, and React replays the errored render — so the WeakSet alone\n// would schedule the navigation twice. While a navigation to a location\n// is pending, further redirect errors for the same location are no-ops.\nlet _pendingRedirectLocation: string | null = null;\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport class TimberErrorBoundary extends Component<\n TimberErrorBoundaryProps,\n TimberErrorBoundaryState\n> {\n constructor(props: TimberErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): TimberErrorBoundaryState {\n // Suppress error boundaries during page unload (refresh/navigate away).\n // The aborted connection causes React's streaming hydration to error,\n // but the page is about to be replaced — showing an error boundary\n // would be a jarring flash for the user.\n if (isPageUnloading()) {\n return { hasError: false, error: null };\n }\n\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error): void {\n // A stale bundle most often surfaces here rather than as a rejected\n // navigation: a client reference missing from this build's manifest, or\n // a lazily-imported chunk the CDN no longer has, thrown during render.\n //\n // Recording it is all that happens — this boundary still renders its\n // fallback, and the recovery is the user's next navigation, which the\n // router turns into a full document load. Reloading from here would be a\n // page load the user did not ask for, on a page that may be mid-rollout\n // and would come back just as stale (TIM-1275).\n markStaleFromError(error);\n }\n\n componentDidUpdate(prevProps: TimberErrorBoundaryProps): void {\n // Reset error state when children change (e.g. client-side navigation).\n // Without this, navigating from one error page to another keeps the\n // stale error — getDerivedStateFromError doesn't re-fire for new children.\n if (this.state.hasError && prevProps.children !== this.props.children) {\n this.setState({ hasError: false, error: null });\n }\n }\n\n /** Reset the error state so children re-render. */\n private reset = () => {\n this.setState({ hasError: false, error: null });\n };\n\n render(): ReactNode {\n if (!this.state.hasError || !this.state.error) {\n return this.props.children;\n }\n\n const error = this.state.error;\n const parsed = parseDigest(error);\n\n // RedirectSignal handling splits by environment:\n //\n // - SSR (no window): re-throw so the Fizz shell fails and the server\n // pipeline catch block can produce a proper HTTP 3xx response. See\n // design/04-authorization.md.\n //\n // - Client (window exists): a RedirectSignal that leaked into the RSC\n // Flight payload during client navigation would otherwise bubble past\n // every error boundary to `window.onerror`, which in dev triggers the\n // Vite error overlay (false positive — navigation itself works).\n // Instead, ask the router to perform an SPA navigation to the target\n // and render nothing while it takes over. The router's own catch path\n // handles cross-origin / hard navigations. See TIM-838.\n if (parsed?.type === 'redirect') {\n if (typeof window === 'undefined') {\n throw error;\n }\n // Dedupe: React may render the error-boundary fallback path more\n // than once for a single caught error (dev-mode double render, and\n // additional boundaries above us in the tree). Only schedule the\n // navigation on the first render that sees this error instance.\n const alreadyHandled =\n _handledRedirects.has(error) || _pendingRedirectLocation === parsed.location;\n if (!alreadyHandled) {\n _handledRedirects.add(error);\n const router = getRouterOrNull();\n if (router) {\n _pendingRedirectLocation = parsed.location;\n // Schedule the navigation outside the render phase to avoid\n // setState-during-render warnings from router state updates.\n queueMicrotask(() => {\n router\n .navigate(parsed.location, { replace: true })\n .catch(() => {\n // Fall back to a hard navigation if the soft navigation fails.\n window.location.href = parsed.location;\n })\n .finally(() => {\n _pendingRedirectLocation = null;\n });\n });\n } else {\n // No router available (shouldn't happen post-bootstrap) — fall\n // back to a hard navigation so the user still ends up at the\n // target.\n window.location.href = parsed.location;\n }\n }\n return null;\n }\n\n // Owner-addressed denies: an in-tree catch site already resolved the\n // fallback chain and matched a file it may not render at its own\n // position, so it re-threw to reach the segment that owns that file.\n // Every boundary but that one declines — otherwise the nearest boundary\n // whose status filter happens to match catches first and renders the\n // deny page at its own depth, wrapped in the layouts the hoist existed\n // to skip, and from a different file than the chain chose. (Boundary\n // nesting is per-segment `{status} → category → error`; the 4xx chain\n // runs status files across ALL segments before any error.tsx, so a\n // leaf error.tsx would otherwise beat a root 404.tsx.)\n //\n // Declining is the default: an unkeyed boundary — a slot boundary, or\n // one from a construction site that builds no deny chains — never\n // claims a deny addressed to a segment. See TIM-1356.\n // `typeof === 'string'`, not a null check: the digest is untrusted JSON —\n // `parseDigest` validates only `type`, and any component can set\n // `error.digest` itself. A non-string `ownerKey` is unequal to every\n // boundary's key, so a truthiness test would let one error decline its\n // way past the entire tree and blank the page, where it would otherwise\n // have hit the nearest matching boundary.\n if (\n parsed?.type === 'deny' &&\n typeof parsed.ownerKey === 'string' &&\n parsed.ownerKey !== this.props.segmentKey\n ) {\n throw error;\n }\n\n // If this boundary has a status filter, check whether the error matches.\n // Non-matching errors re-throw so an outer boundary can catch them.\n if (this.props.status != null) {\n const errorStatus = getErrorStatus(parsed, error);\n if (errorStatus == null || !statusMatches(this.props.status, errorStatus)) {\n // Re-throw: this boundary doesn't handle this error.\n throw error;\n }\n }\n\n // Report DenySignal handling so the pipeline skips the redundant\n // renderDenyPage() re-render — but ONLY when this boundary can fully\n // handle the deny in-tree:\n //\n // ✅ TSX boundaries (fallbackComponent) — can receive runtime props\n // (status, dangerouslyPassData) dynamically in render()\n // ❌ MDX boundaries (fallbackElement) — pre-rendered at tree-build time,\n // cannot receive runtime deny props. Must fall through to re-render.\n //\n // For qualifying segment boundaries: also set the HTTP status code from\n // the DenySignal so the Response has the correct 4xx status. This runs\n // synchronously during Fizz rendering, BEFORE onShellReady.\n //\n // For slot boundaries: set _denyHandledByBoundary but do NOT change\n // statusCode — slot denials are graceful degradation.\n //\n // See TIM-664, LOCAL-298.\n if (parsed?.type === 'deny') {\n const canHandleInTree = this.props.fallbackElement == null;\n\n if (canHandleInTree || this.props.isSlotBoundary) {\n const ssrData = getSsrData();\n if (ssrData?._navContext) {\n ssrData._navContext._denyHandledByBoundary = true;\n if (!this.props.isSlotBoundary) {\n ssrData._navContext.statusCode = parsed.status;\n }\n }\n }\n }\n\n // Pre-rendered fallback element (MDX status files) — render directly.\n // MDX components are server components that cannot be passed as function\n // props across the RSC→client boundary. Instead, they are pre-rendered\n // as elements in the RSC environment and passed here as fallbackElement.\n if (this.props.fallbackElement != null) {\n return this.props.fallbackElement;\n }\n\n // Render the fallback component with the right props shape.\n if (parsed?.type === 'deny') {\n // Status-code file boundaries (404.tsx, 4xx.tsx, …) get the documented\n // 4xx props. error.tsx boundaries (no status filter) get their\n // documented { error, digest, reset } contract — plus the deny extras\n // for dual-shape implementations. Without the error prop, an error.tsx\n // reading error.message crashes on deny fall-through. See TIM-1081.\n if (this.props.status != null) {\n return createElement(this.props.fallbackComponent as never, {\n status: parsed.status,\n dangerouslyPassData: parsed.data,\n });\n }\n return createElement(this.props.fallbackComponent as never, {\n error: denyError(parsed.status, error),\n digest: null,\n reset: this.reset,\n status: parsed.status,\n dangerouslyPassData: parsed.data,\n });\n }\n\n // 5xx / RenderError / unhandled error\n const digest =\n parsed?.type === 'render-error' ? { code: parsed.code, data: parsed.data } : null;\n\n return createElement(this.props.fallbackComponent as never, {\n error,\n digest,\n reset: this.reset,\n });\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Parse the structured digest from the error.\n * React sets `error.digest` from the string returned by RSC's onError.\n */\nfunction parseDigest(error: Error): ParsedDigest | null {\n const raw = (error as { digest?: string }).digest;\n if (typeof raw !== 'string') return null;\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && typeof parsed.type === 'string') {\n return parsed as ParsedDigest;\n }\n } catch (e) {\n console.debug('[timber] error digest is not valid JSON:', e instanceof Error ? e.message : e);\n }\n return null;\n}\n\n/**\n * The Error an `error.tsx` serving a deny should receive.\n *\n * The error that actually arrives here is React's, not the framework's: a\n * server-thrown error crossing Flight has its message and name replaced with\n * a generic redacted string in production, by design. An `error.tsx` written\n * per the docs branches on `error.message` — so handing it the redacted error\n * gives it nothing to branch on, while the in-tree path hands the same file a\n * `DenySignal` named error reading `Access denied with status <N>` (see\n * `renderDenyEntry`). This reconstructs that shape from the digest, which is\n * where the status already is.\n *\n * Derived from the status alone — no stack, no server data — so it is safe on\n * the client for the same reason the digest is. See design/13-security.md\n * §\"Errors don't leak\", TIM-1081.\n */\nfunction denyError(status: number, original: Error): Error {\n // A dev build may have preserved something more useful than the redaction.\n if (original.name === 'DenySignal') return original;\n const error = new Error(`Access denied with status ${status}`);\n error.name = 'DenySignal';\n return error;\n}\n\n/**\n * Extract the HTTP status code from a parsed digest or error message.\n * Falls back to message pattern matching for errors without a digest.\n */\nfunction getErrorStatus(parsed: ParsedDigest | null, error: Error): number | null {\n if (parsed?.type === 'deny') return parsed.status;\n if (parsed?.type === 'render-error') return parsed.status;\n if (parsed?.type === 'redirect') return parsed.status;\n\n // Fallback: parse DenySignal message pattern for errors that lost their digest\n const match = error.message.match(/^Access denied with status (\\d+)$/);\n if (match) return parseInt(match[1], 10);\n\n // Unhandled errors are implicitly 500\n return 500;\n}\n\n/**\n * Check whether an error's status matches the boundary's status filter.\n * Category markers (400, 500) match any status in that range.\n */\nfunction statusMatches(boundaryStatus: number, errorStatus: number): boolean {\n // Category catch-all: 400 matches any 4xx, 500 matches any 5xx\n if (boundaryStatus === 400) return errorStatus >= 400 && errorStatus <= 499;\n if (boundaryStatus === 500) return errorStatus >= 500 && errorStatus <= 599;\n // Exact match\n return boundaryStatus === errorStatus;\n}\n"],"mappings":"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"}
@@ -348,6 +348,10 @@ function formatDeclarationFile(routes, importBase, hasSchema, appDir) {
348
348
  lines.push("}");
349
349
  lines.push("");
350
350
  }
351
+ lines.push("type _IsAny<T> = 0 extends 1 & T ? true : false;");
352
+ lines.push("type _AssertSchemaNotAny<_T extends false = _IsAny<typeof schema>> = true;");
353
+ lines.push("type _AssertCodecTypeNotAny<_T extends false = _IsAny<SegmentParamCodec>> = true;");
354
+ lines.push("");
351
355
  lines.push("type _AssertSchemaValues = {");
352
356
  lines.push(" [K in keyof typeof schema['segmentParams']]: typeof schema['segmentParams'][K] extends SegmentParamCodec ? true : ['Error: value for', K, 'is not a valid Codec or Standard Schema'];");
353
357
  lines.push("};");
@@ -451,4 +455,4 @@ function readFileCached(filePath) {
451
455
  //#endregion
452
456
  export { generateRouteMap as n, readFileCached as t };
453
457
 
454
- //# sourceMappingURL=file-cache-DmX7OqZP.js.map
458
+ //# sourceMappingURL=file-cache-Dw6BJPG7.js.map