@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,493 @@
1
+ import { ReadableStream } from 'node:stream/web'
2
+ import { Readable } from 'node:stream'
3
+ import { TSR_SCRIPT_BARRIER_ID } from './constants'
4
+ import type { AnyRouter } from '../router'
5
+
6
+ export function transformReadableStreamWithRouter(
7
+ router: AnyRouter,
8
+ routerStream: ReadableStream,
9
+ ) {
10
+ return transformStreamWithRouter(router, routerStream)
11
+ }
12
+
13
+ export function transformPipeableStreamWithRouter(
14
+ router: AnyRouter,
15
+ routerStream: Readable,
16
+ ) {
17
+ return Readable.fromWeb(
18
+ transformStreamWithRouter(router, Readable.toWeb(routerStream)),
19
+ )
20
+ }
21
+
22
+ // Use string constants for simple indexOf matching
23
+ const BODY_END_TAG = '</body>'
24
+ const HTML_END_TAG = '</html>'
25
+
26
+ // Minimum length of a valid closing tag: </a> = 4 characters
27
+ const MIN_CLOSING_TAG_LENGTH = 4
28
+
29
+ // Default timeout values (in milliseconds)
30
+ const DEFAULT_SERIALIZATION_TIMEOUT_MS = 60000
31
+ const DEFAULT_LIFETIME_TIMEOUT_MS = 60000
32
+
33
+ // Module-level encoder (stateless, safe to reuse)
34
+ const textEncoder = new TextEncoder()
35
+
36
+ /**
37
+ * Finds the position just after the last valid HTML closing tag in the string.
38
+ *
39
+ * Valid closing tags match the pattern: </[a-zA-Z][\w:.-]*>
40
+ * Examples: </div>, </my-component>, </slot:name.nested>
41
+ *
42
+ * @returns Position after the last closing tag, or -1 if none found
43
+ */
44
+ function findLastClosingTagEnd(str: string): number {
45
+ const len = str.length
46
+ if (len < MIN_CLOSING_TAG_LENGTH) return -1
47
+
48
+ let i = len - 1
49
+
50
+ while (i >= MIN_CLOSING_TAG_LENGTH - 1) {
51
+ // Look for > (charCode 62)
52
+ if (str.charCodeAt(i) === 62) {
53
+ // Look backwards for valid tag name characters
54
+ let j = i - 1
55
+
56
+ // Skip through valid tag name characters
57
+ while (j >= 1) {
58
+ const code = str.charCodeAt(j)
59
+ // Check if it's a valid tag name char: [a-zA-Z0-9_:.-]
60
+ if (
61
+ (code >= 97 && code <= 122) || // a-z
62
+ (code >= 65 && code <= 90) || // A-Z
63
+ (code >= 48 && code <= 57) || // 0-9
64
+ code === 95 || // _
65
+ code === 58 || // :
66
+ code === 46 || // .
67
+ code === 45 // -
68
+ ) {
69
+ j--
70
+ } else {
71
+ break
72
+ }
73
+ }
74
+
75
+ // Check if the first char after </ is a valid start char (letter only)
76
+ const tagNameStart = j + 1
77
+ if (tagNameStart < i) {
78
+ const startCode = str.charCodeAt(tagNameStart)
79
+ // Tag name must start with a letter (a-z or A-Z)
80
+ if (
81
+ (startCode >= 97 && startCode <= 122) ||
82
+ (startCode >= 65 && startCode <= 90)
83
+ ) {
84
+ // Check for </ (charCodes: < = 60, / = 47)
85
+ if (
86
+ j >= 1 &&
87
+ str.charCodeAt(j) === 47 &&
88
+ str.charCodeAt(j - 1) === 60
89
+ ) {
90
+ return i + 1 // Return position after the closing >
91
+ }
92
+ }
93
+ }
94
+ }
95
+ i--
96
+ }
97
+ return -1
98
+ }
99
+
100
+ export function transformStreamWithRouter(
101
+ router: AnyRouter,
102
+ appStream: ReadableStream,
103
+ opts?: {
104
+ /** Timeout for serialization to complete after app render finishes (default: 60000ms) */
105
+ timeoutMs?: number
106
+ /** Maximum lifetime of the stream transform (default: 60000ms). Safety net for cleanup. */
107
+ lifetimeMs?: number
108
+ },
109
+ ) {
110
+ // Check upfront if serialization already finished synchronously
111
+ // This is the fast path for routes with no deferred data
112
+ const serializationAlreadyFinished =
113
+ router.serverSsr?.isSerializationFinished() ?? false
114
+
115
+ // Take any HTML that was buffered before we started listening
116
+ const initialBufferedHtml = router.serverSsr?.takeBufferedHtml()
117
+
118
+ // True passthrough: if serialization already finished and nothing buffered,
119
+ // we can avoid any decoding/scanning while still honoring cleanup + setRenderFinished.
120
+ if (serializationAlreadyFinished && !initialBufferedHtml) {
121
+ let cleanedUp = false
122
+ let controller: ReadableStreamDefaultController<Uint8Array> | undefined
123
+ let isStreamClosed = false
124
+ let lifetimeTimeoutHandle: ReturnType<typeof setTimeout> | undefined
125
+
126
+ const cleanup = () => {
127
+ if (cleanedUp) return
128
+ cleanedUp = true
129
+
130
+ if (lifetimeTimeoutHandle !== undefined) {
131
+ clearTimeout(lifetimeTimeoutHandle)
132
+ lifetimeTimeoutHandle = undefined
133
+ }
134
+
135
+ router.serverSsr?.cleanup()
136
+ }
137
+
138
+ const safeClose = () => {
139
+ if (isStreamClosed) return
140
+ isStreamClosed = true
141
+ try {
142
+ controller?.close()
143
+ } catch {
144
+ // ignore
145
+ }
146
+ }
147
+
148
+ const safeError = (error: unknown) => {
149
+ if (isStreamClosed) return
150
+ isStreamClosed = true
151
+ try {
152
+ controller?.error(error)
153
+ } catch {
154
+ // ignore
155
+ }
156
+ }
157
+
158
+ const lifetimeMs = opts?.lifetimeMs ?? DEFAULT_LIFETIME_TIMEOUT_MS
159
+ lifetimeTimeoutHandle = setTimeout(() => {
160
+ if (!cleanedUp && !isStreamClosed) {
161
+ console.warn(
162
+ `SSR stream transform exceeded maximum lifetime (${lifetimeMs}ms), forcing cleanup`,
163
+ )
164
+ safeError(new Error('Stream lifetime exceeded'))
165
+ cleanup()
166
+ }
167
+ }, lifetimeMs)
168
+
169
+ const stream = new ReadableStream<Uint8Array>({
170
+ start(c: ReadableStreamDefaultController<Uint8Array>) {
171
+ controller = c
172
+ },
173
+ cancel() {
174
+ isStreamClosed = true
175
+ cleanup()
176
+ },
177
+ })
178
+
179
+ ;(async () => {
180
+ const reader = appStream.getReader()
181
+ try {
182
+ while (true) {
183
+ const { done, value } = await reader.read()
184
+ if (done) break
185
+ if (cleanedUp || isStreamClosed) return
186
+ controller?.enqueue(value as unknown as Uint8Array)
187
+ }
188
+
189
+ if (cleanedUp || isStreamClosed) return
190
+
191
+ router.serverSsr?.setRenderFinished()
192
+ safeClose()
193
+ cleanup()
194
+ } catch (error) {
195
+ if (cleanedUp) return
196
+ console.error('Error reading appStream:', error)
197
+ router.serverSsr?.setRenderFinished()
198
+ safeError(error)
199
+ cleanup()
200
+ } finally {
201
+ reader.releaseLock()
202
+ }
203
+ })().catch((error) => {
204
+ if (cleanedUp) return
205
+ console.error('Error in stream transform:', error)
206
+ safeError(error)
207
+ cleanup()
208
+ })
209
+
210
+ return stream
211
+ }
212
+
213
+ let stopListeningToInjectedHtml: (() => void) | undefined
214
+ let stopListeningToSerializationFinished: (() => void) | undefined
215
+ let serializationTimeoutHandle: ReturnType<typeof setTimeout> | undefined
216
+ let lifetimeTimeoutHandle: ReturnType<typeof setTimeout> | undefined
217
+ let cleanedUp = false
218
+
219
+ let controller: ReadableStreamDefaultController<any>
220
+ let isStreamClosed = false
221
+
222
+ const textDecoder = new TextDecoder()
223
+
224
+ // concat'd router HTML; avoids array joins on each flush
225
+ let pendingRouterHtml = initialBufferedHtml ?? ''
226
+
227
+ // between-chunk text buffer; keep bounded to avoid unbounded memory
228
+ let leftover = ''
229
+
230
+ // captured closing tags from </body> onward
231
+ let pendingClosingTags = ''
232
+
233
+ // conservative cap: enough to hold any partial closing tag + a bit
234
+ const MAX_LEFTOVER_CHARS = 2048
235
+
236
+ let isAppRendering = true
237
+ let streamBarrierLifted = false
238
+ let serializationFinished = serializationAlreadyFinished
239
+
240
+ function safeEnqueue(chunk: string | Uint8Array) {
241
+ if (isStreamClosed) return
242
+ if (typeof chunk === 'string') {
243
+ controller.enqueue(textEncoder.encode(chunk))
244
+ } else {
245
+ controller.enqueue(chunk)
246
+ }
247
+ }
248
+
249
+ function safeClose() {
250
+ if (isStreamClosed) return
251
+ isStreamClosed = true
252
+ try {
253
+ controller.close()
254
+ } catch {
255
+ // ignore
256
+ }
257
+ }
258
+
259
+ function safeError(error: unknown) {
260
+ if (isStreamClosed) return
261
+ isStreamClosed = true
262
+ try {
263
+ controller.error(error)
264
+ } catch {
265
+ // ignore
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Cleanup with guards; must be idempotent.
271
+ */
272
+ function cleanup() {
273
+ if (cleanedUp) return
274
+ cleanedUp = true
275
+
276
+ try {
277
+ stopListeningToInjectedHtml?.()
278
+ stopListeningToSerializationFinished?.()
279
+ } catch {
280
+ // ignore
281
+ }
282
+ stopListeningToInjectedHtml = undefined
283
+ stopListeningToSerializationFinished = undefined
284
+
285
+ if (serializationTimeoutHandle !== undefined) {
286
+ clearTimeout(serializationTimeoutHandle)
287
+ serializationTimeoutHandle = undefined
288
+ }
289
+ if (lifetimeTimeoutHandle !== undefined) {
290
+ clearTimeout(lifetimeTimeoutHandle)
291
+ lifetimeTimeoutHandle = undefined
292
+ }
293
+
294
+ pendingRouterHtml = ''
295
+ leftover = ''
296
+ pendingClosingTags = ''
297
+
298
+ router.serverSsr?.cleanup()
299
+ }
300
+
301
+ const stream = new ReadableStream({
302
+ start(c: ReadableStreamDefaultController<any>) {
303
+ controller = c
304
+ },
305
+ cancel() {
306
+ isStreamClosed = true
307
+ cleanup()
308
+ },
309
+ })
310
+
311
+ function flushPendingRouterHtml() {
312
+ if (!pendingRouterHtml) return
313
+ safeEnqueue(pendingRouterHtml)
314
+ pendingRouterHtml = ''
315
+ }
316
+
317
+ function appendRouterHtml(html: string) {
318
+ if (!html) return
319
+ pendingRouterHtml += html
320
+ }
321
+
322
+ /**
323
+ * Finish only when app done and serialization complete.
324
+ */
325
+ function tryFinish() {
326
+ if (isAppRendering || !serializationFinished) return
327
+ if (cleanedUp || isStreamClosed) return
328
+
329
+ if (serializationTimeoutHandle !== undefined) {
330
+ clearTimeout(serializationTimeoutHandle)
331
+ serializationTimeoutHandle = undefined
332
+ }
333
+
334
+ // Flush any remaining bytes in the TextDecoder
335
+ const decoderRemainder = textDecoder.decode()
336
+
337
+ if (leftover) safeEnqueue(leftover)
338
+ if (decoderRemainder) safeEnqueue(decoderRemainder)
339
+ flushPendingRouterHtml()
340
+ if (pendingClosingTags) safeEnqueue(pendingClosingTags)
341
+
342
+ safeClose()
343
+ cleanup()
344
+ }
345
+
346
+ // Safety net: cleanup even if consumer never reads
347
+ const lifetimeMs = opts?.lifetimeMs ?? DEFAULT_LIFETIME_TIMEOUT_MS
348
+ lifetimeTimeoutHandle = setTimeout(() => {
349
+ if (!cleanedUp && !isStreamClosed) {
350
+ console.warn(
351
+ `SSR stream transform exceeded maximum lifetime (${lifetimeMs}ms), forcing cleanup`,
352
+ )
353
+ safeError(new Error('Stream lifetime exceeded'))
354
+ cleanup()
355
+ }
356
+ }, lifetimeMs)
357
+
358
+ if (!serializationAlreadyFinished) {
359
+ stopListeningToInjectedHtml = router.subscribe('onInjectedHtml', () => {
360
+ if (cleanedUp || isStreamClosed) return
361
+ const html = router.serverSsr?.takeBufferedHtml()
362
+ if (!html) return
363
+
364
+ // If we've already captured </body> (pendingClosingTags), we must keep appending
365
+ // so injection stays before the stored closing tags.
366
+ if (isAppRendering || leftover || pendingClosingTags) {
367
+ appendRouterHtml(html)
368
+ } else {
369
+ safeEnqueue(html)
370
+ }
371
+ })
372
+
373
+ stopListeningToSerializationFinished = router.subscribe(
374
+ 'onSerializationFinished',
375
+ () => {
376
+ serializationFinished = true
377
+ tryFinish()
378
+ },
379
+ )
380
+ }
381
+
382
+ // Transform the appStream
383
+ ;(async () => {
384
+ const reader = appStream.getReader()
385
+ try {
386
+ while (true) {
387
+ const { done, value } = await reader.read()
388
+ if (done) break
389
+
390
+ if (cleanedUp || isStreamClosed) return
391
+
392
+ const text =
393
+ value instanceof Uint8Array
394
+ ? textDecoder.decode(value, { stream: true })
395
+ : String(value)
396
+
397
+ // Fast path: most chunks have no pending left-over.
398
+ const chunkString = leftover ? leftover + text : text
399
+
400
+ if (!streamBarrierLifted) {
401
+ if (chunkString.includes(TSR_SCRIPT_BARRIER_ID)) {
402
+ streamBarrierLifted = true
403
+ router.serverSsr?.liftScriptBarrier()
404
+ }
405
+ }
406
+
407
+ // If we already saw </body>, everything else is part of tail; buffer it.
408
+ if (pendingClosingTags) {
409
+ pendingClosingTags += chunkString
410
+ leftover = ''
411
+ continue
412
+ }
413
+
414
+ const bodyEndIndex = chunkString.indexOf(BODY_END_TAG)
415
+ const htmlEndIndex = chunkString.indexOf(HTML_END_TAG)
416
+
417
+ if (
418
+ bodyEndIndex !== -1 &&
419
+ htmlEndIndex !== -1 &&
420
+ bodyEndIndex < htmlEndIndex
421
+ ) {
422
+ pendingClosingTags = chunkString.slice(bodyEndIndex)
423
+ safeEnqueue(chunkString.slice(0, bodyEndIndex))
424
+ flushPendingRouterHtml()
425
+ leftover = ''
426
+ continue
427
+ }
428
+
429
+ const lastClosingTagEnd = findLastClosingTagEnd(chunkString)
430
+
431
+ if (lastClosingTagEnd > 0) {
432
+ safeEnqueue(chunkString.slice(0, lastClosingTagEnd))
433
+ flushPendingRouterHtml()
434
+
435
+ leftover = chunkString.slice(lastClosingTagEnd)
436
+ if (leftover.length > MAX_LEFTOVER_CHARS) {
437
+ // Ensure bounded memory even if a consumer streams long text sequences
438
+ // without any closing tags. This may reduce injection granularity but is correct.
439
+ safeEnqueue(leftover.slice(0, leftover.length - MAX_LEFTOVER_CHARS))
440
+ leftover = leftover.slice(-MAX_LEFTOVER_CHARS)
441
+ }
442
+ } else {
443
+ // No closing tag found; keep small tail to handle split closing tags,
444
+ // but stream older bytes to prevent unbounded buffering.
445
+ const combined = chunkString
446
+ if (combined.length > MAX_LEFTOVER_CHARS) {
447
+ const flushUpto = combined.length - MAX_LEFTOVER_CHARS
448
+ safeEnqueue(combined.slice(0, flushUpto))
449
+ leftover = combined.slice(flushUpto)
450
+ } else {
451
+ leftover = combined
452
+ }
453
+ }
454
+ }
455
+
456
+ if (cleanedUp || isStreamClosed) return
457
+
458
+ isAppRendering = false
459
+ router.serverSsr?.setRenderFinished()
460
+
461
+ if (serializationFinished) {
462
+ tryFinish()
463
+ } else {
464
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_SERIALIZATION_TIMEOUT_MS
465
+ serializationTimeoutHandle = setTimeout(() => {
466
+ if (!cleanedUp && !isStreamClosed) {
467
+ console.error('Serialization timeout after app render finished')
468
+ safeError(
469
+ new Error('Serialization timeout after app render finished'),
470
+ )
471
+ cleanup()
472
+ }
473
+ }, timeoutMs)
474
+ }
475
+ } catch (error) {
476
+ if (cleanedUp) return
477
+ console.error('Error reading appStream:', error)
478
+ isAppRendering = false
479
+ router.serverSsr?.setRenderFinished()
480
+ safeError(error)
481
+ cleanup()
482
+ } finally {
483
+ reader.releaseLock()
484
+ }
485
+ })().catch((error) => {
486
+ if (cleanedUp) return
487
+ console.error('Error in stream transform:', error)
488
+ safeError(error)
489
+ cleanup()
490
+ })
491
+
492
+ return stream
493
+ }
@@ -0,0 +1,20 @@
1
+ self.$_TSR = {
2
+ h() {
3
+ this.hydrated = true
4
+ this.c()
5
+ },
6
+ e() {
7
+ this.streamEnded = true
8
+ this.c()
9
+ },
10
+ c() {
11
+ if (this.hydrated && this.streamEnded) {
12
+ delete self.$_TSR
13
+ delete self.$R['tsr']
14
+ }
15
+ },
16
+ p(script) {
17
+ !this.initialized ? this.buffer.push(script) : script()
18
+ },
19
+ buffer: [],
20
+ }
@@ -0,0 +1,41 @@
1
+ import type { Manifest } from '../manifest'
2
+ import type { MakeRouteMatch } from '../Matches'
3
+
4
+ export interface DehydratedMatch {
5
+ i: MakeRouteMatch['id']
6
+ b?: MakeRouteMatch['__beforeLoadContext']
7
+ l?: MakeRouteMatch['loaderData']
8
+ e?: MakeRouteMatch['error']
9
+ u: MakeRouteMatch['updatedAt']
10
+ s: MakeRouteMatch['status']
11
+ ssr?: MakeRouteMatch['ssr']
12
+ g?: true
13
+ }
14
+
15
+ export interface DehydratedRouter {
16
+ manifest: Manifest | undefined
17
+ dehydratedData?: any
18
+ lastMatchId?: string
19
+ matches: Array<DehydratedMatch>
20
+ }
21
+
22
+ export interface TsrSsrGlobal {
23
+ router?: DehydratedRouter
24
+ // Signal that router hydration is complete
25
+ h: () => void
26
+ // Signal that stream has ended
27
+ e: () => void
28
+ // Cleanup all hydration resources and scripts
29
+ c: () => void
30
+ // p: Push script into buffer or execute immediately
31
+ p: (script: () => void) => void
32
+ buffer: Array<() => void>
33
+ // custom transformers, shortened since this is sent for each streamed value that needs a custom transformer
34
+ t?: Map<string, (value: any) => any>
35
+ // this flag indicates whether the transformers were initialized
36
+ initialized?: boolean
37
+ // router is hydrated and doesnt need the streamed values anymore
38
+ hydrated?: boolean
39
+ // stream has ended
40
+ streamEnded?: boolean
41
+ }