@benjavicente/router-core 1.168.9

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 (380) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/bin/intent.js +25 -0
  4. package/dist/cjs/Matches.cjs +17 -0
  5. package/dist/cjs/Matches.cjs.map +1 -0
  6. package/dist/cjs/Matches.d.cts +139 -0
  7. package/dist/cjs/RouterProvider.d.cts +27 -0
  8. package/dist/cjs/config.cjs +11 -0
  9. package/dist/cjs/config.cjs.map +1 -0
  10. package/dist/cjs/config.d.cts +17 -0
  11. package/dist/cjs/defer.cjs +41 -0
  12. package/dist/cjs/defer.cjs.map +1 -0
  13. package/dist/cjs/defer.d.cts +37 -0
  14. package/dist/cjs/fileRoute.d.cts +24 -0
  15. package/dist/cjs/global.d.cts +7 -0
  16. package/dist/cjs/hash-scroll.cjs +20 -0
  17. package/dist/cjs/hash-scroll.cjs.map +1 -0
  18. package/dist/cjs/hash-scroll.d.cts +7 -0
  19. package/dist/cjs/history.d.cts +8 -0
  20. package/dist/cjs/index.cjs +96 -0
  21. package/dist/cjs/index.d.cts +53 -0
  22. package/dist/cjs/invariant.cjs +8 -0
  23. package/dist/cjs/invariant.cjs.map +1 -0
  24. package/dist/cjs/invariant.d.cts +1 -0
  25. package/dist/cjs/isServer/client.cjs +7 -0
  26. package/dist/cjs/isServer/client.cjs.map +1 -0
  27. package/dist/cjs/isServer/client.d.cts +1 -0
  28. package/dist/cjs/isServer/development.cjs +7 -0
  29. package/dist/cjs/isServer/development.cjs.map +1 -0
  30. package/dist/cjs/isServer/development.d.cts +1 -0
  31. package/dist/cjs/isServer/server.cjs +7 -0
  32. package/dist/cjs/isServer/server.cjs.map +1 -0
  33. package/dist/cjs/isServer/server.d.cts +1 -0
  34. package/dist/cjs/link.cjs +6 -0
  35. package/dist/cjs/link.cjs.map +1 -0
  36. package/dist/cjs/link.d.cts +221 -0
  37. package/dist/cjs/load-matches.cjs +659 -0
  38. package/dist/cjs/load-matches.cjs.map +1 -0
  39. package/dist/cjs/load-matches.d.cts +18 -0
  40. package/dist/cjs/location.d.cts +50 -0
  41. package/dist/cjs/lru-cache.cjs +70 -0
  42. package/dist/cjs/lru-cache.cjs.map +1 -0
  43. package/dist/cjs/lru-cache.d.cts +6 -0
  44. package/dist/cjs/manifest.cjs +18 -0
  45. package/dist/cjs/manifest.cjs.map +1 -0
  46. package/dist/cjs/manifest.d.cts +35 -0
  47. package/dist/cjs/new-process-route-tree.cjs +754 -0
  48. package/dist/cjs/new-process-route-tree.cjs.map +1 -0
  49. package/dist/cjs/new-process-route-tree.d.cts +236 -0
  50. package/dist/cjs/not-found.cjs +26 -0
  51. package/dist/cjs/not-found.cjs.map +1 -0
  52. package/dist/cjs/not-found.d.cts +32 -0
  53. package/dist/cjs/path.cjs +252 -0
  54. package/dist/cjs/path.cjs.map +1 -0
  55. package/dist/cjs/path.d.cts +56 -0
  56. package/dist/cjs/qss.cjs +70 -0
  57. package/dist/cjs/qss.cjs.map +1 -0
  58. package/dist/cjs/qss.d.cts +33 -0
  59. package/dist/cjs/redirect.cjs +56 -0
  60. package/dist/cjs/redirect.cjs.map +1 -0
  61. package/dist/cjs/redirect.d.cts +77 -0
  62. package/dist/cjs/rewrite.cjs +68 -0
  63. package/dist/cjs/rewrite.cjs.map +1 -0
  64. package/dist/cjs/rewrite.d.cts +30 -0
  65. package/dist/cjs/root.cjs +7 -0
  66. package/dist/cjs/root.cjs.map +1 -0
  67. package/dist/cjs/root.d.cts +3 -0
  68. package/dist/cjs/route.cjs +100 -0
  69. package/dist/cjs/route.cjs.map +1 -0
  70. package/dist/cjs/route.d.cts +552 -0
  71. package/dist/cjs/routeInfo.d.cts +54 -0
  72. package/dist/cjs/router.cjs +1173 -0
  73. package/dist/cjs/router.cjs.map +1 -0
  74. package/dist/cjs/router.d.cts +734 -0
  75. package/dist/cjs/scroll-restoration-inline.cjs +6 -0
  76. package/dist/cjs/scroll-restoration-inline.cjs.map +1 -0
  77. package/dist/cjs/scroll-restoration-inline.d.cts +6 -0
  78. package/dist/cjs/scroll-restoration-script/client.cjs +9 -0
  79. package/dist/cjs/scroll-restoration-script/client.cjs.map +1 -0
  80. package/dist/cjs/scroll-restoration-script/client.d.cts +2 -0
  81. package/dist/cjs/scroll-restoration-script/server.cjs +30 -0
  82. package/dist/cjs/scroll-restoration-script/server.cjs.map +1 -0
  83. package/dist/cjs/scroll-restoration-script/server.d.cts +2 -0
  84. package/dist/cjs/scroll-restoration.cjs +191 -0
  85. package/dist/cjs/scroll-restoration.cjs.map +1 -0
  86. package/dist/cjs/scroll-restoration.d.cts +38 -0
  87. package/dist/cjs/searchMiddleware.cjs +55 -0
  88. package/dist/cjs/searchMiddleware.cjs.map +1 -0
  89. package/dist/cjs/searchMiddleware.d.cts +25 -0
  90. package/dist/cjs/searchParams.cjs +65 -0
  91. package/dist/cjs/searchParams.cjs.map +1 -0
  92. package/dist/cjs/searchParams.d.cts +31 -0
  93. package/dist/cjs/ssr/client.cjs +7 -0
  94. package/dist/cjs/ssr/client.d.cts +6 -0
  95. package/dist/cjs/ssr/constants.cjs +8 -0
  96. package/dist/cjs/ssr/constants.cjs.map +1 -0
  97. package/dist/cjs/ssr/constants.d.cts +3 -0
  98. package/dist/cjs/ssr/createRequestHandler.cjs +44 -0
  99. package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -0
  100. package/dist/cjs/ssr/createRequestHandler.d.cts +9 -0
  101. package/dist/cjs/ssr/handlerCallback.cjs +8 -0
  102. package/dist/cjs/ssr/handlerCallback.cjs.map +1 -0
  103. package/dist/cjs/ssr/handlerCallback.d.cts +9 -0
  104. package/dist/cjs/ssr/headers.cjs +21 -0
  105. package/dist/cjs/ssr/headers.cjs.map +1 -0
  106. package/dist/cjs/ssr/headers.d.cts +3 -0
  107. package/dist/cjs/ssr/json.cjs +11 -0
  108. package/dist/cjs/ssr/json.cjs.map +1 -0
  109. package/dist/cjs/ssr/json.d.cts +10 -0
  110. package/dist/cjs/ssr/serializer/RawStream.cjs +287 -0
  111. package/dist/cjs/ssr/serializer/RawStream.cjs.map +1 -0
  112. package/dist/cjs/ssr/serializer/RawStream.d.cts +64 -0
  113. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs +32 -0
  114. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -0
  115. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.d.cts +9 -0
  116. package/dist/cjs/ssr/serializer/seroval-plugins.cjs +13 -0
  117. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -0
  118. package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -0
  119. package/dist/cjs/ssr/serializer/transformer.cjs +53 -0
  120. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -0
  121. package/dist/cjs/ssr/serializer/transformer.d.cts +91 -0
  122. package/dist/cjs/ssr/server.cjs +13 -0
  123. package/dist/cjs/ssr/server.d.cts +6 -0
  124. package/dist/cjs/ssr/ssr-client.cjs +183 -0
  125. package/dist/cjs/ssr/ssr-client.cjs.map +1 -0
  126. package/dist/cjs/ssr/ssr-client.d.cts +10 -0
  127. package/dist/cjs/ssr/ssr-match-id.cjs +12 -0
  128. package/dist/cjs/ssr/ssr-match-id.cjs.map +1 -0
  129. package/dist/cjs/ssr/ssr-match-id.d.cts +2 -0
  130. package/dist/cjs/ssr/ssr-server.cjs +279 -0
  131. package/dist/cjs/ssr/ssr-server.cjs.map +1 -0
  132. package/dist/cjs/ssr/ssr-server.d.cts +42 -0
  133. package/dist/cjs/ssr/transformStreamWithRouter.cjs +327 -0
  134. package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -0
  135. package/dist/cjs/ssr/transformStreamWithRouter.d.cts +11 -0
  136. package/dist/cjs/ssr/tsrScript.cjs +6 -0
  137. package/dist/cjs/ssr/tsrScript.cjs.map +1 -0
  138. package/dist/cjs/ssr/tsrScript.d.cts +1 -0
  139. package/dist/cjs/ssr/types.d.cts +30 -0
  140. package/dist/cjs/stores.cjs +148 -0
  141. package/dist/cjs/stores.cjs.map +1 -0
  142. package/dist/cjs/stores.d.cts +70 -0
  143. package/dist/cjs/structuralSharing.d.cts +4 -0
  144. package/dist/cjs/typePrimitives.d.cts +65 -0
  145. package/dist/cjs/useLoaderData.d.cts +5 -0
  146. package/dist/cjs/useLoaderDeps.d.cts +5 -0
  147. package/dist/cjs/useNavigate.d.cts +3 -0
  148. package/dist/cjs/useParams.d.cts +5 -0
  149. package/dist/cjs/useRouteContext.d.cts +9 -0
  150. package/dist/cjs/useSearch.d.cts +5 -0
  151. package/dist/cjs/utils.cjs +339 -0
  152. package/dist/cjs/utils.cjs.map +1 -0
  153. package/dist/cjs/utils.d.cts +178 -0
  154. package/dist/cjs/validators.d.cts +51 -0
  155. package/dist/esm/Matches.d.ts +139 -0
  156. package/dist/esm/Matches.js +17 -0
  157. package/dist/esm/Matches.js.map +1 -0
  158. package/dist/esm/RouterProvider.d.ts +27 -0
  159. package/dist/esm/config.d.ts +17 -0
  160. package/dist/esm/config.js +11 -0
  161. package/dist/esm/config.js.map +1 -0
  162. package/dist/esm/defer.d.ts +37 -0
  163. package/dist/esm/defer.js +40 -0
  164. package/dist/esm/defer.js.map +1 -0
  165. package/dist/esm/fileRoute.d.ts +24 -0
  166. package/dist/esm/global.d.ts +7 -0
  167. package/dist/esm/hash-scroll.d.ts +7 -0
  168. package/dist/esm/hash-scroll.js +20 -0
  169. package/dist/esm/hash-scroll.js.map +1 -0
  170. package/dist/esm/history.d.ts +8 -0
  171. package/dist/esm/index.d.ts +53 -0
  172. package/dist/esm/index.js +24 -0
  173. package/dist/esm/invariant.d.ts +1 -0
  174. package/dist/esm/invariant.js +8 -0
  175. package/dist/esm/invariant.js.map +1 -0
  176. package/dist/esm/isServer/client.d.ts +1 -0
  177. package/dist/esm/isServer/client.js +6 -0
  178. package/dist/esm/isServer/client.js.map +1 -0
  179. package/dist/esm/isServer/development.d.ts +1 -0
  180. package/dist/esm/isServer/development.js +6 -0
  181. package/dist/esm/isServer/development.js.map +1 -0
  182. package/dist/esm/isServer/server.d.ts +1 -0
  183. package/dist/esm/isServer/server.js +6 -0
  184. package/dist/esm/isServer/server.js.map +1 -0
  185. package/dist/esm/link.d.ts +221 -0
  186. package/dist/esm/link.js +6 -0
  187. package/dist/esm/link.js.map +1 -0
  188. package/dist/esm/load-matches.d.ts +18 -0
  189. package/dist/esm/load-matches.js +657 -0
  190. package/dist/esm/load-matches.js.map +1 -0
  191. package/dist/esm/location.d.ts +50 -0
  192. package/dist/esm/lru-cache.d.ts +6 -0
  193. package/dist/esm/lru-cache.js +70 -0
  194. package/dist/esm/lru-cache.js.map +1 -0
  195. package/dist/esm/manifest.d.ts +35 -0
  196. package/dist/esm/manifest.js +17 -0
  197. package/dist/esm/manifest.js.map +1 -0
  198. package/dist/esm/new-process-route-tree.d.ts +236 -0
  199. package/dist/esm/new-process-route-tree.js +749 -0
  200. package/dist/esm/new-process-route-tree.js.map +1 -0
  201. package/dist/esm/not-found.d.ts +32 -0
  202. package/dist/esm/not-found.js +25 -0
  203. package/dist/esm/not-found.js.map +1 -0
  204. package/dist/esm/path.d.ts +56 -0
  205. package/dist/esm/path.js +243 -0
  206. package/dist/esm/path.js.map +1 -0
  207. package/dist/esm/qss.d.ts +33 -0
  208. package/dist/esm/qss.js +69 -0
  209. package/dist/esm/qss.js.map +1 -0
  210. package/dist/esm/redirect.d.ts +77 -0
  211. package/dist/esm/redirect.js +53 -0
  212. package/dist/esm/redirect.js.map +1 -0
  213. package/dist/esm/rewrite.d.ts +30 -0
  214. package/dist/esm/rewrite.js +65 -0
  215. package/dist/esm/rewrite.js.map +1 -0
  216. package/dist/esm/root.d.ts +3 -0
  217. package/dist/esm/root.js +7 -0
  218. package/dist/esm/root.js.map +1 -0
  219. package/dist/esm/route.d.ts +552 -0
  220. package/dist/esm/route.js +98 -0
  221. package/dist/esm/route.js.map +1 -0
  222. package/dist/esm/routeInfo.d.ts +54 -0
  223. package/dist/esm/router.d.ts +734 -0
  224. package/dist/esm/router.js +1165 -0
  225. package/dist/esm/router.js.map +1 -0
  226. package/dist/esm/scroll-restoration-inline.d.ts +6 -0
  227. package/dist/esm/scroll-restoration-inline.js +6 -0
  228. package/dist/esm/scroll-restoration-inline.js.map +1 -0
  229. package/dist/esm/scroll-restoration-script/client.d.ts +2 -0
  230. package/dist/esm/scroll-restoration-script/client.js +8 -0
  231. package/dist/esm/scroll-restoration-script/client.js.map +1 -0
  232. package/dist/esm/scroll-restoration-script/server.d.ts +2 -0
  233. package/dist/esm/scroll-restoration-script/server.js +29 -0
  234. package/dist/esm/scroll-restoration-script/server.js.map +1 -0
  235. package/dist/esm/scroll-restoration.d.ts +38 -0
  236. package/dist/esm/scroll-restoration.js +187 -0
  237. package/dist/esm/scroll-restoration.js.map +1 -0
  238. package/dist/esm/searchMiddleware.d.ts +25 -0
  239. package/dist/esm/searchMiddleware.js +54 -0
  240. package/dist/esm/searchMiddleware.js.map +1 -0
  241. package/dist/esm/searchParams.d.ts +31 -0
  242. package/dist/esm/searchParams.js +62 -0
  243. package/dist/esm/searchParams.js.map +1 -0
  244. package/dist/esm/ssr/client.d.ts +6 -0
  245. package/dist/esm/ssr/client.js +4 -0
  246. package/dist/esm/ssr/constants.d.ts +3 -0
  247. package/dist/esm/ssr/constants.js +7 -0
  248. package/dist/esm/ssr/constants.js.map +1 -0
  249. package/dist/esm/ssr/createRequestHandler.d.ts +9 -0
  250. package/dist/esm/ssr/createRequestHandler.js +44 -0
  251. package/dist/esm/ssr/createRequestHandler.js.map +1 -0
  252. package/dist/esm/ssr/handlerCallback.d.ts +9 -0
  253. package/dist/esm/ssr/handlerCallback.js +8 -0
  254. package/dist/esm/ssr/handlerCallback.js.map +1 -0
  255. package/dist/esm/ssr/headers.d.ts +3 -0
  256. package/dist/esm/ssr/headers.js +21 -0
  257. package/dist/esm/ssr/headers.js.map +1 -0
  258. package/dist/esm/ssr/json.d.ts +10 -0
  259. package/dist/esm/ssr/json.js +11 -0
  260. package/dist/esm/ssr/json.js.map +1 -0
  261. package/dist/esm/ssr/serializer/RawStream.d.ts +64 -0
  262. package/dist/esm/ssr/serializer/RawStream.js +282 -0
  263. package/dist/esm/ssr/serializer/RawStream.js.map +1 -0
  264. package/dist/esm/ssr/serializer/ShallowErrorPlugin.d.ts +9 -0
  265. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js +33 -0
  266. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -0
  267. package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -0
  268. package/dist/esm/ssr/serializer/seroval-plugins.js +13 -0
  269. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -0
  270. package/dist/esm/ssr/serializer/transformer.d.ts +91 -0
  271. package/dist/esm/ssr/serializer/transformer.js +51 -0
  272. package/dist/esm/ssr/serializer/transformer.js.map +1 -0
  273. package/dist/esm/ssr/server.d.ts +6 -0
  274. package/dist/esm/ssr/server.js +5 -0
  275. package/dist/esm/ssr/ssr-client.d.ts +10 -0
  276. package/dist/esm/ssr/ssr-client.js +183 -0
  277. package/dist/esm/ssr/ssr-client.js.map +1 -0
  278. package/dist/esm/ssr/ssr-match-id.d.ts +2 -0
  279. package/dist/esm/ssr/ssr-match-id.js +11 -0
  280. package/dist/esm/ssr/ssr-match-id.js.map +1 -0
  281. package/dist/esm/ssr/ssr-server.d.ts +42 -0
  282. package/dist/esm/ssr/ssr-server.js +277 -0
  283. package/dist/esm/ssr/ssr-server.js.map +1 -0
  284. package/dist/esm/ssr/transformStreamWithRouter.d.ts +11 -0
  285. package/dist/esm/ssr/transformStreamWithRouter.js +325 -0
  286. package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -0
  287. package/dist/esm/ssr/tsrScript.d.ts +0 -0
  288. package/dist/esm/ssr/tsrScript.js +6 -0
  289. package/dist/esm/ssr/tsrScript.js.map +1 -0
  290. package/dist/esm/ssr/types.d.ts +30 -0
  291. package/dist/esm/stores.d.ts +70 -0
  292. package/dist/esm/stores.js +146 -0
  293. package/dist/esm/stores.js.map +1 -0
  294. package/dist/esm/structuralSharing.d.ts +4 -0
  295. package/dist/esm/typePrimitives.d.ts +65 -0
  296. package/dist/esm/useLoaderData.d.ts +5 -0
  297. package/dist/esm/useLoaderDeps.d.ts +5 -0
  298. package/dist/esm/useNavigate.d.ts +3 -0
  299. package/dist/esm/useParams.d.ts +5 -0
  300. package/dist/esm/useRouteContext.d.ts +9 -0
  301. package/dist/esm/useSearch.d.ts +5 -0
  302. package/dist/esm/utils.d.ts +178 -0
  303. package/dist/esm/utils.js +322 -0
  304. package/dist/esm/utils.js.map +1 -0
  305. package/dist/esm/validators.d.ts +51 -0
  306. package/package.json +200 -0
  307. package/skills/router-core/SKILL.md +139 -0
  308. package/skills/router-core/auth-and-guards/SKILL.md +458 -0
  309. package/skills/router-core/code-splitting/SKILL.md +322 -0
  310. package/skills/router-core/data-loading/SKILL.md +485 -0
  311. package/skills/router-core/navigation/SKILL.md +448 -0
  312. package/skills/router-core/not-found-and-errors/SKILL.md +435 -0
  313. package/skills/router-core/path-params/SKILL.md +382 -0
  314. package/skills/router-core/search-params/SKILL.md +349 -0
  315. package/skills/router-core/search-params/references/validation-patterns.md +379 -0
  316. package/skills/router-core/ssr/SKILL.md +437 -0
  317. package/skills/router-core/type-safety/SKILL.md +497 -0
  318. package/src/Matches.ts +291 -0
  319. package/src/RouterProvider.ts +47 -0
  320. package/src/config.ts +42 -0
  321. package/src/defer.ts +69 -0
  322. package/src/fileRoute.ts +164 -0
  323. package/src/global.ts +9 -0
  324. package/src/hash-scroll.ts +21 -0
  325. package/src/history.ts +9 -0
  326. package/src/index.ts +471 -0
  327. package/src/invariant.ts +3 -0
  328. package/src/isServer/client.ts +1 -0
  329. package/src/isServer/development.ts +2 -0
  330. package/src/isServer/server.ts +1 -0
  331. package/src/link.ts +704 -0
  332. package/src/load-matches.ts +1281 -0
  333. package/src/location.ts +51 -0
  334. package/src/lru-cache.ts +74 -0
  335. package/src/manifest.ts +68 -0
  336. package/src/new-process-route-tree.ts +1387 -0
  337. package/src/not-found.ts +41 -0
  338. package/src/path.ts +436 -0
  339. package/src/qss.ts +81 -0
  340. package/src/redirect.ts +179 -0
  341. package/src/rewrite.ts +93 -0
  342. package/src/root.ts +3 -0
  343. package/src/route.ts +2235 -0
  344. package/src/routeInfo.ts +235 -0
  345. package/src/router.ts +3207 -0
  346. package/src/scroll-restoration-inline.ts +81 -0
  347. package/src/scroll-restoration-script/client.ts +5 -0
  348. package/src/scroll-restoration-script/server.ts +64 -0
  349. package/src/scroll-restoration.ts +357 -0
  350. package/src/searchMiddleware.ts +76 -0
  351. package/src/searchParams.ts +90 -0
  352. package/src/ssr/client.ts +6 -0
  353. package/src/ssr/constants.ts +3 -0
  354. package/src/ssr/createRequestHandler.ts +98 -0
  355. package/src/ssr/handlerCallback.ts +15 -0
  356. package/src/ssr/headers.ts +40 -0
  357. package/src/ssr/json.ts +16 -0
  358. package/src/ssr/serializer/RawStream.ts +464 -0
  359. package/src/ssr/serializer/ShallowErrorPlugin.ts +43 -0
  360. package/src/ssr/serializer/seroval-plugins.ts +12 -0
  361. package/src/ssr/serializer/transformer.ts +312 -0
  362. package/src/ssr/server.ts +14 -0
  363. package/src/ssr/ssr-client.ts +313 -0
  364. package/src/ssr/ssr-match-id.ts +7 -0
  365. package/src/ssr/ssr-server.ts +425 -0
  366. package/src/ssr/transformStreamWithRouter.ts +493 -0
  367. package/src/ssr/tsrScript.ts +20 -0
  368. package/src/ssr/types.ts +41 -0
  369. package/src/stores.ts +342 -0
  370. package/src/structuralSharing.ts +7 -0
  371. package/src/typePrimitives.ts +181 -0
  372. package/src/useLoaderData.ts +20 -0
  373. package/src/useLoaderDeps.ts +13 -0
  374. package/src/useNavigate.ts +13 -0
  375. package/src/useParams.ts +20 -0
  376. package/src/useRouteContext.ts +39 -0
  377. package/src/useSearch.ts +20 -0
  378. package/src/utils.ts +708 -0
  379. package/src/validators.ts +121 -0
  380. package/src/vite-env.d.ts +4 -0
@@ -0,0 +1,349 @@
1
+ ---
2
+ name: router-core/search-params
3
+ description: >-
4
+ validateSearch, search param validation with Zod/Valibot/ArkType adapters,
5
+ fallback(), search middlewares (retainSearchParams, stripSearchParams),
6
+ custom serialization (parseSearch, stringifySearch), search param
7
+ inheritance, loaderDeps for cache keys, reading and writing search params.
8
+ type: sub-skill
9
+ library: tanstack-router
10
+ library_version: '1.166.2'
11
+ requires:
12
+ - router-core
13
+ sources:
14
+ - TanStack/router:docs/router/guide/search-params.md
15
+ - TanStack/router:docs/router/how-to/setup-basic-search-params.md
16
+ - TanStack/router:docs/router/how-to/validate-search-params.md
17
+ - TanStack/router:docs/router/how-to/navigate-with-search-params.md
18
+ - TanStack/router:docs/router/how-to/share-search-params-across-routes.md
19
+ - TanStack/router:docs/router/guide/custom-search-param-serialization.md
20
+ ---
21
+
22
+ # Search Params
23
+
24
+ TanStack Router treats search params as JSON-first application state. They are automatically parsed from the URL into structured objects (numbers, booleans, arrays, nested objects) and validated via `validateSearch` on each route.
25
+
26
+ > **CRITICAL**: When using `zodValidator()` and Zod v3, use `fallback()` from `@benjavicente/zod-adapter`, NOT zod's `.catch()`. Using `.catch()` with the zod adapter makes the output type `unknown`, destroying type safety. This does not apply to Valibot or ArkType (which use their own fallback mechanisms). It also does not apply to Zod v4, which should use `.catch()` and not use the `zodValidator()`.
27
+ > **CRITICAL**: Types are fully inferred. Never annotate the return of `useSearch()`.
28
+
29
+ ## Setup: Zod Adapter (Recommended)
30
+
31
+ ```bash
32
+ npm install zod @benjavicente/zod-adapter
33
+ ```
34
+
35
+ ```tsx
36
+ // src/routes/products.tsx
37
+ import { createFileRoute } from '@benjavicente/react-router'
38
+ import { z } from 'zod'
39
+
40
+ const productSearchSchema = z.object({
41
+ page: z.number().default(1).catch(1),
42
+ filter: z.string().default(''),
43
+ sort: z.enum(['newest', 'oldest', 'price']).default('newest').catch('newest'),
44
+ })
45
+
46
+ export const Route = createFileRoute('/products')({
47
+ validateSearch: productSearchSchema,
48
+ component: ProductsPage,
49
+ })
50
+
51
+ function ProductsPage() {
52
+ // page: number, filter: string, sort: 'newest' | 'oldest' | 'price'
53
+ // ALL INFERRED — do not annotate
54
+ const { page, filter, sort } = Route.useSearch()
55
+
56
+ return (
57
+ <div>
58
+ <p>
59
+ Page {page}, filter: {filter}, sort: {sort}
60
+ </p>
61
+ </div>
62
+ )
63
+ }
64
+ ```
65
+
66
+ ## Reading Search Params
67
+
68
+ ### In Route Components: `Route.useSearch()`
69
+
70
+ ```tsx
71
+ function ProductsPage() {
72
+ const { page, sort } = Route.useSearch()
73
+ return <div>Page {page}</div>
74
+ }
75
+ ```
76
+
77
+ ### In Code-Split Components: `getRouteApi()`
78
+
79
+ ```tsx
80
+ import { getRouteApi } from '@benjavicente/react-router'
81
+
82
+ const routeApi = getRouteApi('/products')
83
+
84
+ function ProductFilters() {
85
+ const { sort } = routeApi.useSearch()
86
+ return <select value={sort}>{/* options */}</select>
87
+ }
88
+ ```
89
+
90
+ ### From Any Component: `useSearch({ from })`
91
+
92
+ ```tsx
93
+ import { useSearch } from '@benjavicente/react-router'
94
+
95
+ function SortIndicator() {
96
+ const { sort } = useSearch({ from: '/products' })
97
+ return <span>Sorted by: {sort}</span>
98
+ }
99
+ ```
100
+
101
+ ### Loose Access: `useSearch({ strict: false })`
102
+
103
+ ```tsx
104
+ function GenericPaginator() {
105
+ const search = useSearch({ strict: false })
106
+ // search.page is number | undefined (union of all routes)
107
+ return <span>Page: {search.page ?? 1}</span>
108
+ }
109
+ ```
110
+
111
+ ## Writing Search Params
112
+
113
+ ### Link with Function Form (Preserves Existing Params)
114
+
115
+ ```tsx
116
+ import { Link } from '@benjavicente/react-router'
117
+
118
+ function Pagination() {
119
+ return (
120
+ <Link
121
+ from="/products"
122
+ search={(prev) => ({ ...prev, page: prev.page + 1 })}
123
+ >
124
+ Next Page
125
+ </Link>
126
+ )
127
+ }
128
+ ```
129
+
130
+ ### Link with Object Form (Replaces All Params)
131
+
132
+ ```tsx
133
+ <Link to="/products" search={{ page: 1, filter: '', sort: 'newest' }}>
134
+ Reset
135
+ </Link>
136
+ ```
137
+
138
+ ### Programmatic: `useNavigate()`
139
+
140
+ ```tsx
141
+ import { useNavigate } from '@benjavicente/react-router'
142
+
143
+ function SortDropdown() {
144
+ const navigate = useNavigate({ from: '/products' })
145
+
146
+ return (
147
+ <select
148
+ onChange={(e) => {
149
+ navigate({
150
+ search: (prev) => ({ ...prev, sort: e.target.value, page: 1 }),
151
+ })
152
+ }}
153
+ >
154
+ <option value="newest">Newest</option>
155
+ <option value="price">Price</option>
156
+ </select>
157
+ )
158
+ }
159
+ ```
160
+
161
+ ## Search Param Inheritance
162
+
163
+ Parent route search params are automatically merged into child routes:
164
+
165
+ ```tsx
166
+ // src/routes/shop.tsx — parent defines shared params
167
+ import { createFileRoute } from '@benjavicente/react-router'
168
+ import { z } from 'zod'
169
+
170
+ const shopSearchSchema = z.object({
171
+ currency: z.enum(['USD', 'EUR']).default('USD').catch('USD'),
172
+ })
173
+
174
+ export const Route = createFileRoute('/shop')({
175
+ validateSearch: shopSearchSchema,
176
+ })
177
+ ```
178
+
179
+ ```tsx
180
+ // src/routes/shop/products.tsx — child inherits currency
181
+ import { createFileRoute } from '@benjavicente/react-router'
182
+
183
+ export const Route = createFileRoute('/shop/products')({
184
+ component: ShopProducts,
185
+ })
186
+
187
+ function ShopProducts() {
188
+ // currency is available here from parent — fully typed
189
+ const { currency } = Route.useSearch()
190
+ return <div>Currency: {currency}</div>
191
+ }
192
+ ```
193
+
194
+ ## Search Middlewares
195
+
196
+ ### `retainSearchParams` — Keep Params Across Navigation
197
+
198
+ ```tsx
199
+ import { createRootRoute, retainSearchParams } from '@benjavicente/react-router'
200
+ import { z } from 'zod'
201
+
202
+ const rootSearchSchema = z.object({
203
+ debug: z.boolean().optional(),
204
+ })
205
+
206
+ export const Route = createRootRoute({
207
+ validateSearch: rootSearchSchema,
208
+ search: {
209
+ middlewares: [retainSearchParams(['debug'])],
210
+ },
211
+ })
212
+ ```
213
+
214
+ ### `stripSearchParams` — Remove Default Values from URL
215
+
216
+ ```tsx
217
+ import { createFileRoute, stripSearchParams } from '@benjavicente/react-router'
218
+ import { z } from 'zod'
219
+
220
+ const defaults = { sort: 'newest', page: 1 }
221
+
222
+ const searchSchema = z.object({
223
+ sort: z.string().default(defaults.sort),
224
+ page: z.number().default(defaults.page),
225
+ })
226
+
227
+ export const Route = createFileRoute('/items')({
228
+ validateSearch: searchSchema,
229
+ search: {
230
+ middlewares: [stripSearchParams(defaults)],
231
+ },
232
+ })
233
+ ```
234
+
235
+ ### Chaining Middlewares
236
+
237
+ ```tsx
238
+ export const Route = createFileRoute('/search')({
239
+ validateSearch: z.object({
240
+ retainMe: z.string().optional(),
241
+ arrayWithDefaults: z.string().array().default(['foo', 'bar']),
242
+ required: z.string(),
243
+ }),
244
+ search: {
245
+ middlewares: [
246
+ retainSearchParams(['retainMe']),
247
+ stripSearchParams({ arrayWithDefaults: ['foo', 'bar'] }),
248
+ ],
249
+ },
250
+ })
251
+ ```
252
+
253
+ ## Custom Serialization
254
+
255
+ Override the default JSON serialization at the router level:
256
+
257
+ ```tsx
258
+ import {
259
+ createRouter,
260
+ parseSearchWith,
261
+ stringifySearchWith,
262
+ } from '@benjavicente/react-router'
263
+
264
+ const router = createRouter({
265
+ routeTree,
266
+ // Example: use JSURL2 for compact, human-readable URLs
267
+ parseSearch: parseSearchWith(parse),
268
+ stringifySearch: stringifySearchWith(stringify),
269
+ })
270
+ ```
271
+
272
+ ## Using Search Params in Loaders via `loaderDeps`
273
+
274
+ ```tsx
275
+ export const Route = createFileRoute('/products')({
276
+ validateSearch: productSearchSchema,
277
+ // Pick ONLY the params the loader needs — not the entire search object
278
+ loaderDeps: ({ search }) => ({ page: search.page }),
279
+ loader: async ({ deps }) => {
280
+ return fetchProducts({ page: deps.page })
281
+ },
282
+ })
283
+ ```
284
+
285
+ ## Common Mistakes
286
+
287
+ ### 1. HIGH: Using zod v3's `.catch()` with `zodValidator()` instead of adapter `fallback()`
288
+
289
+ ```tsx
290
+ // WRONG — .catch() with zodValidator makes the type unknown
291
+ const schema = z.object({ page: z.number().catch(1) })
292
+ validateSearch: zodValidator(schema) // page is typed as unknown!
293
+
294
+ // CORRECT — fallback() preserves the inferred type
295
+ import { fallback } from '@benjavicente/zod-adapter'
296
+ const schema = z.object({ page: fallback(z.number(), 1) })
297
+ ```
298
+
299
+ **Important:** This only applies when using Zod v3, not when using Zod v4. For v4, using `.catch()` is correct.
300
+
301
+ ### 2. HIGH: Returning entire search object from `loaderDeps`
302
+
303
+ ```tsx
304
+ // WRONG — loader re-runs on ANY search param change
305
+ loaderDeps: ({ search }) => search
306
+
307
+ // CORRECT — loader only re-runs when page changes
308
+ loaderDeps: ({ search }) => ({ page: search.page })
309
+ ```
310
+
311
+ ### 3. HIGH: Passing Date objects in search params
312
+
313
+ ```tsx
314
+ // WRONG — Date does not serialize correctly to JSON in URLs
315
+ <Link search={{ startDate: new Date() }}>
316
+
317
+ // CORRECT — convert to ISO string
318
+ <Link search={{ startDate: new Date().toISOString() }}>
319
+ ```
320
+
321
+ ### 4. MEDIUM: Parent route missing `validateSearch` blocks inheritance
322
+
323
+ ```tsx
324
+ // WRONG — child cannot access shared params
325
+ export const Route = createRootRoute({
326
+ component: RootComponent,
327
+ // no validateSearch!
328
+ })
329
+
330
+ // CORRECT — parent must define validateSearch for children to inherit
331
+ export const Route = createRootRoute({
332
+ validateSearch: globalSearchSchema,
333
+ component: RootComponent,
334
+ })
335
+ ```
336
+
337
+ ### 5. HIGH (cross-skill): Using search as object instead of function loses params
338
+
339
+ ```tsx
340
+ // WRONG — replaces ALL search params, losing any existing ones
341
+ <Link to="." search={{ page: 2 }}>Page 2</Link>
342
+
343
+ // CORRECT — preserves existing params, updates only page
344
+ <Link to="." search={(prev) => ({ ...prev, page: 2 })}>Page 2</Link>
345
+ ```
346
+
347
+ ## References
348
+
349
+ - [Validation Patterns Reference](./references/validation-patterns.md) — comprehensive patterns for all validation libraries
@@ -0,0 +1,379 @@
1
+ # Search Param Validation Patterns Reference
2
+
3
+ Comprehensive validation patterns for TanStack Router search params across all supported validation approaches.
4
+
5
+ ## Zod with `@benjavicente/zod-adapter`
6
+
7
+ Zod v3 does not implement Standard Schema, so the `@benjavicente/zod-adapter` wrapper is required. Always use `fallback()` from the adapter instead of zod's `.catch()`. Always wrap with `zodValidator()`.
8
+
9
+ ### Basic Types
10
+
11
+ ```tsx
12
+ import { zodValidator, fallback } from '@benjavicente/zod-adapter'
13
+ import { z } from 'zod'
14
+
15
+ const schema = z.object({
16
+ count: fallback(z.number(), 0),
17
+ name: fallback(z.string(), ''),
18
+ active: fallback(z.boolean(), true),
19
+ })
20
+
21
+ export const Route = createFileRoute('/example')({
22
+ validateSearch: zodValidator(schema),
23
+ })
24
+ ```
25
+
26
+ ### Optional Params
27
+
28
+ ```tsx
29
+ const schema = z.object({
30
+ // Truly optional — can be undefined in component
31
+ searchTerm: z.string().optional(),
32
+ // Optional in URL but always has a value in component
33
+ page: fallback(z.number(), 1).default(1),
34
+ })
35
+ ```
36
+
37
+ ### Default Values
38
+
39
+ ```tsx
40
+ const schema = z.object({
41
+ // .default() means the param is optional during navigation
42
+ // but always present (with default) when reading
43
+ page: fallback(z.number(), 1).default(1),
44
+ sort: fallback(z.enum(['name', 'date', 'price']), 'name').default('name'),
45
+ ascending: fallback(z.boolean(), true).default(true),
46
+ })
47
+ ```
48
+
49
+ ### Array Params
50
+
51
+ ```tsx
52
+ const schema = z.object({
53
+ tags: fallback(z.string().array(), []).default([]),
54
+ selectedIds: fallback(z.number().array(), []).default([]),
55
+ })
56
+
57
+ // URL: /items?tags=%5B%22react%22%2C%22typescript%22%5D&selectedIds=%5B1%2C2%2C3%5D
58
+ // Parsed: { tags: ['react', 'typescript'], selectedIds: [1, 2, 3] }
59
+ ```
60
+
61
+ ### Nested Object Params
62
+
63
+ ```tsx
64
+ const schema = z.object({
65
+ filters: fallback(
66
+ z.object({
67
+ status: z.enum(['active', 'inactive']).optional(),
68
+ tags: z.string().array().optional(),
69
+ priceRange: z
70
+ .object({
71
+ min: z.number().min(0),
72
+ max: z.number().min(0),
73
+ })
74
+ .optional(),
75
+ }),
76
+ {},
77
+ ).default({}),
78
+ })
79
+ ```
80
+
81
+ ### Enum with Constraints
82
+
83
+ ```tsx
84
+ const schema = z.object({
85
+ sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
86
+ 'newest',
87
+ ),
88
+ page: fallback(z.number().int().min(1).max(1000), 1).default(1),
89
+ limit: fallback(z.number().int().min(10).max(100), 20).default(20),
90
+ })
91
+ ```
92
+
93
+ ### Discriminated Union
94
+
95
+ ```tsx
96
+ const schema = z.object({
97
+ searchType: fallback(z.enum(['basic', 'advanced']), 'basic').default('basic'),
98
+ query: fallback(z.string(), '').default(''),
99
+ // Advanced-only fields are optional
100
+ category: z.string().optional(),
101
+ minPrice: z.number().optional(),
102
+ maxPrice: z.number().optional(),
103
+ })
104
+ ```
105
+
106
+ For true discriminated union validation:
107
+
108
+ ```tsx
109
+ const basicSearch = z.object({
110
+ searchType: z.literal('basic'),
111
+ query: z.string(),
112
+ })
113
+
114
+ const advancedSearch = z.object({
115
+ searchType: z.literal('advanced'),
116
+ query: z.string(),
117
+ category: z.string(),
118
+ minPrice: z.number(),
119
+ maxPrice: z.number(),
120
+ })
121
+
122
+ const schema = z.discriminatedUnion('searchType', [basicSearch, advancedSearch])
123
+
124
+ export const Route = createFileRoute('/search')({
125
+ validateSearch: zodValidator(schema),
126
+ })
127
+ ```
128
+
129
+ ### Input Transforms (String to Number)
130
+
131
+ When using the zod adapter with transforms, configure `input` and `output` types:
132
+
133
+ ```tsx
134
+ const schema = z.object({
135
+ page: fallback(z.number(), 1).default(1),
136
+ filter: fallback(z.string(), '').default(''),
137
+ })
138
+
139
+ export const Route = createFileRoute('/items')({
140
+ // Default: input type used for navigation, output type used for reading
141
+ validateSearch: zodValidator(schema),
142
+
143
+ // Advanced: swap input/output inference
144
+ // validateSearch: zodValidator({ schema, input: 'output', output: 'input' }),
145
+ })
146
+ ```
147
+
148
+ ### Schema Composition
149
+
150
+ ```tsx
151
+ const paginationSchema = z.object({
152
+ page: fallback(z.number().int().positive(), 1).default(1),
153
+ limit: fallback(z.number().int().min(1).max(100), 20).default(20),
154
+ })
155
+
156
+ const sortSchema = z.object({
157
+ sortBy: z.enum(['name', 'date', 'relevance']).optional(),
158
+ sortOrder: z.enum(['asc', 'desc']).optional(),
159
+ })
160
+
161
+ // Compose for specific routes
162
+ const productSearchSchema = paginationSchema.extend({
163
+ category: z.string().optional(),
164
+ inStock: fallback(z.boolean(), true).default(true),
165
+ })
166
+
167
+ const userSearchSchema = paginationSchema.merge(sortSchema).extend({
168
+ role: z.enum(['admin', 'user']).optional(),
169
+ })
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Valibot (Standard Schema)
175
+
176
+ Valibot 1.0+ implements Standard Schema. No adapter wrapper needed — pass the schema directly to `validateSearch`. The `@benjavicente/valibot-adapter` is optional and only needed for explicit input/output type control.
177
+
178
+ ```bash
179
+ npm install valibot
180
+ ```
181
+
182
+ ```tsx
183
+ import { createFileRoute } from '@benjavicente/react-router'
184
+ import * as v from 'valibot'
185
+
186
+ const productSearchSchema = v.object({
187
+ page: v.optional(v.fallback(v.number(), 1), 1),
188
+ filter: v.optional(v.fallback(v.string(), ''), ''),
189
+ sort: v.optional(
190
+ v.fallback(v.picklist(['newest', 'oldest', 'price']), 'newest'),
191
+ 'newest',
192
+ ),
193
+ })
194
+
195
+ export const Route = createFileRoute('/products')({
196
+ // Pass schema directly — Standard Schema compliant
197
+ validateSearch: productSearchSchema,
198
+ component: ProductsPage,
199
+ })
200
+
201
+ function ProductsPage() {
202
+ const { page, filter, sort } = Route.useSearch()
203
+ return <div>Page {page}</div>
204
+ }
205
+ ```
206
+
207
+ ### Valibot with Constraints
208
+
209
+ ```tsx
210
+ import * as v from 'valibot'
211
+
212
+ const schema = v.object({
213
+ page: v.optional(
214
+ v.fallback(v.pipe(v.number(), v.integer(), v.minValue(1)), 1),
215
+ 1,
216
+ ),
217
+ query: v.optional(v.pipe(v.string(), v.minLength(1), v.maxLength(100))),
218
+ tags: v.optional(v.fallback(v.array(v.string()), []), []),
219
+ })
220
+ ```
221
+
222
+ ### Valibot with Adapter (Alternative)
223
+
224
+ If you need explicit input/output type control:
225
+
226
+ ```tsx
227
+ import { valibotValidator } from '@benjavicente/valibot-adapter'
228
+ import * as v from 'valibot'
229
+
230
+ const schema = v.object({
231
+ page: v.optional(v.fallback(v.number(), 1), 1),
232
+ })
233
+
234
+ export const Route = createFileRoute('/items')({
235
+ validateSearch: valibotValidator(schema),
236
+ })
237
+ ```
238
+
239
+ ---
240
+
241
+ ## ArkType (Standard Schema)
242
+
243
+ ArkType 2.0-rc+ implements Standard Schema. No adapter needed — pass the type directly to `validateSearch`. The `@benjavicente/arktype-adapter` is optional and only needed for explicit input/output type control.
244
+
245
+ ```bash
246
+ npm install arktype
247
+ ```
248
+
249
+ ```tsx
250
+ import { createFileRoute } from '@benjavicente/react-router'
251
+ import { type } from 'arktype'
252
+
253
+ const productSearchSchema = type({
254
+ page: 'number = 1',
255
+ filter: 'string = ""',
256
+ sort: '"newest" | "oldest" | "price" = "newest"',
257
+ })
258
+
259
+ export const Route = createFileRoute('/products')({
260
+ // Pass directly — Standard Schema compliant
261
+ validateSearch: productSearchSchema,
262
+ component: ProductsPage,
263
+ })
264
+
265
+ function ProductsPage() {
266
+ const { page, filter, sort } = Route.useSearch()
267
+ return <div>Page {page}</div>
268
+ }
269
+ ```
270
+
271
+ ### ArkType with Constraints
272
+
273
+ ```tsx
274
+ import { type } from 'arktype'
275
+
276
+ const searchSchema = type({
277
+ 'query?': 'string>0&<=100',
278
+ page: 'number>0 = 1',
279
+ 'sortBy?': "'name'|'date'|'relevance'",
280
+ 'filters?': 'string[]',
281
+ })
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Manual Validation Function
287
+
288
+ For full control without any library. The function receives raw JSON-parsed (but unvalidated) search params.
289
+
290
+ ```tsx
291
+ import { createFileRoute } from '@benjavicente/react-router'
292
+
293
+ type ProductSearch = {
294
+ page: number
295
+ filter: string
296
+ sort: 'newest' | 'oldest' | 'price'
297
+ }
298
+
299
+ export const Route = createFileRoute('/products')({
300
+ validateSearch: (search: Record<string, unknown>): ProductSearch => ({
301
+ page: Number(search?.page ?? 1),
302
+ filter: (search.filter as string) || '',
303
+ sort:
304
+ search.sort === 'newest' ||
305
+ search.sort === 'oldest' ||
306
+ search.sort === 'price'
307
+ ? search.sort
308
+ : 'newest',
309
+ }),
310
+ component: ProductsPage,
311
+ })
312
+
313
+ function ProductsPage() {
314
+ const { page, filter, sort } = Route.useSearch()
315
+ return <div>Page {page}</div>
316
+ }
317
+ ```
318
+
319
+ ### Manual Validation with Error Throwing
320
+
321
+ If `validateSearch` throws, the route's `errorComponent` renders instead:
322
+
323
+ ```tsx
324
+ export const Route = createFileRoute('/products')({
325
+ validateSearch: (search: Record<string, unknown>) => {
326
+ const page = Number(search.page)
327
+ if (isNaN(page) || page < 1) {
328
+ throw new Error('Invalid page number')
329
+ }
330
+ return { page }
331
+ },
332
+ errorComponent: ({ error }) => <div>Bad search params: {error.message}</div>,
333
+ })
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Pattern: Object with `parse` Method
339
+
340
+ Any object with a `.parse()` method works as `validateSearch`:
341
+
342
+ ```tsx
343
+ const mySchema = {
344
+ parse: (input: Record<string, unknown>) => ({
345
+ page: Number(input.page ?? 1),
346
+ query: String(input.query ?? ''),
347
+ }),
348
+ }
349
+
350
+ export const Route = createFileRoute('/search')({
351
+ validateSearch: mySchema,
352
+ })
353
+ ```
354
+
355
+ ---
356
+
357
+ ## Dates in Search Params
358
+
359
+ Never put `Date` objects in search params. Always use ISO strings:
360
+
361
+ ```tsx
362
+ const schema = z.object({
363
+ // Store as string, parse in component if needed
364
+ startDate: z.string().optional(),
365
+ endDate: z.string().optional(),
366
+ })
367
+
368
+ // In component:
369
+ function DateFilter() {
370
+ const { startDate } = Route.useSearch()
371
+ const date = startDate ? new Date(startDate) : null
372
+ return <div>{date?.toLocaleDateString()}</div>
373
+ }
374
+
375
+ // When navigating:
376
+ ;<Link search={(prev) => ({ ...prev, startDate: new Date().toISOString() })}>
377
+ Set Start Date
378
+ </Link>
379
+ ```