@real-router/core 0.79.0 → 0.80.0

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 (338) hide show
  1. package/dist/cjs/Router-DGUed2F4.js +2 -0
  2. package/dist/cjs/{Router-BRuC-daj.js.map → Router-DGUed2F4.js.map} +1 -1
  3. package/dist/cjs/{Router-BG5yNYUG.d.ts → Router.d.ts} +5 -4
  4. package/dist/cjs/Router.d.ts.map +1 -0
  5. package/dist/cjs/Router.js +2 -0
  6. package/dist/cjs/Router.js.map +1 -0
  7. package/dist/cjs/RouterError.d.ts +182 -0
  8. package/dist/cjs/RouterError.d.ts.map +1 -0
  9. package/dist/cjs/RouterError.js +2 -0
  10. package/dist/cjs/RouterError.js.map +1 -0
  11. package/dist/cjs/api/cloneRouter.d.ts +86 -0
  12. package/dist/cjs/api/cloneRouter.d.ts.map +1 -0
  13. package/dist/cjs/api/cloneRouter.js +2 -0
  14. package/dist/cjs/api/cloneRouter.js.map +1 -0
  15. package/dist/cjs/api/getDependenciesApi.d.ts +7 -0
  16. package/dist/cjs/api/getDependenciesApi.d.ts.map +1 -0
  17. package/dist/cjs/api/getDependenciesApi.js +2 -0
  18. package/dist/cjs/api/getDependenciesApi.js.map +1 -0
  19. package/dist/cjs/api/getLifecycleApi.d.ts +7 -0
  20. package/dist/cjs/api/getLifecycleApi.d.ts.map +1 -0
  21. package/dist/cjs/api/getLifecycleApi.js +2 -0
  22. package/dist/cjs/api/getLifecycleApi.js.map +1 -0
  23. package/dist/cjs/api/getPluginApi.d.ts +7 -0
  24. package/dist/cjs/api/getPluginApi.d.ts.map +1 -0
  25. package/dist/cjs/api/getPluginApi.js +2 -0
  26. package/dist/cjs/api/getPluginApi.js.map +1 -0
  27. package/dist/cjs/api/getRoutesApi.d.ts +7 -0
  28. package/dist/cjs/api/getRoutesApi.d.ts.map +1 -0
  29. package/dist/cjs/api/getRoutesApi.js +2 -0
  30. package/dist/cjs/api/getRoutesApi.js.map +1 -0
  31. package/dist/cjs/api/helpers.js +2 -0
  32. package/dist/cjs/api/helpers.js.map +1 -0
  33. package/dist/cjs/api/types.d.ts +9 -0
  34. package/dist/cjs/api/types.d.ts.map +1 -0
  35. package/dist/cjs/api.d.ts +8 -105
  36. package/dist/cjs/api.js +1 -2
  37. package/dist/cjs/api.js.map +1 -1
  38. package/dist/cjs/buildParamMeta-DniluAIV.js.map +1 -1
  39. package/dist/cjs/constants.d.ts +25 -0
  40. package/dist/cjs/constants.d.ts.map +1 -0
  41. package/dist/cjs/constants.js +2 -0
  42. package/dist/cjs/constants.js.map +1 -0
  43. package/dist/cjs/createRouter.d.ts +23 -0
  44. package/dist/cjs/createRouter.d.ts.map +1 -0
  45. package/dist/cjs/createRouter.js +2 -0
  46. package/dist/cjs/createRouter.js.map +1 -0
  47. package/dist/cjs/engine/builder/buildTree.js +2 -0
  48. package/dist/cjs/engine/builder/buildTree.js.map +1 -0
  49. package/dist/cjs/engine/builder/computeCaches.js +2 -0
  50. package/dist/cjs/engine/builder/computeCaches.js.map +1 -0
  51. package/dist/cjs/engine/builder/createRouteTree.js +2 -0
  52. package/dist/cjs/engine/builder/createRouteTree.js.map +1 -0
  53. package/dist/cjs/engine/builder/types.d.ts +48 -0
  54. package/dist/cjs/engine/builder/types.d.ts.map +1 -0
  55. package/dist/cjs/engine/createMatcher.d.ts +29 -0
  56. package/dist/cjs/engine/createMatcher.d.ts.map +1 -0
  57. package/dist/cjs/engine/createMatcher.js +2 -0
  58. package/dist/cjs/engine/createMatcher.js.map +1 -0
  59. package/dist/cjs/engine/operations/routeTreeToDefinitions.js +2 -0
  60. package/dist/cjs/engine/operations/routeTreeToDefinitions.js.map +1 -0
  61. package/dist/cjs/engine/path-matcher/SegmentMatcher.d.ts +16 -0
  62. package/dist/cjs/engine/path-matcher/SegmentMatcher.d.ts.map +1 -0
  63. package/dist/cjs/engine/path-matcher/SegmentMatcher.js +2 -0
  64. package/dist/cjs/engine/path-matcher/SegmentMatcher.js.map +1 -0
  65. package/dist/cjs/engine/path-matcher/buildParamMeta.js +2 -0
  66. package/dist/cjs/engine/path-matcher/buildParamMeta.js.map +1 -0
  67. package/dist/cjs/engine/path-matcher/encoding.js +2 -0
  68. package/dist/cjs/engine/path-matcher/encoding.js.map +1 -0
  69. package/dist/cjs/engine/path-matcher/parseSegment.js +2 -0
  70. package/dist/cjs/engine/path-matcher/parseSegment.js.map +1 -0
  71. package/dist/cjs/engine/path-matcher/pathUtils.js +2 -0
  72. package/dist/cjs/engine/path-matcher/pathUtils.js.map +1 -0
  73. package/dist/cjs/engine/path-matcher/percentEncoding.js +2 -0
  74. package/dist/cjs/engine/path-matcher/percentEncoding.js.map +1 -0
  75. package/dist/cjs/engine/path-matcher/registration/buildParts.js +2 -0
  76. package/dist/cjs/engine/path-matcher/registration/buildParts.js.map +1 -0
  77. package/dist/cjs/engine/path-matcher/registration/context.js +2 -0
  78. package/dist/cjs/engine/path-matcher/registration/context.js.map +1 -0
  79. package/dist/cjs/engine/path-matcher/registration/errors.js +2 -0
  80. package/dist/cjs/engine/path-matcher/registration/errors.js.map +1 -0
  81. package/dist/cjs/engine/path-matcher/registration/index.js +2 -0
  82. package/dist/cjs/engine/path-matcher/registration/index.js.map +1 -0
  83. package/dist/cjs/engine/path-matcher/registration/trie.js +2 -0
  84. package/dist/cjs/engine/path-matcher/registration/trie.js.map +1 -0
  85. package/dist/cjs/engine/path-matcher/registration/trieNodes.js +2 -0
  86. package/dist/cjs/engine/path-matcher/registration/trieNodes.js.map +1 -0
  87. package/dist/cjs/{types-DaXCTxi1.d.ts → engine/path-matcher/types.d.ts} +2 -47
  88. package/dist/cjs/engine/path-matcher/types.d.ts.map +1 -0
  89. package/dist/cjs/engine/search-params/decode.js +2 -0
  90. package/dist/cjs/engine/search-params/decode.js.map +1 -0
  91. package/dist/cjs/engine/search-params/encode.js +2 -0
  92. package/dist/cjs/engine/search-params/encode.js.map +1 -0
  93. package/dist/cjs/engine/search-params/searchParams.js +2 -0
  94. package/dist/cjs/engine/search-params/searchParams.js.map +1 -0
  95. package/dist/cjs/engine/search-params/strategies/array.js +2 -0
  96. package/dist/cjs/engine/search-params/strategies/array.js.map +1 -0
  97. package/dist/cjs/engine/search-params/strategies/boolean.js +2 -0
  98. package/dist/cjs/engine/search-params/strategies/boolean.js.map +1 -0
  99. package/dist/cjs/engine/search-params/strategies/index.js +2 -0
  100. package/dist/cjs/engine/search-params/strategies/index.js.map +1 -0
  101. package/dist/cjs/engine/search-params/strategies/null.js +2 -0
  102. package/dist/cjs/engine/search-params/strategies/null.js.map +1 -0
  103. package/dist/cjs/engine/search-params/strategies/number.js +2 -0
  104. package/dist/cjs/engine/search-params/strategies/number.js.map +1 -0
  105. package/dist/cjs/engine/search-params/types.d.ts +72 -0
  106. package/dist/cjs/engine/search-params/types.d.ts.map +1 -0
  107. package/dist/cjs/engine/search-params/utils.js +2 -0
  108. package/dist/cjs/engine/search-params/utils.js.map +1 -0
  109. package/dist/cjs/engine/validation/route-batch.d.ts +38 -0
  110. package/dist/cjs/engine/validation/route-batch.d.ts.map +1 -0
  111. package/dist/cjs/engine/validation/route-batch.js +2 -0
  112. package/dist/cjs/engine/validation/route-batch.js.map +1 -0
  113. package/dist/cjs/engine/validation/routes.js +2 -0
  114. package/dist/cjs/engine/validation/routes.js.map +1 -0
  115. package/dist/cjs/foundation/event-emitter/EventEmitter.js +2 -0
  116. package/dist/cjs/foundation/event-emitter/EventEmitter.js.map +1 -0
  117. package/dist/cjs/foundation/fsm/fsm.js +2 -0
  118. package/dist/cjs/foundation/fsm/fsm.js.map +1 -0
  119. package/dist/cjs/foundation/logger/RouterLogger.js +2 -0
  120. package/dist/cjs/foundation/logger/RouterLogger.js.map +1 -0
  121. package/dist/cjs/foundation/logger/constants.js +2 -0
  122. package/dist/cjs/foundation/logger/constants.js.map +1 -0
  123. package/dist/cjs/getNavigator.d.ts +6 -0
  124. package/dist/cjs/getNavigator.d.ts.map +1 -0
  125. package/dist/cjs/getNavigator.js +2 -0
  126. package/dist/cjs/getNavigator.js.map +1 -0
  127. package/dist/cjs/guards.js +2 -0
  128. package/dist/cjs/guards.js.map +1 -0
  129. package/dist/cjs/helpers.js +2 -0
  130. package/dist/cjs/helpers.js.map +1 -0
  131. package/dist/cjs/index.d.ts +17 -239
  132. package/dist/cjs/index.js +1 -2
  133. package/dist/cjs/internals.d.ts +98 -0
  134. package/dist/cjs/internals.d.ts.map +1 -0
  135. package/dist/cjs/internals.js +2 -0
  136. package/dist/cjs/internals.js.map +1 -0
  137. package/dist/cjs/namespaces/DependenciesNamespace/dependenciesStore.d.ts +10 -0
  138. package/dist/cjs/namespaces/DependenciesNamespace/dependenciesStore.d.ts.map +1 -0
  139. package/dist/cjs/namespaces/DependenciesNamespace/dependenciesStore.js +2 -0
  140. package/dist/cjs/namespaces/DependenciesNamespace/dependenciesStore.js.map +1 -0
  141. package/dist/cjs/namespaces/EventBusNamespace/EventBusNamespace.js +2 -0
  142. package/dist/cjs/namespaces/EventBusNamespace/EventBusNamespace.js.map +1 -0
  143. package/dist/cjs/namespaces/NavigationNamespace/NavigationNamespace.js +2 -0
  144. package/dist/cjs/namespaces/NavigationNamespace/NavigationNamespace.js.map +1 -0
  145. package/dist/cjs/namespaces/NavigationNamespace/constants.js +2 -0
  146. package/dist/cjs/namespaces/NavigationNamespace/constants.js.map +1 -0
  147. package/dist/cjs/namespaces/NavigationNamespace/transition/completeTransition.js +2 -0
  148. package/dist/cjs/namespaces/NavigationNamespace/transition/completeTransition.js.map +1 -0
  149. package/dist/cjs/namespaces/NavigationNamespace/transition/errorHandling.js +2 -0
  150. package/dist/cjs/namespaces/NavigationNamespace/transition/errorHandling.js.map +1 -0
  151. package/dist/cjs/namespaces/NavigationNamespace/transition/guardPhase.js +2 -0
  152. package/dist/cjs/namespaces/NavigationNamespace/transition/guardPhase.js.map +1 -0
  153. package/dist/cjs/namespaces/OptionsNamespace/OptionsNamespace.js +2 -0
  154. package/dist/cjs/namespaces/OptionsNamespace/OptionsNamespace.js.map +1 -0
  155. package/dist/cjs/namespaces/OptionsNamespace/constants.js +2 -0
  156. package/dist/cjs/namespaces/OptionsNamespace/constants.js.map +1 -0
  157. package/dist/cjs/namespaces/OptionsNamespace/helpers.js +2 -0
  158. package/dist/cjs/namespaces/OptionsNamespace/helpers.js.map +1 -0
  159. package/dist/cjs/namespaces/OptionsNamespace/validators.js +2 -0
  160. package/dist/cjs/namespaces/OptionsNamespace/validators.js.map +1 -0
  161. package/dist/cjs/namespaces/PluginsNamespace/PluginsNamespace.js +2 -0
  162. package/dist/cjs/namespaces/PluginsNamespace/PluginsNamespace.js.map +1 -0
  163. package/dist/cjs/namespaces/PluginsNamespace/constants.js +2 -0
  164. package/dist/cjs/namespaces/PluginsNamespace/constants.js.map +1 -0
  165. package/dist/cjs/namespaces/PluginsNamespace/validators.js +2 -0
  166. package/dist/cjs/namespaces/PluginsNamespace/validators.js.map +1 -0
  167. package/dist/cjs/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.d.ts +174 -0
  168. package/dist/cjs/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.d.ts.map +1 -0
  169. package/dist/cjs/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.js +2 -0
  170. package/dist/cjs/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.js.map +1 -0
  171. package/dist/cjs/namespaces/RouteLifecycleNamespace/types.d.ts +17 -0
  172. package/dist/cjs/namespaces/RouteLifecycleNamespace/types.d.ts.map +1 -0
  173. package/dist/cjs/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.js +2 -0
  174. package/dist/cjs/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.js.map +1 -0
  175. package/dist/cjs/namespaces/RouterLifecycleNamespace/constants.js +2 -0
  176. package/dist/cjs/namespaces/RouterLifecycleNamespace/constants.js.map +1 -0
  177. package/dist/cjs/namespaces/RoutesNamespace/RoutesNamespace.js +2 -0
  178. package/dist/cjs/namespaces/RoutesNamespace/RoutesNamespace.js.map +1 -0
  179. package/dist/cjs/namespaces/RoutesNamespace/constants.js +2 -0
  180. package/dist/cjs/namespaces/RoutesNamespace/constants.js.map +1 -0
  181. package/dist/cjs/namespaces/RoutesNamespace/forwardChain.d.ts +5 -0
  182. package/dist/cjs/namespaces/RoutesNamespace/forwardChain.d.ts.map +1 -0
  183. package/dist/cjs/namespaces/RoutesNamespace/forwardChain.js +2 -0
  184. package/dist/cjs/namespaces/RoutesNamespace/forwardChain.js.map +1 -0
  185. package/dist/cjs/namespaces/RoutesNamespace/helpers.js +2 -0
  186. package/dist/cjs/namespaces/RoutesNamespace/helpers.js.map +1 -0
  187. package/dist/cjs/namespaces/RoutesNamespace/routeGuards.js +2 -0
  188. package/dist/cjs/namespaces/RoutesNamespace/routeGuards.js.map +1 -0
  189. package/dist/cjs/namespaces/RoutesNamespace/routesStore.d.ts +42 -0
  190. package/dist/cjs/namespaces/RoutesNamespace/routesStore.d.ts.map +1 -0
  191. package/dist/cjs/namespaces/RoutesNamespace/routesStore.js +2 -0
  192. package/dist/cjs/namespaces/RoutesNamespace/routesStore.js.map +1 -0
  193. package/dist/cjs/namespaces/RoutesNamespace/types.d.ts +57 -0
  194. package/dist/cjs/namespaces/RoutesNamespace/types.d.ts.map +1 -0
  195. package/dist/cjs/namespaces/StateNamespace/StateNamespace.js +2 -0
  196. package/dist/cjs/namespaces/StateNamespace/StateNamespace.js.map +1 -0
  197. package/dist/cjs/namespaces/StateNamespace/helpers.js +2 -0
  198. package/dist/cjs/namespaces/StateNamespace/helpers.js.map +1 -0
  199. package/dist/cjs/routerFSM.js +2 -0
  200. package/dist/cjs/routerFSM.js.map +1 -0
  201. package/dist/cjs/stateMetaStore.js +2 -0
  202. package/dist/cjs/stateMetaStore.js.map +1 -0
  203. package/dist/cjs/transitionPath.js +2 -0
  204. package/dist/cjs/transitionPath.js.map +1 -0
  205. package/dist/cjs/{RouterValidator-CZ8kPkrI.d.ts → types/RouterValidator.d.ts} +2 -2
  206. package/dist/cjs/types/RouterValidator.d.ts.map +1 -0
  207. package/dist/cjs/types/api.d.ts +184 -0
  208. package/dist/cjs/types/api.d.ts.map +1 -0
  209. package/dist/cjs/types/base.d.ts +95 -0
  210. package/dist/cjs/types/base.d.ts.map +1 -0
  211. package/dist/cjs/types/constants.d.ts +72 -0
  212. package/dist/cjs/types/constants.d.ts.map +1 -0
  213. package/dist/cjs/types/internal.d.ts +9 -0
  214. package/dist/cjs/types/internal.d.ts.map +1 -0
  215. package/dist/cjs/types/limits.d.ts +45 -0
  216. package/dist/cjs/types/limits.d.ts.map +1 -0
  217. package/dist/cjs/types/route-node-types.d.ts +46 -0
  218. package/dist/cjs/types/route-node-types.d.ts.map +1 -0
  219. package/dist/cjs/types/router.d.ts +313 -0
  220. package/dist/cjs/types/router.d.ts.map +1 -0
  221. package/dist/cjs/types/tree-changed.d.ts +55 -0
  222. package/dist/cjs/types/tree-changed.d.ts.map +1 -0
  223. package/dist/cjs/types.d.ts +208 -2
  224. package/dist/cjs/types.d.ts.map +1 -0
  225. package/dist/cjs/validation.d.ts +6 -518
  226. package/dist/cjs/validation.js +1 -2
  227. package/dist/cjs/wiring/wireNamespaces.js +2 -0
  228. package/dist/cjs/wiring/wireNamespaces.js.map +1 -0
  229. package/dist/esm/Router-Bk6PfSE8.mjs +2 -0
  230. package/dist/esm/{Router-DikzugaD.mjs.map → Router-Bk6PfSE8.mjs.map} +1 -1
  231. package/dist/esm/{Router-Cy75qbgU.d.mts → Router.d.mts} +5 -4
  232. package/dist/esm/Router.d.mts.map +1 -0
  233. package/dist/esm/RouterError.d.mts +182 -0
  234. package/dist/esm/RouterError.d.mts.map +1 -0
  235. package/dist/esm/api/cloneRouter.d.mts +86 -0
  236. package/dist/esm/api/cloneRouter.d.mts.map +1 -0
  237. package/dist/esm/api/getDependenciesApi.d.mts +7 -0
  238. package/dist/esm/api/getDependenciesApi.d.mts.map +1 -0
  239. package/dist/esm/api/getLifecycleApi.d.mts +7 -0
  240. package/dist/esm/api/getLifecycleApi.d.mts.map +1 -0
  241. package/dist/esm/api/getPluginApi.d.mts +7 -0
  242. package/dist/esm/api/getPluginApi.d.mts.map +1 -0
  243. package/dist/esm/api/getRoutesApi.d.mts +7 -0
  244. package/dist/esm/api/getRoutesApi.d.mts.map +1 -0
  245. package/dist/esm/api/types.d.mts +9 -0
  246. package/dist/esm/api/types.d.mts.map +1 -0
  247. package/dist/esm/api.d.mts +8 -105
  248. package/dist/esm/api.mjs +1 -1
  249. package/dist/esm/api.mjs.map +1 -1
  250. package/dist/esm/buildParamMeta-bOLhLF9h.mjs.map +1 -1
  251. package/dist/esm/constants.d.mts +25 -0
  252. package/dist/esm/constants.d.mts.map +1 -0
  253. package/dist/esm/createRouter.d.mts +23 -0
  254. package/dist/esm/createRouter.d.mts.map +1 -0
  255. package/dist/esm/engine/builder/types.d.mts +48 -0
  256. package/dist/esm/engine/builder/types.d.mts.map +1 -0
  257. package/dist/esm/engine/createMatcher.d.mts +29 -0
  258. package/dist/esm/engine/createMatcher.d.mts.map +1 -0
  259. package/dist/esm/engine/path-matcher/SegmentMatcher.d.mts +16 -0
  260. package/dist/esm/engine/path-matcher/SegmentMatcher.d.mts.map +1 -0
  261. package/dist/esm/{types-DaXCTxi1.d.mts → engine/path-matcher/types.d.mts} +2 -47
  262. package/dist/esm/engine/path-matcher/types.d.mts.map +1 -0
  263. package/dist/esm/engine/search-params/types.d.mts +72 -0
  264. package/dist/esm/engine/search-params/types.d.mts.map +1 -0
  265. package/dist/esm/engine/validation/route-batch.d.mts +38 -0
  266. package/dist/esm/engine/validation/route-batch.d.mts.map +1 -0
  267. package/dist/esm/getNavigator.d.mts +6 -0
  268. package/dist/esm/getNavigator.d.mts.map +1 -0
  269. package/dist/esm/index.d.mts +17 -239
  270. package/dist/esm/index.mjs +1 -1
  271. package/dist/esm/internals.d.mts +98 -0
  272. package/dist/esm/internals.d.mts.map +1 -0
  273. package/dist/esm/namespaces/DependenciesNamespace/dependenciesStore.d.mts +10 -0
  274. package/dist/esm/namespaces/DependenciesNamespace/dependenciesStore.d.mts.map +1 -0
  275. package/dist/esm/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.d.mts +174 -0
  276. package/dist/esm/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.d.mts.map +1 -0
  277. package/dist/esm/namespaces/RouteLifecycleNamespace/types.d.mts +17 -0
  278. package/dist/esm/namespaces/RouteLifecycleNamespace/types.d.mts.map +1 -0
  279. package/dist/esm/namespaces/RoutesNamespace/forwardChain.d.mts +5 -0
  280. package/dist/esm/namespaces/RoutesNamespace/forwardChain.d.mts.map +1 -0
  281. package/dist/esm/namespaces/RoutesNamespace/routesStore.d.mts +42 -0
  282. package/dist/esm/namespaces/RoutesNamespace/routesStore.d.mts.map +1 -0
  283. package/dist/esm/namespaces/RoutesNamespace/types.d.mts +57 -0
  284. package/dist/esm/namespaces/RoutesNamespace/types.d.mts.map +1 -0
  285. package/dist/esm/{RouterValidator-CZ8kPkrI.d.mts → types/RouterValidator.d.mts} +2 -2
  286. package/dist/esm/types/RouterValidator.d.mts.map +1 -0
  287. package/dist/esm/types/api.d.mts +184 -0
  288. package/dist/esm/types/api.d.mts.map +1 -0
  289. package/dist/esm/types/base.d.mts +95 -0
  290. package/dist/esm/types/base.d.mts.map +1 -0
  291. package/dist/esm/types/constants.d.mts +72 -0
  292. package/dist/esm/types/constants.d.mts.map +1 -0
  293. package/dist/esm/types/internal.d.mts +9 -0
  294. package/dist/esm/types/internal.d.mts.map +1 -0
  295. package/dist/esm/types/limits.d.mts +45 -0
  296. package/dist/esm/types/limits.d.mts.map +1 -0
  297. package/dist/esm/types/route-node-types.d.mts +46 -0
  298. package/dist/esm/types/route-node-types.d.mts.map +1 -0
  299. package/dist/esm/types/router.d.mts +313 -0
  300. package/dist/esm/types/router.d.mts.map +1 -0
  301. package/dist/esm/types/tree-changed.d.mts +55 -0
  302. package/dist/esm/types/tree-changed.d.mts.map +1 -0
  303. package/dist/esm/types.d.mts +208 -2
  304. package/dist/esm/types.d.mts.map +1 -0
  305. package/dist/esm/validation.d.mts +6 -518
  306. package/package.json +5 -14
  307. package/dist/cjs/Router-BG5yNYUG.d.ts.map +0 -1
  308. package/dist/cjs/Router-BRuC-daj.js +0 -2
  309. package/dist/cjs/RouterValidator-CZ8kPkrI.d.ts.map +0 -1
  310. package/dist/cjs/api.d.ts.map +0 -1
  311. package/dist/cjs/cloneRouter-3AOUeQ8M.js +0 -2
  312. package/dist/cjs/cloneRouter-3AOUeQ8M.js.map +0 -1
  313. package/dist/cjs/index-CAnGQpnz.d.ts +0 -974
  314. package/dist/cjs/index-CAnGQpnz.d.ts.map +0 -1
  315. package/dist/cjs/index-DDrryY2U.d.ts +0 -309
  316. package/dist/cjs/index-DDrryY2U.d.ts.map +0 -1
  317. package/dist/cjs/index.d.ts.map +0 -1
  318. package/dist/cjs/types-DaXCTxi1.d.ts.map +0 -1
  319. package/dist/cjs/utils.d.ts +0 -2
  320. package/dist/cjs/utils.js +0 -2
  321. package/dist/cjs/utils.js.map +0 -1
  322. package/dist/cjs/validation.d.ts.map +0 -1
  323. package/dist/esm/Router-Cy75qbgU.d.mts.map +0 -1
  324. package/dist/esm/Router-DikzugaD.mjs +0 -2
  325. package/dist/esm/RouterValidator-CZ8kPkrI.d.mts.map +0 -1
  326. package/dist/esm/api.d.mts.map +0 -1
  327. package/dist/esm/cloneRouter-CAh5vA3l.mjs +0 -2
  328. package/dist/esm/cloneRouter-CAh5vA3l.mjs.map +0 -1
  329. package/dist/esm/index-CAnGQpnz.d.mts +0 -974
  330. package/dist/esm/index-CAnGQpnz.d.mts.map +0 -1
  331. package/dist/esm/index-DnSU6huX.d.mts +0 -309
  332. package/dist/esm/index-DnSU6huX.d.mts.map +0 -1
  333. package/dist/esm/index.d.mts.map +0 -1
  334. package/dist/esm/types-DaXCTxi1.d.mts.map +0 -1
  335. package/dist/esm/utils.d.mts +0 -2
  336. package/dist/esm/utils.mjs +0 -2
  337. package/dist/esm/utils.mjs.map +0 -1
  338. package/dist/esm/validation.d.mts.map +0 -1
@@ -0,0 +1,2 @@
1
+ const e=()=>!0,t=()=>!1,n=()=>e,r=()=>t;function i(e){return e?n:r}var a=class{#e=new Map;#t=new Map;#n=new Map;#r=new Map;#i=new Map;#a=new Map;#o=[this.#i,this.#a];#s;setDependencies(e){this.#s=e}getHandlerCount(e){let t=e===`activate`?this.#e:this.#n,n=e===`activate`?this.#t:this.#r;if(t.size===0)return n.size;if(n.size===0)return t.size;let r=new Set(t.keys());for(let e of n.keys())r.add(e);return r.size}preflightHandlerLimit(e,t,n){let r=this.#s.getValidator();if(!r)return;let i=(e,t,i)=>{let{definition:a,external:o}=this.#d(e),s=0;for(let e of t)(n?o.has(e):a.has(e)||o.has(e))||s++;if(s===0)return;let c=n?o.size:this.getHandlerCount(e);r.lifecycle.validateHandlerLimit(c+s-1,i)};i(`activate`,e,`canActivate`),i(`deactivate`,t,`canDeactivate`)}addCanActivate(e,t,n=!1,r){this.#c(`activate`,e,t,n,`canActivate`,r)}addCanDeactivate(e,t,n=!1,r){this.#c(`deactivate`,e,t,n,`canDeactivate`,r)}clearCanActivate(e,t){this.#l(`activate`,e,t)}clearCanDeactivate(e,t){this.#l(`deactivate`,e,t)}clearAll(){this.#e.clear(),this.#t.clear(),this.#n.clear(),this.#r.clear(),this.#a.clear(),this.#i.clear()}clearDefinitionGuards(){for(let e of this.#e.keys())this.#t.has(e)?this.#u(`activate`,e):this.#a.delete(e);for(let e of this.#n.keys())this.#r.has(e)?this.#u(`deactivate`,e):this.#i.delete(e);this.#e.clear(),this.#n.clear()}getFactories(){let e={},t={};for(let[t,n]of this.#n)e[t]=n;for(let[t,n]of this.#r)e[t]=n;for(let[e,n]of this.#e)t[e]=n;for(let[e,n]of this.#t)t[e]=n;return[e,t]}getFactoriesByOrigin(){let e={},t={},n={},r={};for(let[t,n]of this.#n)e[t]=n;for(let[e,n]of this.#e)t[e]=n;for(let[e,t]of this.#r)n[e]=t;for(let[e,t]of this.#t)r[e]=t;return{definition:[e,t],external:[n,r]}}getFunctions(){return this.#o}canNavigateTo(e,t,n,r){for(let t of e)if(!this.#f(this.#i,t,n,r,`canNavigateTo`))return!1;for(let e of t)if(!this.#f(this.#a,e,n,r,`canNavigateTo`))return!1;return!0}compileGuardFactory(e,t){let n=typeof e==`boolean`?i(e):e,r=this.#s.compileFactory(n);if(typeof r!=`function`)throw TypeError(`[router.${t}] Factory must return a function, got ${typeof r}`);return r}#c(e,t,n,r,a,o){let s=this.#d(e),c=e===`activate`?this.#a:this.#i,l=r?s.definition:s.external,u=r?s.external:s.definition;if(l.has(t)||u.has(t))this.#s.getValidator()?.lifecycle.warnOverwrite(t,e,a);else{let t=this.#s.getValidator();if(t){let n=this.getHandlerCount(e);t.lifecycle.validateHandlerLimit(n,a),t.lifecycle.validateCountThresholds(n+1,a)}}let d=typeof n==`boolean`?i(n):n,f=l.get(t);l.set(t,d);let p=r&&u.has(t);try{let e=o??this.compileGuardFactory(d,a);p||c.set(t,e)}catch(n){throw f===void 0?l.delete(t):l.set(t,f),this.#u(e,t),n}}#l(e,t,n){let{definition:r,external:i}=this.#d(e),a=n!==`external`&&r.delete(t),o=n!==`definition`&&i.delete(t);(a||o)&&this.#u(e,t)}#u(e,t){let n=this.#d(e),r=e===`activate`?this.#a:this.#i,i=n.external.get(t)??n.definition.get(t);if(!i){r.delete(t);return}try{let e=this.#s.compileFactory(i);if(typeof e!=`function`){r.delete(t);return}r.set(t,e)}catch{r.delete(t)}}#d(e){return e===`activate`?{definition:this.#e,external:this.#t}:{definition:this.#n,external:this.#r}}#f(e,t,n,r,i){let a=e.get(t);if(!a)return!0;try{let e=a(n,r);return typeof e==`boolean`?e:(this.#s.getValidator()?.lifecycle.warnAsyncGuardSync(t,i),!1)}catch(e){return this.#s.logger.warn(`router.${i}`,`Guard for "${t}" threw — treated as navigation-blocking (returned false)`,e),!1}}};exports.RouteLifecycleNamespace=a;
2
+ //# sourceMappingURL=RouteLifecycleNamespace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteLifecycleNamespace.js","names":["#definitionActivateFactories","#externalActivateFactories","#definitionDeactivateFactories","#externalDeactivateFactories","#canDeactivateFunctions","#canActivateFunctions","#functionsTuple","#deps","#getFactoryMaps","#registerHandler","#clearGuard","#recompileSlot","#checkGuardSync"],"sources":["../../../../src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts"],"sourcesContent":["// packages/core/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts\n\nimport type { RouteLifecycleDependencies } from \"./types\";\nimport type {\n DefaultDependencies,\n GuardFn,\n State,\n GuardFnFactory,\n} from \"../../types\";\n\n// Boolean shorthand has only two possible values, so the guard and its factory\n// are module-level singletons — registering `true`/`false` reuses one cached\n// factory instead of allocating a fresh closure per call (#962).\nconst TRUE_GUARD: GuardFn = () => true;\nconst FALSE_GUARD: GuardFn = () => false;\nconst TRUE_FACTORY: GuardFnFactory = () => TRUE_GUARD;\nconst FALSE_FACTORY: GuardFnFactory = () => FALSE_GUARD;\n\n/**\n * Converts a boolean value to a guard function factory.\n * Used for the shorthand syntax where true/false is passed instead of a function.\n * Returns one of two cached factories — no per-call allocation (#962).\n */\nfunction booleanToFactory<Dependencies extends DefaultDependencies>(\n value: boolean,\n): GuardFnFactory<Dependencies> {\n return value ? TRUE_FACTORY : FALSE_FACTORY;\n}\n\n/**\n * Origin lane for a guard clear. Every `clearCanActivate` / `clearCanDeactivate`\n * caller names its lane — there is no origin-blind default — so a new call site\n * cannot silently wipe both the route-config and the external guard (#1171):\n *\n * - `\"definition\"` — clear only the route-config guard (`update(name, {…: null})`, #952).\n * - `\"external\"` — clear only the external, component-managed guard\n * (`removeXGuard()` and post-leave auto-cleanup — the inverse of `addXGuard()`).\n * - `\"both\"` — clear both (route removal / router teardown; the route is gone).\n */\nexport type GuardClearScope = \"definition\" | \"external\" | \"both\";\n\n/**\n * Source of truth for `canActivate` / `canDeactivate` guards.\n *\n * Storage is split by origin into four factory Maps (definition vs external,\n * each ×activate/deactivate); a single compiled-function Map per kind backs\n * navigation (\"external wins\" — when a route holds both a definition and an\n * external guard, the compiled guard is the external one, regardless of\n * registration order; #1174). `getFunctions()` returns a cached\n * `[deactivate, activate]` tuple for the hot path (stable reference, no\n * per-navigate allocation).\n *\n * All input validation is handled upstream by `getLifecycleApi` and\n * `getRoutesApi` — this class has no static methods.\n *\n * **Ordering convention.** Every paired surface lists **deactivate before\n * activate**: `getFunctions()` / `getFactories()` return `[deactivate,\n * activate]`, `getFactoriesByOrigin()` returns that tuple per origin, and\n * `canNavigateTo(toDeactivate, toActivate, …)` takes deactivate first. Keep\n * any new paired surface consistent with this order.\n */\nexport class RouteLifecycleNamespace<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n> {\n // Storage split by origin: definition vs external. Resolution is\n // EXTERNAL-WINS regardless of registration order (#1174): the compiled slot\n // reflects the external factory whenever one exists, else the definition. One\n // policy across every path — `#registerHandler` (keeps external over a later\n // definition), `#recompileSlot`, and `clearDefinitionGuards` (#1192) — so a\n // clone's fixed definition→external replay yields the source's effective guard\n // with no extra tracking. Both semantics are expressed over these primary Maps.\n readonly #definitionActivateFactories = new Map<\n string,\n GuardFnFactory<Dependencies>\n >();\n readonly #externalActivateFactories = new Map<\n string,\n GuardFnFactory<Dependencies>\n >();\n readonly #definitionDeactivateFactories = new Map<\n string,\n GuardFnFactory<Dependencies>\n >();\n readonly #externalDeactivateFactories = new Map<\n string,\n GuardFnFactory<Dependencies>\n >();\n // Compiled-function view. Single Map per kind because navigation does not\n // distinguish origin — it just runs the effective guard. Set on add\n // (external-wins — a definition does not overwrite a live external, #1174)\n // and recompiled on clear from whichever origin Map still holds the slot.\n readonly #canDeactivateFunctions = new Map<string, GuardFn>();\n readonly #canActivateFunctions = new Map<string, GuardFn>();\n // Cached tuple — Maps never change reference, so this is stable\n readonly #functionsTuple: [Map<string, GuardFn>, Map<string, GuardFn>] = [\n this.#canDeactivateFunctions,\n this.#canActivateFunctions,\n ];\n\n #deps!: RouteLifecycleDependencies<Dependencies>;\n\n setDependencies(deps: RouteLifecycleDependencies<Dependencies>): void {\n this.#deps = deps;\n }\n\n getHandlerCount(type: \"activate\" | \"deactivate\"): number {\n const definitionMap =\n type === \"activate\"\n ? this.#definitionActivateFactories\n : this.#definitionDeactivateFactories;\n const externalMap =\n type === \"activate\"\n ? this.#externalActivateFactories\n : this.#externalDeactivateFactories;\n\n if (definitionMap.size === 0) {\n return externalMap.size;\n }\n\n if (externalMap.size === 0) {\n return definitionMap.size;\n }\n\n const names = new Set(definitionMap.keys());\n\n for (const name of externalMap.keys()) {\n names.add(name);\n }\n\n return names.size;\n }\n\n /**\n * Pre-flights the #961 handler-limit `RangeError` into the route-CRUD PREPARE\n * phase (#1046). `#registerHandler`'s per-slot limit check throws AFTER the\n * tree/config swap, so `add`/`replace`/`update` tore post-commit when the\n * validator was installed and the per-type count was at `maxLifecycleHandlers`.\n * Running the same check here — before any store mutation — restores atomicity\n * (#951/#956/#698): a batch that would exceed the limit aborts before a single\n * write.\n *\n * Only NEW slots count (an overwrite leaves the union count unchanged, mirroring\n * `#registerHandler`). For `replace` (`clearsDefinition = true`) the definition\n * guards are about to be cleared, so the projection runs against the surviving\n * EXTERNAL guards only — exactly the post-clear state the install loop sees.\n * Plugin-gated: a no-op without the validator (the limit is opt-in).\n *\n * @param activateNames - route names a `canActivate` would be registered for\n * @param deactivateNames - route names a `canDeactivate` would be registered for\n * @param clearsDefinition - true for `replace` (definition guards cleared first)\n */\n preflightHandlerLimit(\n activateNames: Iterable<string>,\n deactivateNames: Iterable<string>,\n clearsDefinition: boolean,\n ): void {\n const validator = this.#deps.getValidator();\n\n if (!validator) {\n return;\n }\n\n const check = (\n type: \"activate\" | \"deactivate\",\n names: Iterable<string>,\n methodName: string,\n ): void => {\n const { definition, external } = this.#getFactoryMaps(type);\n\n // A name already holding a guard of this type is an overwrite (no new\n // slot, mirroring `#registerHandler`). After a definition-clear (replace)\n // only EXTERNAL guards survive, so the existing-name check — and the base\n // count below — run against `external` alone, matching the post-clear\n // install state the loop sees.\n let newSlots = 0;\n\n for (const name of names) {\n const isExisting = clearsDefinition\n ? external.has(name)\n : definition.has(name) || external.has(name);\n\n if (!isExisting) {\n newSlots++;\n }\n }\n\n if (newSlots === 0) {\n return;\n }\n\n // The install loop throws when a new-slot registration observes\n // `count >= max`. Starting from `base` and adding `newSlots` new names,\n // the highest pre-register count it reaches is `base + newSlots - 1` —\n // replicate that worst case so the pre-flight throws iff the loop would.\n const base = clearsDefinition\n ? external.size\n : this.getHandlerCount(type);\n\n validator.lifecycle.validateHandlerLimit(base + newSlots - 1, methodName);\n };\n\n check(\"activate\", activateNames, \"canActivate\");\n check(\"deactivate\", deactivateNames, \"canDeactivate\");\n }\n\n // =========================================================================\n // Instance methods\n // =========================================================================\n\n /**\n * Adds a canActivate guard for a route.\n *\n * @param name - Route name (input-validated by facade)\n * @param handler - Guard function or boolean (input-validated by facade)\n * @param isFromDefinition - True when guard comes from route definition\n * (lands in the definition Map; subject to `clearDefinitionGuards()`).\n * False (default) when added via `getLifecycleApi().addActivateGuard(...)`\n * (lands in the external Map; survives `replace()`).\n *\n * External wins at runtime (#1174): when a route holds both a definition and\n * an external guard, the compiled function is the external one, regardless of\n * registration order. Within one origin the most recent add overwrites. Origin\n * determines which Map the factory is filed under (relevant for\n * `clearDefinitionGuards()` and `cloneRouter` re-registration).\n */\n addCanActivate(\n name: string,\n handler: GuardFnFactory<Dependencies> | boolean,\n isFromDefinition = false,\n precompiledFn?: GuardFn,\n ): void {\n this.#registerHandler(\n \"activate\",\n name,\n handler,\n isFromDefinition,\n \"canActivate\",\n precompiledFn,\n );\n }\n\n /**\n * Adds a canDeactivate guard for a route.\n *\n * Symmetric counterpart to {@link addCanActivate}.\n */\n addCanDeactivate(\n name: string,\n handler: GuardFnFactory<Dependencies> | boolean,\n isFromDefinition = false,\n precompiledFn?: GuardFn,\n ): void {\n this.#registerHandler(\n \"deactivate\",\n name,\n handler,\n isFromDefinition,\n \"canDeactivate\",\n precompiledFn,\n );\n }\n\n /**\n * Removes a canActivate guard for a route. `scope` names the origin lane\n * (see {@link GuardClearScope}) — there is no origin-blind default, so every\n * caller commits to a lane and a new call site cannot silently clear both.\n * Delegates to {@link #clearGuard} (mirrors the add side's `#registerHandler`).\n *\n * @param name - Route name (already validated by facade)\n * @param scope - Which origin(s) to clear: `\"definition\"` / `\"external\"` / `\"both\"`\n */\n clearCanActivate(name: string, scope: GuardClearScope): void {\n this.#clearGuard(\"activate\", name, scope);\n }\n\n /**\n * Removes a canDeactivate guard for a route. Symmetric counterpart to\n * {@link clearCanActivate}.\n *\n * The `\"external\"` lane is what makes a route-config `canDeactivate` durable:\n * post-leave auto-cleanup (`completeTransition`) and `removeDeactivateGuard()`\n * unregister only the external, component-managed guard (router5 mount/unmount\n * heritage), while a definition guard survives for re-entry — symmetric with\n * definition `canActivate`, which lives as long as the route is in the tree\n * (#1171). Clearing both by default made a config guard one-shot: the first\n * permitted leave erased it, so re-entry was unguarded, `getRoutesApi().get()`\n * lost the field, and a clone taken after the leave never received it\n * (clone invariant #6).\n *\n * @param name - Route name (already validated by facade)\n * @param scope - Which origin(s) to clear: `\"definition\"` / `\"external\"` / `\"both\"`\n */\n clearCanDeactivate(name: string, scope: GuardClearScope): void {\n this.#clearGuard(\"deactivate\", name, scope);\n }\n\n /**\n * Clears all lifecycle handlers (canActivate and canDeactivate).\n * Used by clearRoutes to reset all lifecycle state.\n */\n clearAll(): void {\n this.#definitionActivateFactories.clear();\n this.#externalActivateFactories.clear();\n this.#definitionDeactivateFactories.clear();\n this.#externalDeactivateFactories.clear();\n this.#canActivateFunctions.clear();\n this.#canDeactivateFunctions.clear();\n }\n\n /**\n * Clears only lifecycle handlers that were registered from route definitions.\n * Used by HMR `replace()` to remove definition-sourced guards without\n * touching externally-added guards.\n *\n * For a slot where BOTH a definition and an external guard exist, the external\n * factory survives — and the compiled function is RECOMPILED from it (#1192).\n * Under external-wins (#1174) the compiled slot is already the external guard,\n * so this recompile is idempotent — it re-derives the surviving external factory\n * through the same choke point that keeps clearing correct (and stays robust if\n * the compiled slot were ever out of sync). For a definition-only slot, the\n * compiled function is dropped.\n */\n clearDefinitionGuards(): void {\n for (const name of this.#definitionActivateFactories.keys()) {\n if (this.#externalActivateFactories.has(name)) {\n this.#recompileSlot(\"activate\", name);\n } else {\n this.#canActivateFunctions.delete(name);\n }\n }\n\n for (const name of this.#definitionDeactivateFactories.keys()) {\n if (this.#externalDeactivateFactories.has(name)) {\n this.#recompileSlot(\"deactivate\", name);\n } else {\n this.#canDeactivateFunctions.delete(name);\n }\n }\n\n this.#definitionActivateFactories.clear();\n this.#definitionDeactivateFactories.clear();\n }\n\n /**\n * Returns lifecycle factories as a flat `[deactivate, activate]` tuple of\n * `Record<name, factory>` — the effective view where external wins over\n * definition for the same slot. Used by `getRoutesApi` to enrich route\n * objects with their current canActivate / canDeactivate factories and by\n * the route-removal cleanup path.\n *\n * For cloneRouter (which needs to preserve origin on re-registration), use\n * {@link getFactoriesByOrigin} instead.\n */\n getFactories(): [\n Record<string, GuardFnFactory<Dependencies>>,\n Record<string, GuardFnFactory<Dependencies>>,\n ] {\n const deactivateRecord: Record<string, GuardFnFactory<Dependencies>> = {};\n const activateRecord: Record<string, GuardFnFactory<Dependencies>> = {};\n\n for (const [name, factory] of this.#definitionDeactivateFactories) {\n deactivateRecord[name] = factory;\n }\n for (const [name, factory] of this.#externalDeactivateFactories) {\n deactivateRecord[name] = factory;\n }\n\n for (const [name, factory] of this.#definitionActivateFactories) {\n activateRecord[name] = factory;\n }\n for (const [name, factory] of this.#externalActivateFactories) {\n activateRecord[name] = factory;\n }\n\n return [deactivateRecord, activateRecord];\n }\n\n /**\n * Returns factories tagged by origin — definition and external as separate\n * `[deactivate, activate]` tuples. Used by `cloneRouter` to re-register\n * guards on the clone with their original origin flag preserved.\n */\n getFactoriesByOrigin(): {\n definition: [\n Record<string, GuardFnFactory<Dependencies>>,\n Record<string, GuardFnFactory<Dependencies>>,\n ];\n external: [\n Record<string, GuardFnFactory<Dependencies>>,\n Record<string, GuardFnFactory<Dependencies>>,\n ];\n } {\n const defDeact: Record<string, GuardFnFactory<Dependencies>> = {};\n const defAct: Record<string, GuardFnFactory<Dependencies>> = {};\n const extensionDeact: Record<string, GuardFnFactory<Dependencies>> = {};\n const extensionAct: Record<string, GuardFnFactory<Dependencies>> = {};\n\n for (const [name, factory] of this.#definitionDeactivateFactories) {\n defDeact[name] = factory;\n }\n for (const [name, factory] of this.#definitionActivateFactories) {\n defAct[name] = factory;\n }\n for (const [name, factory] of this.#externalDeactivateFactories) {\n extensionDeact[name] = factory;\n }\n for (const [name, factory] of this.#externalActivateFactories) {\n extensionAct[name] = factory;\n }\n\n return {\n definition: [defDeact, defAct],\n external: [extensionDeact, extensionAct],\n };\n }\n\n /**\n * Returns compiled lifecycle functions for transition execution.\n *\n * @returns Tuple of [canDeactivateFunctions, canActivateFunctions] as Maps\n */\n getFunctions(): [Map<string, GuardFn>, Map<string, GuardFn>] {\n return this.#functionsTuple;\n }\n\n canNavigateTo(\n toDeactivate: string[],\n toActivate: string[],\n toState: State,\n fromState: State | undefined,\n ): boolean {\n for (const segment of toDeactivate) {\n if (\n !this.#checkGuardSync(\n this.#canDeactivateFunctions,\n segment,\n toState,\n fromState,\n \"canNavigateTo\",\n )\n ) {\n return false;\n }\n }\n\n for (const segment of toActivate) {\n if (\n !this.#checkGuardSync(\n this.#canActivateFunctions,\n segment,\n toState,\n fromState,\n \"canNavigateTo\",\n )\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Compiles a guard factory to its `GuardFn` WITHOUT registering it — surfaces\n * a throwing / non-function factory eagerly. The prepare-then-commit\n * add/replace path (`adoptRouteArtifacts`) calls this for every pending guard\n * BEFORE the store swap (#956), so a malformed factory aborts the mutation\n * with the store untouched. The returned function is then installed via the\n * `precompiledFn` argument of {@link addCanActivate} / {@link addCanDeactivate}\n * — no re-compile, so a factory with compile-time side effects runs exactly\n * once. Same boolean-shorthand handling + compile + non-function check as the\n * inline `#registerHandler` path, so a route-config `canActivate: true`\n * (boolean shorthand, runtime-reachable via the public route type) compiles to\n * the cached `TRUE_GUARD`/`FALSE_GUARD` instead of throwing on a non-callable.\n */\n compileGuardFactory(\n handler: GuardFnFactory<Dependencies> | boolean,\n methodName: string,\n ): GuardFn {\n const factory =\n typeof handler === \"boolean\"\n ? booleanToFactory<Dependencies>(handler)\n : handler;\n const fn = this.#deps.compileFactory(factory);\n\n if (typeof fn !== \"function\") {\n throw new TypeError(\n `[router.${methodName}] Factory must return a function, got ${typeof fn}`,\n );\n }\n\n return fn;\n }\n\n // =========================================================================\n // Private methods (business logic)\n // =========================================================================\n\n /**\n * Routes a registration into the origin-specific factory Map and updates the\n * compiled function under EXTERNAL-WINS (#1174): the just-added factory becomes\n * the compiled guard unless it is a definition registered while an external\n * guard is already live (then external stays effective; the definition is still\n * stored for a later `clearDefinitionGuards()`). Within one origin the most\n * recent add overwrites.\n * Emits overwrite / threshold warnings symmetric with the pre-refactor\n * single-Map behaviour: any prior entry for the slot — same origin or\n * cross-origin — counts as an overwrite for the warning surface; only a\n * brand-new slot (no entry in either Map) increments the threshold check.\n */\n #registerHandler(\n type: \"activate\" | \"deactivate\",\n name: string,\n handler: GuardFnFactory<Dependencies> | boolean,\n isFromDefinition: boolean,\n methodName: string,\n precompiledFn?: GuardFn,\n ): void {\n const factoryMaps = this.#getFactoryMaps(type);\n const functions =\n type === \"activate\"\n ? this.#canActivateFunctions\n : this.#canDeactivateFunctions;\n const targetMap = isFromDefinition\n ? factoryMaps.definition\n : factoryMaps.external;\n const otherMap = isFromDefinition\n ? factoryMaps.external\n : factoryMaps.definition;\n\n const isOverwrite = targetMap.has(name) || otherMap.has(name);\n\n if (isOverwrite) {\n this.#deps\n .getValidator()\n ?.lifecycle.warnOverwrite(name, type, methodName);\n } else {\n // Single enforcement choke point for EVERY registration path: programmatic\n // (getLifecycleApi) and route-config (getRoutesApi.add/update, where\n // isFromDefinition=true). The hard limit throws here so route-config guards\n // are bounded exactly like programmatic ones (#961); the approaching-limit\n // warning follows. Only new slots count toward the limit — an overwrite\n // leaves the count unchanged. `getHandlerCount` is read once and only when\n // the validator is installed (opt-in), so the no-plugin path stays free.\n const validator = this.#deps.getValidator();\n\n if (validator) {\n const count = this.getHandlerCount(type);\n\n validator.lifecycle.validateHandlerLimit(count, methodName);\n validator.lifecycle.validateCountThresholds(count + 1, methodName);\n }\n }\n\n const factory =\n typeof handler === \"boolean\"\n ? booleanToFactory<Dependencies>(handler)\n : handler;\n\n // Capture the slot's prior factory (if any) BEFORE the overwrite, so a\n // compile-throw can be rolled back to the previously-valid guard rather\n // than dropping it (#963).\n const previousFactory = targetMap.get(name);\n\n targetMap.set(name, factory);\n\n // External-wins (#1174): the compiled slot reflects the external guard\n // whenever one exists, regardless of registration order. A definition\n // registered while an external guard is live is still stored (so a later\n // replace()-clear can recompile from it via `#recompileSlot`) but does NOT\n // overwrite the compiled function — external stays effective. This makes\n // `#registerHandler` consistent with `#recompileSlot` / `clearDefinitionGuards`\n // (both external-wins, #1192), so the whole namespace has ONE policy, and\n // cloneRouter's fixed definition→external replay yields the same effective\n // guard as the source with no extra origin tracking. (The factory is still\n // compiled below to validate it and to keep the rollback path symmetric.)\n const externalWins = isFromDefinition && otherMap.has(name);\n\n try {\n // A pre-validated function (from the #956 add/replace pre-compile) is\n // installed directly — no re-compile; otherwise compile + non-function\n // check here (`compileGuardFactory` throws on a bad factory).\n const fn = precompiledFn ?? this.compileGuardFactory(factory, methodName);\n\n if (!externalWins) {\n functions.set(name, fn);\n }\n } catch (error) {\n // Roll the slot back to its pre-call state: restore the previous factory\n // on an overwrite (#963), else clear the slot. `#recompileSlot` then\n // resets the compiled function from whichever origin Map still holds an\n // entry — the restored same-origin factory, a surviving cross-origin one,\n // or (empty slot) deletes the compiled function.\n if (previousFactory === undefined) {\n targetMap.delete(name);\n } else {\n targetMap.set(name, previousFactory);\n }\n\n this.#recompileSlot(type, name);\n\n throw error;\n }\n }\n\n /**\n * Shared implementation for {@link clearCanActivate} / {@link clearCanDeactivate}\n * — the clear-side counterpart to {@link #registerHandler}. `scope` selects the\n * origin lane (no origin-blind default, #1171); when one origin is cleared and\n * the other survives, `#recompileSlot` recompiles the compiled function from\n * the survivor (external wins, #1174).\n */\n #clearGuard(\n type: \"activate\" | \"deactivate\",\n name: string,\n scope: GuardClearScope,\n ): void {\n const { definition, external } = this.#getFactoryMaps(type);\n const clearedDefinition =\n scope === \"external\" ? false : definition.delete(name);\n const clearedExternal =\n scope === \"definition\" ? false : external.delete(name);\n\n if (clearedDefinition || clearedExternal) {\n this.#recompileSlot(type, name);\n }\n }\n\n /**\n * Recompiles the compiled-function slot from whichever origin Map still has\n * an entry for `name` after a clear. External wins over definition; if\n * neither has an entry, the compiled function is deleted.\n */\n #recompileSlot(type: \"activate\" | \"deactivate\", name: string): void {\n const factoryMaps = this.#getFactoryMaps(type);\n const functions =\n type === \"activate\"\n ? this.#canActivateFunctions\n : this.#canDeactivateFunctions;\n\n const effective =\n factoryMaps.external.get(name) ?? factoryMaps.definition.get(name);\n\n if (!effective) {\n functions.delete(name);\n\n return;\n }\n\n try {\n const fn = this.#deps.compileFactory(effective);\n\n /* v8 ignore next 4 -- @preserve: stored factories were validated at add time, compileFactory should yield a function on second call too */\n if (typeof fn !== \"function\") {\n functions.delete(name);\n\n return;\n }\n\n functions.set(name, fn);\n } catch {\n /* v8 ignore next 2 -- @preserve: defensive — a user-provided factory could theoretically throw on re-compile (state changed since add time); deleting the function blocks navigation on that slot */\n functions.delete(name);\n }\n }\n\n #getFactoryMaps(type: \"activate\" | \"deactivate\"): {\n definition: Map<string, GuardFnFactory<Dependencies>>;\n external: Map<string, GuardFnFactory<Dependencies>>;\n } {\n return type === \"activate\"\n ? {\n definition: this.#definitionActivateFactories,\n external: this.#externalActivateFactories,\n }\n : {\n definition: this.#definitionDeactivateFactories,\n external: this.#externalDeactivateFactories,\n };\n }\n\n /**\n * Shared implementation for synchronous guard checks.\n * Warns if a guard returns a Promise (async guards are not supported in sync mode).\n * Catches exceptions and treats them as navigation-blocking (`false`).\n *\n * @param functions - Map of compiled guard functions to look up\n * @param name - Route name to check the guard for\n * @param toState - Target navigation state\n * @param fromState - Current state (`undefined` on initial navigation)\n * @param methodName - Public API method name for warning messages\n */\n #checkGuardSync(\n functions: Map<string, GuardFn>,\n name: string,\n toState: State,\n fromState: State | undefined,\n methodName: string,\n ): boolean {\n const guardFn = functions.get(name);\n\n if (!guardFn) {\n return true;\n }\n\n try {\n const result = guardFn(toState, fromState);\n\n if (typeof result === \"boolean\") {\n return result;\n }\n\n this.#deps.getValidator()?.lifecycle.warnAsyncGuardSync(name, methodName);\n\n return false;\n } catch (error) {\n // #959: a throwing sync guard must not vanish silently. `navigate()`\n // surfaces the same throw via `handleGuardError` → TRANSITION_ERROR; the\n // sync predicate (`canNavigateTo`) has no error channel, so core logs it\n // directly. This is an OPERATIONAL signal (the guard crashed — distinct\n // from the opt-in validator DX warnings above for which the validator is\n // the right home): the navigation is still treated as blocked (`false`).\n this.#deps.logger.warn(\n `router.${methodName}`,\n `Guard for \"${name}\" threw — treated as navigation-blocking (returned false)`,\n error,\n );\n\n return false;\n }\n }\n}\n"],"mappings":"AAaA,MAAM,MAA4B,GAC5B,MAA6B,GAC7B,MAAqC,EACrC,MAAsC,EAO5C,SAAS,EACP,EAC8B,CAC9B,OAAO,EAAQ,EAAe,CAChC,CAkCA,IAAa,EAAb,KAEE,CAQA,GAAwC,IAAI,IAI5C,GAAsC,IAAI,IAI1C,GAA0C,IAAI,IAI9C,GAAwC,IAAI,IAQ5C,GAAmC,IAAI,IACvC,GAAiC,IAAI,IAErC,GAAyE,CACvE,KAAKI,GACL,KAAKC,EACP,EAEA,GAEA,gBAAgB,EAAsD,CACpE,KAAKE,GAAQ,CACf,CAEA,gBAAgB,EAAyC,CACvD,IAAM,EACJ,IAAS,WACL,KAAKP,GACL,KAAKE,GACL,EACJ,IAAS,WACL,KAAKD,GACL,KAAKE,GAEX,GAAI,EAAc,OAAS,EACzB,OAAO,EAAY,KAGrB,GAAI,EAAY,OAAS,EACvB,OAAO,EAAc,KAGvB,IAAM,EAAQ,IAAI,IAAI,EAAc,KAAK,CAAC,EAE1C,IAAK,IAAM,KAAQ,EAAY,KAAK,EAClC,EAAM,IAAI,CAAI,EAGhB,OAAO,EAAM,IACf,CAqBA,sBACE,EACA,EACA,EACM,CACN,IAAM,EAAY,KAAKI,GAAM,aAAa,EAE1C,GAAI,CAAC,EACH,OAGF,IAAM,GACJ,EACA,EACA,IACS,CACT,GAAM,CAAE,aAAY,YAAa,KAAKC,GAAgB,CAAI,EAOtD,EAAW,EAEf,IAAK,IAAM,KAAQ,GACE,EACf,EAAS,IAAI,CAAI,EACjB,EAAW,IAAI,CAAI,GAAK,EAAS,IAAI,CAAI,IAG3C,IAIJ,GAAI,IAAa,EACf,OAOF,IAAM,EAAO,EACT,EAAS,KACT,KAAK,gBAAgB,CAAI,EAE7B,EAAU,UAAU,qBAAqB,EAAO,EAAW,EAAG,CAAU,CAC1E,EAEA,EAAM,WAAY,EAAe,aAAa,EAC9C,EAAM,aAAc,EAAiB,eAAe,CACtD,CAsBA,eACE,EACA,EACA,EAAmB,GACnB,EACM,CACN,KAAKC,GACH,WACA,EACA,EACA,EACA,cACA,CACF,CACF,CAOA,iBACE,EACA,EACA,EAAmB,GACnB,EACM,CACN,KAAKA,GACH,aACA,EACA,EACA,EACA,gBACA,CACF,CACF,CAWA,iBAAiB,EAAc,EAA8B,CAC3D,KAAKC,GAAY,WAAY,EAAM,CAAK,CAC1C,CAmBA,mBAAmB,EAAc,EAA8B,CAC7D,KAAKA,GAAY,aAAc,EAAM,CAAK,CAC5C,CAMA,UAAiB,CACf,KAAKV,GAA6B,MAAM,EACxC,KAAKC,GAA2B,MAAM,EACtC,KAAKC,GAA+B,MAAM,EAC1C,KAAKC,GAA6B,MAAM,EACxC,KAAKE,GAAsB,MAAM,EACjC,KAAKD,GAAwB,MAAM,CACrC,CAeA,uBAA8B,CAC5B,IAAK,IAAM,KAAQ,KAAKJ,GAA6B,KAAK,EACpD,KAAKC,GAA2B,IAAI,CAAI,EAC1C,KAAKU,GAAe,WAAY,CAAI,EAEpC,KAAKN,GAAsB,OAAO,CAAI,EAI1C,IAAK,IAAM,KAAQ,KAAKH,GAA+B,KAAK,EACtD,KAAKC,GAA6B,IAAI,CAAI,EAC5C,KAAKQ,GAAe,aAAc,CAAI,EAEtC,KAAKP,GAAwB,OAAO,CAAI,EAI5C,KAAKJ,GAA6B,MAAM,EACxC,KAAKE,GAA+B,MAAM,CAC5C,CAYA,cAGE,CACA,IAAM,EAAiE,CAAC,EAClE,EAA+D,CAAC,EAEtE,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKA,GACjC,EAAiB,GAAQ,EAE3B,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKC,GACjC,EAAiB,GAAQ,EAG3B,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKH,GACjC,EAAe,GAAQ,EAEzB,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKC,GACjC,EAAe,GAAQ,EAGzB,MAAO,CAAC,EAAkB,CAAc,CAC1C,CAOA,sBASE,CACA,IAAM,EAAyD,CAAC,EAC1D,EAAuD,CAAC,EACxD,EAA+D,CAAC,EAChE,EAA6D,CAAC,EAEpE,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKC,GACjC,EAAS,GAAQ,EAEnB,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKF,GACjC,EAAO,GAAQ,EAEjB,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKG,GACjC,EAAe,GAAQ,EAEzB,IAAK,GAAM,CAAC,EAAM,KAAY,KAAKF,GACjC,EAAa,GAAQ,EAGvB,MAAO,CACL,WAAY,CAAC,EAAU,CAAM,EAC7B,SAAU,CAAC,EAAgB,CAAY,CACzC,CACF,CAOA,cAA6D,CAC3D,OAAO,KAAKK,EACd,CAEA,cACE,EACA,EACA,EACA,EACS,CACT,IAAK,IAAM,KAAW,EACpB,GACE,CAAC,KAAKM,GACJ,KAAKR,GACL,EACA,EACA,EACA,eACF,EAEA,MAAO,GAIX,IAAK,IAAM,KAAW,EACpB,GACE,CAAC,KAAKQ,GACJ,KAAKP,GACL,EACA,EACA,EACA,eACF,EAEA,MAAO,GAIX,MAAO,EACT,CAeA,oBACE,EACA,EACS,CACT,IAAM,EACJ,OAAO,GAAY,UACf,EAA+B,CAAO,EACtC,EACA,EAAK,KAAKE,GAAM,eAAe,CAAO,EAE5C,GAAI,OAAO,GAAO,WAChB,MAAU,UACR,WAAW,EAAW,wCAAwC,OAAO,GACvE,EAGF,OAAO,CACT,CAkBA,GACE,EACA,EACA,EACA,EACA,EACA,EACM,CACN,IAAM,EAAc,KAAKC,GAAgB,CAAI,EACvC,EACJ,IAAS,WACL,KAAKH,GACL,KAAKD,GACL,EAAY,EACd,EAAY,WACZ,EAAY,SACV,EAAW,EACb,EAAY,SACZ,EAAY,WAIhB,GAFoB,EAAU,IAAI,CAAI,GAAK,EAAS,IAAI,CAAI,EAG1D,KAAKG,GACF,aAAa,CAAC,EACb,UAAU,cAAc,EAAM,EAAM,CAAU,MAC7C,CAQL,IAAM,EAAY,KAAKA,GAAM,aAAa,EAE1C,GAAI,EAAW,CACb,IAAM,EAAQ,KAAK,gBAAgB,CAAI,EAEvC,EAAU,UAAU,qBAAqB,EAAO,CAAU,EAC1D,EAAU,UAAU,wBAAwB,EAAQ,EAAG,CAAU,CACnE,CACF,CAEA,IAAM,EACJ,OAAO,GAAY,UACf,EAA+B,CAAO,EACtC,EAKA,EAAkB,EAAU,IAAI,CAAI,EAE1C,EAAU,IAAI,EAAM,CAAO,EAY3B,IAAM,EAAe,GAAoB,EAAS,IAAI,CAAI,EAE1D,GAAI,CAIF,IAAM,EAAK,GAAiB,KAAK,oBAAoB,EAAS,CAAU,EAEnE,GACH,EAAU,IAAI,EAAM,CAAE,CAE1B,OAAS,EAAO,CAcd,MARI,IAAoB,IAAA,GACtB,EAAU,OAAO,CAAI,EAErB,EAAU,IAAI,EAAM,CAAe,EAGrC,KAAKI,GAAe,EAAM,CAAI,EAExB,CACR,CACF,CASA,GACE,EACA,EACA,EACM,CACN,GAAM,CAAE,aAAY,YAAa,KAAKH,GAAgB,CAAI,EACpD,EACJ,IAAU,YAAqB,EAAW,OAAO,CAAI,EACjD,EACJ,IAAU,cAAuB,EAAS,OAAO,CAAI,GAEnD,GAAqB,IACvB,KAAKG,GAAe,EAAM,CAAI,CAElC,CAOA,GAAe,EAAiC,EAAoB,CAClE,IAAM,EAAc,KAAKH,GAAgB,CAAI,EACvC,EACJ,IAAS,WACL,KAAKH,GACL,KAAKD,GAEL,EACJ,EAAY,SAAS,IAAI,CAAI,GAAK,EAAY,WAAW,IAAI,CAAI,EAEnE,GAAI,CAAC,EAAW,CACd,EAAU,OAAO,CAAI,EAErB,MACF,CAEA,GAAI,CACF,IAAM,EAAK,KAAKG,GAAM,eAAe,CAAS,EAG9C,GAAI,OAAO,GAAO,WAAY,CAC5B,EAAU,OAAO,CAAI,EAErB,MACF,CAEA,EAAU,IAAI,EAAM,CAAE,CACxB,MAAQ,CAEN,EAAU,OAAO,CAAI,CACvB,CACF,CAEA,GAAgB,EAGd,CACA,OAAO,IAAS,WACZ,CACE,WAAY,KAAKP,GACjB,SAAU,KAAKC,EACjB,EACA,CACE,WAAY,KAAKC,GACjB,SAAU,KAAKC,EACjB,CACN,CAaA,GACE,EACA,EACA,EACA,EACA,EACS,CACT,IAAM,EAAU,EAAU,IAAI,CAAI,EAElC,GAAI,CAAC,EACH,MAAO,GAGT,GAAI,CACF,IAAM,EAAS,EAAQ,EAAS,CAAS,EAQzC,OANI,OAAO,GAAW,UACb,GAGT,KAAKI,GAAM,aAAa,CAAC,EAAE,UAAU,mBAAmB,EAAM,CAAU,EAEjE,GACT,OAAS,EAAO,CAad,OANA,KAAKA,GAAM,OAAO,KAChB,UAAU,IACV,cAAc,EAAK,2DACnB,CACF,EAEO,EACT,CACF,CACF"}
@@ -0,0 +1,17 @@
1
+ import { DefaultDependencies, GuardFn, GuardFnFactory, RouterLogger } from "../../types/router.js";
2
+ import { RouterValidator } from "../../types/RouterValidator.js";
3
+ //#region src/namespaces/RouteLifecycleNamespace/types.d.ts
4
+ interface RouteLifecycleDependencies<Dependencies extends DefaultDependencies = DefaultDependencies> {
5
+ /** Per-router logger instance (from `getInternals(router).logger`) */
6
+ logger: RouterLogger;
7
+ compileFactory: (factory: GuardFnFactory<Dependencies>) => GuardFn;
8
+ /**
9
+ * Returns the opt-in DX validator, or `null` when no validation-plugin is
10
+ * installed. A plain deps field (#1331) — internals are registered before
11
+ * wiring, so `getInternals(router)` never throws and no try/catch is needed.
12
+ */
13
+ getValidator: () => RouterValidator | null;
14
+ }
15
+ //#endregion
16
+ export { RouteLifecycleDependencies };
17
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/namespaces/RouteLifecycleNamespace/types.ts"],"mappings":";;;UAUiB,2BACf,qBAAqB,sBAAsB;;EAG3C,QAAQ;EAER,iBAAiB,SAAS,eAAe,kBAAkB;;;;;;EAM3D,oBAAoB"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../constants.js"),t=require("../../RouterError.js"),n=Object.freeze({replace:!0});var r=class{#e;setDependencies(e){this.#e=e}async start(r){let i=this.#e;if(i.isIdle())throw new t.RouterError(e.errorCodes.TRANSITION_CANCELLED);let a=i.getOptions();if(typeof r!=`string`)throw TypeError(`[router.start] path must be a string, got ${typeof r}`);let o=i.matchPath(r);if(!o&&!a.allowNotFound){let n=new t.RouterError(e.errorCodes.ROUTE_NOT_FOUND,{path:r});throw i.emitTransitionError(void 0,void 0,n),n}return i.completeStart(),o?i.navigateToState(o,n):i.navigateToNotFound(r)}stop(){this.#e.clearState()}};exports.RouterLifecycleNamespace=r;
2
+ //# sourceMappingURL=RouterLifecycleNamespace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterLifecycleNamespace.js","names":["#deps","RouterError","errorCodes"],"sources":["../../../../src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts"],"sourcesContent":["// packages/core/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts\n\nimport { errorCodes } from \"../../constants\";\nimport { RouterError } from \"../../RouterError\";\n\nimport type { RouterLifecycleDependencies } from \"./types\";\nimport type { NavigationOptions, State } from \"../../types\";\n\nconst REPLACE_OPTS: NavigationOptions = Object.freeze({ replace: true });\n\n/**\n * Independent namespace for managing router lifecycle.\n *\n * Handles start() and stop(). Lifecycle state (isActive, isStarted) is managed\n * by RouterFSM in the facade (Router.ts).\n */\nexport class RouterLifecycleNamespace {\n #deps!: RouterLifecycleDependencies;\n\n // =========================================================================\n // Dependency injection\n // =========================================================================\n\n /**\n * Sets dependencies for lifecycle operations.\n * Must be called before using lifecycle methods.\n */\n setDependencies(deps: RouterLifecycleDependencies): void {\n this.#deps = deps;\n }\n\n // =========================================================================\n // Instance methods\n // =========================================================================\n\n /**\n * Starts the router with the given path.\n *\n * Guards (concurrent start, already started) are handled by the facade via\n * RouterFSM state checks before this method is called.\n */\n async start(startPath: string): Promise<State> {\n const deps = this.#deps;\n\n // #1185: this method is the start-interceptor target — it runs AFTER the\n // whole interceptor chain. A stop() during that window sent STOP\n // (STARTING → IDLE via the FSM table), so if the router is back at IDLE the\n // start was cancelled mid-window; reject instead of committing a state on a\n // stopped router (mirrors the guard phase, which cancels from\n // TRANSITION_STARTED). `isIdle()` is deliberate — a dispose() mid-window\n // leaves the FSM DISPOSED, which the navigateToState / navigateToNotFound\n // liveness gate rejects as ROUTER_DISPOSED (#1186), not conflated with a\n // cancel.\n if (deps.isIdle()) {\n throw new RouterError(errorCodes.TRANSITION_CANCELLED);\n }\n\n const options = deps.getOptions();\n\n // Invariant guard (#939): core is platform-agnostic, so the caller must\n // provide a string path. Without a browser-plugin start interceptor to\n // inject a location, a non-string `startPath` (e.g. `start(undefined)`)\n // would otherwise reach matchPath() and throw a cryptic, code-less\n // `TypeError: …codePointAt` deep inside path-matcher. This guard runs AFTER\n // the interceptor chain (browser-plugin substitutes the location upstream),\n // so it only fires when nothing supplied a path — turning the cryptic crash\n // into an actionable error. Symmetric with the subscribe / navigateToNotFound\n // type guards; the validator deliberately permits `undefined` at the facade\n // for exactly the browser-plugin-override case.\n if (typeof startPath !== \"string\") {\n throw new TypeError(\n `[router.start] path must be a string, got ${typeof startPath}`,\n );\n }\n\n const matchedState = deps.matchPath(startPath);\n\n if (!matchedState && !options.allowNotFound) {\n const err = new RouterError(errorCodes.ROUTE_NOT_FOUND, {\n path: startPath,\n });\n\n deps.emitTransitionError(undefined, undefined, err);\n\n throw err;\n }\n\n deps.completeStart();\n\n if (matchedState) {\n // navigateToState commits matchedState verbatim — same primitive URL\n // plugins use on popstate / navigate-event (#525). Keeps trailing-slash\n // and any other source-URL flavor that matchPath produced; skips the\n // redundant forwardState+buildPath round-trip in buildNavigateState.\n return deps.navigateToState(matchedState, REPLACE_OPTS);\n }\n\n return deps.navigateToNotFound(startPath);\n }\n\n /**\n * Stops the router and resets state.\n *\n * Called for READY / TRANSITION_STARTED and, since #1185, STARTING (a stop()\n * that cancels a parked start — state is still `undefined` there, so\n * `clearState()` is a no-op that keeps the reset symmetric). The facade\n * handles IDLE / DISPOSED.\n */\n stop(): void {\n this.#deps.clearState();\n }\n}\n"],"mappings":"wEAQM,EAAkC,OAAO,OAAO,CAAE,QAAS,EAAK,CAAC,EAQvE,IAAa,EAAb,KAAsC,CACpC,GAUA,gBAAgB,EAAyC,CACvD,KAAKA,GAAQ,CACf,CAYA,MAAM,MAAM,EAAmC,CAC7C,IAAM,EAAO,KAAKA,GAWlB,GAAI,EAAK,OAAO,EACd,MAAM,IAAIC,EAAAA,YAAYC,EAAAA,WAAW,oBAAoB,EAGvD,IAAM,EAAU,EAAK,WAAW,EAYhC,GAAI,OAAO,GAAc,SACvB,MAAU,UACR,6CAA6C,OAAO,GACtD,EAGF,IAAM,EAAe,EAAK,UAAU,CAAS,EAE7C,GAAI,CAAC,GAAgB,CAAC,EAAQ,cAAe,CAC3C,IAAM,EAAM,IAAID,EAAAA,YAAYC,EAAAA,WAAW,gBAAiB,CACtD,KAAM,CACR,CAAC,EAID,MAFA,EAAK,oBAAoB,IAAA,GAAW,IAAA,GAAW,CAAG,EAE5C,CACR,CAYA,OAVA,EAAK,cAAc,EAEf,EAKK,EAAK,gBAAgB,EAAc,CAAY,EAGjD,EAAK,mBAAmB,CAAS,CAC1C,CAUA,MAAa,CACX,KAAKF,GAAM,WAAW,CACxB,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../constants.js"),t=new(require("../../RouterError.js")).RouterError(e.errorCodes.ROUTER_ALREADY_STARTED);exports.CACHED_ALREADY_STARTED_ERROR=t;
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","names":["RouterError","errorCodes"],"sources":["../../../../src/namespaces/RouterLifecycleNamespace/constants.ts"],"sourcesContent":["// packages/core/src/namespaces/RouterLifecycleNamespace/constants.ts\n\nimport { errorCodes } from \"../../constants\";\nimport { RouterError } from \"../../RouterError\";\n\n// =============================================================================\n// Cached Errors (Performance Optimization)\n// =============================================================================\n// Pre-create error instances to avoid object allocation on hot paths.\n// Error creation involves: new object, stack trace capture (~500ns-2μs).\n// Cached errors skip this overhead entirely.\n//\n// Trade-off: All error instances share the same stack trace (points here).\n// This is acceptable because:\n// 1. These errors indicate user misconfiguration, not internal bugs\n// 2. Error code and message are sufficient for debugging\n// 3. Performance gain (~80% for error paths) outweighs stack trace loss\n// =============================================================================\n\n/**\n * Cached error for start() called when router is already started/starting.\n */\nexport const CACHED_ALREADY_STARTED_ERROR = new RouterError(\n errorCodes.ROUTER_ALREADY_STARTED,\n);\n"],"mappings":"sCAsBa,EAA+B,kCAAIA,EAAAA,CAAAA,YAC9CC,EAAAA,WAAW,sBACb"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../constants.js"),t=require("./helpers.js"),n=require("./routesStore.js"),r=require("../../transitionPath.js");function i(e){let t=[];for(let n of e)for(let e of n.paramMeta.urlParams)t.push(e);return t}function a(e,t){return{name:t??e.segments.at(-1).fullName,params:e.params,meta:e.meta}}var o=class{#e;#t;#n;get#r(){return this.#e.depsStore}constructor(e,t,r){this.#e=n.createRoutesStore(e,t,r)}static shouldUpdateNode(e){return(t,n)=>{if(!(t&&typeof t==`object`&&`name`in t))throw TypeError(`[router.shouldUpdateNode] toState must be valid State object`);if(t.transition.reload||e===``)return!0;let{intersection:i,toActivate:a,toDeactivate:o}=r.getTransitionPath(t,n);return e===i||a.includes(e)?!0:o.includes(e)}}setDependencies(e){this.#e.depsStore=e}flushPendingGuards(){let e=this.#r;for(let[t,n]of this.#e.pendingCanActivate)e.addActivateGuard(t,n);this.#e.pendingCanActivate.clear();for(let[t,n]of this.#e.pendingCanDeactivate)e.addDeactivateGuard(t,n);this.#e.pendingCanDeactivate.clear()}setLifecycleNamespace(e){this.#e.lifecycleNamespace=e}setRootPath(e){this.#e.rootPath=e,n.rebuildTreeInPlace(this.#e)}hasRoute(e){return this.#e.matcher.hasRoute(e)}clearRoutes(){n.resetStore(this.#e)}buildPath(t,n,r){if(t===e.constants.UNKNOWN_ROUTE)return typeof n?.path==`string`?n.path:``;let i=Object.hasOwn(this.#e.config.defaultParams,t)?{...this.#e.config.defaultParams[t],...n}:n??{},a=typeof this.#e.config.encoders[t]==`function`?this.#e.config.encoders[t]({...i}):i;return this.#e.matcher.buildPath(t,a,this.#a(r))}matchPath(e,n){let r=n,i=this.#e.matcher.match(e);if(!i)return;let{name:o,params:s,meta:c}=a(i),l=typeof this.#e.config.decoders[o]==`function`?this.#e.config.decoders[o](s):s,{name:u,params:d}=this.#r.forwardState(o,l),f=e;if(r.rewritePathOnMatch){let n=typeof this.#e.config.encoders[u]==`function`?this.#e.config.encoders[u]({...d}):d,i=r.trailingSlash;try{f=this.#e.matcher.buildPath(u,n,{trailingSlash:i===`never`||i===`always`?i:void 0,queryParamsMode:r.queryParamsMode}),i===`preserve`&&(f=t.matchSourceTrailingSlash(e,f))}catch{f=e}}return this.#r.makeState(u,d,f,c)}forwardState(e,t){if(Object.hasOwn(this.#e.config.forwardFnMap,e)){let n=this.#i(e,t),r=this.#e.config.forwardFnMap[e],i=this.#o(e,r,t);return{name:i,params:this.#i(i,n)}}let n=this.#e.resolvedForwardMap[e]??e;if(n!==e&&Object.hasOwn(this.#e.config.forwardFnMap,n)){let r=this.#i(e,t),i=this.#e.config.forwardFnMap[n],a=this.#o(n,i,t);return{name:a,params:this.#i(a,r)}}if(n!==e){let r=this.#i(e,t);return{name:n,params:this.#i(n,r)}}return{name:e,params:this.#i(e,t)}}buildStateResolved(e,t){let n=this.#e.matcher.getSegmentsByName(e);if(n)return a({segments:n,params:t,meta:this.#e.matcher.getMetaByName(e)},e)}isActiveRoute(n,r={},i=!1,a=!0){let o=this.#r.getState();if(!o)return!1;let s=o.name;if(s!==n&&!s.startsWith(`${n}.`)&&!n.startsWith(`${s}.`))return!1;let c=this.#e.config.defaultParams[n];if(i||s===n){let t={name:n,params:c?{...c,...r}:r,path:``,transition:e.DEFAULT_TRANSITION,context:{}};return this.#r.areStatesEqual(t,o,a)}if(!s.startsWith(`${n}.`))return!1;let l=o.params;return t.paramsMatch(r,l)?!c||t.paramsMatchExcluding(a?t.stripQueryDefaults(c,this.#e.matcher.getMetaByName(n)?.[n]):c,l,r):!1}getMetaForState(e){return this.#e.matcher.hasRoute(e)?this.#e.matcher.getMetaByName(e):void 0}getUrlParams(e){let t=this.#e.urlParamsCache.get(e);if(t!==void 0)return t;let n=this.#e.matcher.getSegmentsByName(e),r=n?i(n):[];return this.#e.urlParamsCache.set(e,r),r}getStore(){return this.#e}#i(e,t){return Object.hasOwn(this.#e.config.defaultParams,e)?{...this.#e.config.defaultParams[e],...t}:t}#a(e){if(this.#t)return e!==this.#n&&this.#r.logger.warn(`router.buildPath`,"`options` differs from the cached source reference; router options are immutable per router instance, so the first-cached buildPath options are reused (#957)."),this.#t;this.#n=e;let t=e?.trailingSlash;return this.#t=Object.freeze({trailingSlash:t===`never`||t===`always`?t:void 0,queryParamsMode:e?.queryParamsMode}),this.#t}#o(e,t,n){let r=new Set([e]),i=t(this.#r.getDependency,n),a=0;if(typeof i!=`string`)throw TypeError(`forwardTo callback must return a string, got ${typeof i}`);for(;a<100;){if(this.#e.matcher.getSegmentsByName(i)===void 0)throw Error(`Route "${i}" does not exist`);if(r.has(i)){let e=[...r,i].join(` → `);throw Error(`Circular forwardTo: ${e}`)}if(r.add(i),Object.hasOwn(this.#e.config.forwardFnMap,i)){let e=this.#e.config.forwardFnMap[i];i=e(this.#r.getDependency,n),a++;continue}let e=this.#e.config.forwardMap[i];if(e!==void 0){i=e,a++;continue}return i}throw Error(`forwardTo exceeds maximum depth of 100`)}};exports.RoutesNamespace=o;
2
+ //# sourceMappingURL=RoutesNamespace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoutesNamespace.js","names":["#store","#deps","createRoutesStore","getTransitionPath","constants","#getBuildPathOptions","matchSourceTrailingSlash","#mergeDefaultParams","#resolveDynamicForward","DEFAULT_TRANSITION","paramsMatch","paramsMatchExcluding","stripQueryDefaults","#cachedBuildPathOpts","#cachedOptionsSource"],"sources":["../../../../src/namespaces/RoutesNamespace/RoutesNamespace.ts"],"sourcesContent":["// packages/core/src/namespaces/RoutesNamespace/RoutesNamespace.ts\n\nimport { DEFAULT_ROUTE_NAME } from \"./constants\";\nimport {\n matchSourceTrailingSlash,\n paramsMatch,\n paramsMatchExcluding,\n stripQueryDefaults,\n} from \"./helpers\";\nimport {\n createRoutesStore,\n rebuildTreeInPlace,\n resetStore,\n} from \"./routesStore\";\nimport { constants, DEFAULT_TRANSITION } from \"../../constants\";\nimport { getTransitionPath } from \"../../transitionPath\";\n\nimport type { RoutesStore } from \"./routesStore\";\nimport type { RoutesDependencies } from \"./types\";\nimport type {\n CreateMatcherOptions,\n RouteParams,\n RouteTree,\n RouteTreeState,\n} from \"../../engine\";\nimport type {\n DefaultDependencies,\n ForwardToCallback,\n Options,\n Params,\n RouterLogger,\n State,\n Route,\n} from \"../../types\";\nimport type { RouteLifecycleNamespace } from \"../RouteLifecycleNamespace\";\n\nfunction collectUrlParamsArray(segments: readonly RouteTree[]): string[] {\n const params: string[] = [];\n\n for (const segment of segments) {\n for (const param of segment.paramMeta.urlParams) {\n params.push(param);\n }\n }\n\n return params;\n}\n\nfunction createRouteState<P extends RouteParams = RouteParams>(\n matchResult: {\n readonly segments: readonly { fullName: string }[];\n readonly params: Readonly<Record<string, unknown>>;\n readonly meta: Readonly<Record<string, Record<string, \"url\" | \"query\">>>;\n },\n name?: string,\n): RouteTreeState<P> {\n // The matcher yields ≥1 segment for every successful match, each carrying the\n // cumulative route name as `fullName`, so the last element is always present.\n // (Formerly `buildNameFromSegments` with a `?? \"\"` fallback — that branch was\n // unreachable defensive cruft propped up by a white-box test; inlined here.)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- matcher invariant: a successful match is never empty\n const resolvedName = name ?? matchResult.segments.at(-1)!.fullName;\n\n return {\n name: resolvedName,\n params: matchResult.params as P,\n meta: matchResult.meta,\n };\n}\n\ninterface CachedBuildPathOpts {\n readonly trailingSlash?: \"always\" | \"never\" | undefined;\n readonly queryParamsMode?: \"default\" | \"strict\" | \"loose\" | undefined;\n}\n\n/**\n * Independent namespace for managing routes.\n *\n * Static methods handle validation (called by facade).\n * Instance methods handle storage and business logic.\n */\nexport class RoutesNamespace<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n> {\n readonly #store: RoutesStore<Dependencies>;\n #cachedBuildPathOpts: CachedBuildPathOpts | undefined;\n // Source `options` reference captured on the first #getBuildPathOptions call;\n // used only by the dev-build immutability assertion below (#957).\n #cachedOptionsSource: Options | undefined;\n\n get #deps(): RoutesDependencies<Dependencies> {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.#store.depsStore!;\n }\n\n constructor(\n // No `= []` default: the sole caller (Router's ctor) always passes its own\n // already-defaulted `routes` — a namespace-level default would be dead code\n // and a default-before-required-params smell (S1788).\n routes: Route<Dependencies>[],\n matcherOptions: CreateMatcherOptions | undefined,\n logger: RouterLogger,\n ) {\n this.#store = createRoutesStore(routes, matcherOptions, logger);\n }\n\n /**\n * Creates a predicate function to check if a route node should be updated.\n * Note: Argument validation is done by facade (Router.ts) via validateShouldUpdateNodeArgs.\n */\n static shouldUpdateNode(\n nodeName: string,\n ): (toState: State, fromState?: State) => boolean {\n return (toState: State, fromState?: State): boolean => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!(toState && typeof toState === \"object\" && \"name\" in toState)) {\n throw new TypeError(\n \"[router.shouldUpdateNode] toState must be valid State object\",\n );\n }\n\n if (toState.transition.reload) {\n return true;\n }\n\n // Root node (DEFAULT_ROUTE_NAME === \"\") has no route-level identity — it\n // represents \"any route\". It must update on every transition so that\n // consumers subscribed via useRouteNode(\"\") (including RouteView at\n // the top of the tree) see every change. This matches the documented\n // contract in adapter docs: `useRouteNode(\"\")` — Root — ALL route\n // changes. See #519 for the missed transitions it was suffering from\n // (users → users.user had intersection=\"users\", leaving the root node\n // un-updated under a flat <Match segment=\"users.user\" exact> pattern).\n if (nodeName === DEFAULT_ROUTE_NAME) {\n return true;\n }\n\n const { intersection, toActivate, toDeactivate } = getTransitionPath(\n toState,\n fromState,\n );\n\n if (nodeName === intersection) {\n return true;\n }\n\n if (toActivate.includes(nodeName)) {\n return true;\n }\n\n return toDeactivate.includes(nodeName);\n };\n }\n\n // =========================================================================\n // Dependency injection\n // =========================================================================\n\n /**\n * Sets dependencies. Pure assignment — no side effects (#1331).\n *\n * The pending canActivate/canDeactivate factories from initial routes are\n * flushed separately by {@link flushPendingGuards}, called once wiring is\n * complete, so the order of the wire-* calls is unconstrained.\n */\n setDependencies(deps: RoutesDependencies<Dependencies>): void {\n this.#store.depsStore = deps;\n }\n\n /**\n * Registers the pending guard factories collected from initial route\n * definitions. Deferred out of {@link setDependencies} (#1331) so it runs on\n * a fully-built, fully-bound router: a guard factory that calls any\n * `router.*` method sees a ready instance instead of a half-assembled one.\n *\n * Invoked as the last step of the Router constructor. Idempotent after the\n * first call (the pending maps are cleared). Runtime `add()`/`replace()`\n * compile guards in their own PREPARE phase and never populate these maps.\n */\n flushPendingGuards(): void {\n const deps = this.#deps;\n\n for (const [routeName, handler] of this.#store.pendingCanActivate) {\n deps.addActivateGuard(routeName, handler);\n }\n\n this.#store.pendingCanActivate.clear();\n\n for (const [routeName, handler] of this.#store.pendingCanDeactivate) {\n deps.addDeactivateGuard(routeName, handler);\n }\n\n this.#store.pendingCanDeactivate.clear();\n }\n\n /**\n * Sets the lifecycle namespace reference.\n */\n setLifecycleNamespace(\n namespace: RouteLifecycleNamespace<Dependencies> | undefined,\n ): void {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.#store.lifecycleNamespace = namespace!;\n }\n\n // =========================================================================\n // Route tree operations\n // =========================================================================\n\n setRootPath(newRootPath: string): void {\n this.#store.rootPath = newRootPath;\n rebuildTreeInPlace(this.#store);\n }\n\n hasRoute(name: string): boolean {\n return this.#store.matcher.hasRoute(name);\n }\n\n clearRoutes(): void {\n resetStore(this.#store);\n }\n\n // =========================================================================\n // Path operations\n // =========================================================================\n\n /**\n * Builds a URL path for a route.\n * Note: Argument validation is done by facade (Router.ts) via validateBuildPathArgs.\n *\n * @param route - Route name\n * @param params - Route parameters\n * @param options - Router options\n */\n buildPath(route: string, params?: Params, options?: Options): string {\n if (route === constants.UNKNOWN_ROUTE) {\n return typeof params?.path === \"string\" ? params.path : \"\";\n }\n\n const paramsWithDefault = Object.hasOwn(\n this.#store.config.defaultParams,\n route,\n )\n ? { ...this.#store.config.defaultParams[route], ...params }\n : /* v8 ignore next -- @preserve: V8 can't track ?? branch in ternary; covered by buildPath tests without params */ (params ??\n {});\n\n const encodedParams =\n typeof this.#store.config.encoders[route] === \"function\"\n ? this.#store.config.encoders[route]({ ...paramsWithDefault })\n : paramsWithDefault;\n\n return this.#store.matcher.buildPath(\n route,\n encodedParams,\n this.#getBuildPathOptions(options),\n );\n }\n\n /**\n * Matches a URL path to a route in the tree.\n * Note: Argument validation is done by facade (Router.ts) via validateMatchPathArgs.\n */\n matchPath<P extends Params = Params>(\n path: string,\n options?: Options,\n ): State<P> | undefined {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Router.ts always passes options\n const opts = options!;\n\n const matchResult = this.#store.matcher.match(path);\n\n if (!matchResult) {\n return undefined;\n }\n\n const routeState = createRouteState(matchResult);\n const { name, params, meta } = routeState;\n\n const decodedParams =\n typeof this.#store.config.decoders[name] === \"function\"\n ? this.#store.config.decoders[name](params)\n : params;\n\n const { name: routeName, params: routeParams } = this.#deps.forwardState<P>(\n name,\n decodedParams as P,\n );\n\n let builtPath = path;\n\n if (opts.rewritePathOnMatch) {\n const buildParams =\n typeof this.#store.config.encoders[routeName] === \"function\"\n ? this.#store.config.encoders[routeName]({\n ...(routeParams as Params),\n })\n : (routeParams as Record<string, unknown>);\n\n const ts = opts.trailingSlash;\n\n try {\n builtPath = this.#store.matcher.buildPath(routeName, buildParams, {\n trailingSlash: ts === \"never\" || ts === \"always\" ? ts : undefined,\n queryParamsMode: opts.queryParamsMode,\n });\n\n if (ts === \"preserve\") {\n builtPath = matchSourceTrailingSlash(path, builtPath);\n }\n } catch {\n // The match already succeeded (route found, params decoded); only the\n // post-match path rewrite threw — e.g. a custom encoder handed buildPath\n // a query value its codec cannot serialise. Keep the source path\n // un-rewritten rather than discard a valid match (#1157). Opposite of the\n // parse side (#737): there a throw means \"URL not understood\" → unmatched;\n // here the URL WAS matched and only re-canonicalisation failed.\n builtPath = path;\n }\n }\n\n return this.#deps.makeState<P>(routeName, routeParams, builtPath, meta);\n }\n\n /**\n * Applies forwardTo and returns resolved state with merged defaultParams.\n *\n * Merges params in order:\n * 1. Source route defaultParams\n * 2. Provided params\n * 3. Target route defaultParams (after resolving forwardTo)\n */\n forwardState<P extends Params = Params>(\n name: string,\n params: P,\n ): { name: string; params: P } {\n if (Object.hasOwn(this.#store.config.forwardFnMap, name)) {\n const paramsWithSourceDefaults = this.#mergeDefaultParams(name, params);\n const dynamicForward = this.#store.config.forwardFnMap[name];\n const resolved = this.#resolveDynamicForward(\n name,\n dynamicForward,\n params,\n );\n\n return {\n name: resolved,\n params: this.#mergeDefaultParams(resolved, paramsWithSourceDefaults),\n };\n }\n\n const staticForward = this.#store.resolvedForwardMap[name] ?? name;\n\n if (\n staticForward !== name &&\n Object.hasOwn(this.#store.config.forwardFnMap, staticForward)\n ) {\n const paramsWithSourceDefaults = this.#mergeDefaultParams(name, params);\n const targetDynamicForward =\n this.#store.config.forwardFnMap[staticForward];\n const resolved = this.#resolveDynamicForward(\n staticForward,\n targetDynamicForward,\n params,\n );\n\n return {\n name: resolved,\n params: this.#mergeDefaultParams(resolved, paramsWithSourceDefaults),\n };\n }\n\n if (staticForward !== name) {\n const paramsWithSourceDefaults = this.#mergeDefaultParams(name, params);\n\n return {\n name: staticForward,\n params: this.#mergeDefaultParams(\n staticForward,\n paramsWithSourceDefaults,\n ),\n };\n }\n\n return { name, params: this.#mergeDefaultParams(name, params) };\n }\n\n /**\n * Builds a RouteTreeState from already-resolved route name and params.\n * Called by Router.buildState after forwardState is applied at facade level.\n * This allows plugins to intercept forwardState.\n */\n buildStateResolved(\n resolvedName: string,\n resolvedParams: Params,\n ): RouteTreeState | undefined {\n const segments = this.#store.matcher.getSegmentsByName(resolvedName);\n\n if (!segments) {\n return undefined;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const meta = this.#store.matcher.getMetaByName(resolvedName)!;\n\n return createRouteState(\n { segments, params: resolvedParams, meta },\n resolvedName,\n );\n }\n\n // =========================================================================\n // Query operations\n // =========================================================================\n\n /**\n * Checks if a route is currently active.\n */\n isActiveRoute(\n name: string,\n params: Params = {},\n strictEquality = false,\n ignoreQueryParams = true,\n ): boolean {\n // Note: empty string check is handled by Router.ts facade\n const activeState = this.#deps.getState();\n\n if (!activeState) {\n return false;\n }\n\n const activeName = activeState.name;\n\n // Fast path: check if routes are related before expensive operations\n if (\n activeName !== name &&\n !activeName.startsWith(`${name}.`) &&\n !name.startsWith(`${activeName}.`)\n ) {\n return false;\n }\n\n const defaultParams = this.#store.config.defaultParams[name] as\n Params | undefined;\n\n // Exact match case\n if (strictEquality || activeName === name) {\n const effectiveParams = defaultParams\n ? { ...defaultParams, ...params }\n : params;\n\n const targetState: State = {\n name,\n params: effectiveParams,\n path: \"\",\n transition: DEFAULT_TRANSITION,\n context: {},\n };\n\n return this.#deps.areStatesEqual(\n targetState,\n activeState,\n ignoreQueryParams,\n );\n }\n\n // The fast path above lets through three relations: exact (handled in\n // the previous block), `activeName` descendant of `name`, and `name`\n // descendant of `activeName`. Only the first two count as \"active\" —\n // a link pointing DEEPER than the current state is a navigation option,\n // not an active state. Reject the descendant-of-active case explicitly.\n if (!activeName.startsWith(`${name}.`)) {\n return false;\n }\n\n // Hierarchical check: activeState is a descendant of target (name)\n const activeParams = activeState.params;\n\n if (!paramsMatch(params, activeParams)) {\n return false;\n }\n\n if (!defaultParams) {\n return true;\n }\n\n // Honor `ignoreQueryParams` symmetrically with the exact-match branch\n // above: query-only param differences (e.g. parent has\n // `defaultParams: { sort: \"asc\" }` while the active descendant is\n // `products.detail` with `params: { id: \"6\" }` and no sort) must not\n // disqualify an ancestor link from being active. Strip query-typed\n // keys of `name` from the defaults before comparison; URL-typed keys\n // (`:id`, `:role`, etc.) are still enforced.\n // `name` reaches this point only after the fast-path established a valid\n // hierarchical relation AND `defaultParams` is non-null — both imply the\n // matcher has registered the route. Since the #1414 skip-empty meta, a\n // fully-static route resolves to the shared EMPTY_ROUTE_META with no own\n // entry, so `getMetaByName(name)?.[name]` is undefined there — exactly the\n // \"nothing to strip\" signal stripQueryDefaults short-circuits on (a static\n // route cannot declare query params, hence cannot carry query defaults).\n const defaultsToCheck = ignoreQueryParams\n ? stripQueryDefaults(\n defaultParams,\n this.#store.matcher.getMetaByName(name)?.[name],\n )\n : defaultParams;\n\n return paramsMatchExcluding(defaultsToCheck, activeParams, params);\n }\n\n getMetaForState(\n name: string,\n ): Record<string, Record<string, \"url\" | \"query\">> | undefined {\n return this.#store.matcher.hasRoute(name)\n ? this.#store.matcher.getMetaByName(name)\n : undefined;\n }\n\n getUrlParams(name: string): string[] {\n const cached = this.#store.urlParamsCache.get(name);\n\n // Stryker disable next-line BlockStatement: equivalent — cache short-circuit; emptying the early-return recomputes the identical value (getUrlParams is deterministic per route name) and re-caches it. (ConditionalExpression stays live: `→true` returns undefined on a cache miss = killed.)\n if (cached !== undefined) {\n return cached;\n }\n\n const segments = this.#store.matcher.getSegmentsByName(name);\n const result = segments\n ? collectUrlParamsArray(segments as readonly RouteTree[])\n : [];\n\n this.#store.urlParamsCache.set(name, result);\n\n return result;\n }\n\n getStore(): RoutesStore<Dependencies> {\n return this.#store;\n }\n\n #mergeDefaultParams<P extends Params = Params>(\n routeName: string,\n params: P,\n ): P {\n if (Object.hasOwn(this.#store.config.defaultParams, routeName)) {\n return {\n ...this.#store.config.defaultParams[routeName],\n ...params,\n };\n }\n\n return params;\n }\n\n #getBuildPathOptions(options?: Options): CachedBuildPathOpts {\n // Stryker disable next-line BlockStatement: equivalent — cache short-circuit; emptying the early-return rebuilds the identical buildPath options (deterministic) and re-caches them. (ConditionalExpression stays live: `→false` always rebuilds but a real consumer test pins the cached identity.)\n if (this.#cachedBuildPathOpts) {\n /* v8 ignore next 5 -- @preserve: dev assertion guarding a future caller that passes per-call varying options; the sole caller (Router.buildPath, always via this.#options.get()) passes the same immutable, deep-frozen per-instance options, so this branch is unreachable through the public API by construction (#957) */\n if (options !== this.#cachedOptionsSource) {\n this.#deps.logger.warn(\n \"router.buildPath\",\n \"`options` differs from the cached source reference; router options are immutable per router instance, so the first-cached buildPath options are reused (#957).\",\n );\n }\n\n return this.#cachedBuildPathOpts;\n }\n\n this.#cachedOptionsSource = options;\n\n const ts = options?.trailingSlash;\n\n this.#cachedBuildPathOpts = Object.freeze({\n trailingSlash: ts === \"never\" || ts === \"always\" ? ts : undefined,\n queryParamsMode: options?.queryParamsMode,\n });\n\n return this.#cachedBuildPathOpts;\n }\n\n #resolveDynamicForward(\n startName: string,\n startFn: ForwardToCallback<Dependencies>,\n params: Params,\n ): string {\n const visited = new Set<string>([startName]);\n\n let current = startFn(this.#deps.getDependency, params);\n let depth = 0;\n const MAX_DEPTH = 100;\n\n if (typeof current !== \"string\") {\n throw new TypeError(\n `forwardTo callback must return a string, got ${typeof current}`,\n );\n }\n\n while (depth < MAX_DEPTH) {\n if (this.#store.matcher.getSegmentsByName(current) === undefined) {\n throw new Error(`Route \"${current}\" does not exist`);\n }\n\n if (visited.has(current)) {\n const chain = [...visited, current].join(\" → \");\n\n throw new Error(`Circular forwardTo: ${chain}`);\n }\n\n visited.add(current);\n\n if (Object.hasOwn(this.#store.config.forwardFnMap, current)) {\n const fn = this.#store.config.forwardFnMap[\n current\n ] as ForwardToCallback<Dependencies>;\n\n current = fn(this.#deps.getDependency, params);\n\n depth++;\n continue;\n }\n\n const staticForward = this.#store.config.forwardMap[current];\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (staticForward !== undefined) {\n current = staticForward;\n depth++;\n continue;\n }\n\n return current;\n }\n\n throw new Error(`forwardTo exceeds maximum depth of ${MAX_DEPTH}`);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=new Set([`name`,`path`,`children`,`canActivate`,`canDeactivate`,`forwardTo`,`encodeParams`,`decodeParams`,`defaultParams`]);exports.STANDARD_ROUTE_KEYS=e;
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/constants.ts"],"sourcesContent":["// packages/core/src/namespaces/RoutesNamespace/constants.ts\n\n/**\n * Default route name for the root node.\n */\nexport const DEFAULT_ROUTE_NAME = \"\";\n\n/**\n * Keys that belong to a route's structural/config surface — everything NOT in\n * this set is a plugin-defined **custom field** (e.g. lifecycle hooks,\n * `preload`, `searchSchema`), stored in `RoutesStore.routeCustomFields`.\n *\n * Single source of truth for the custom-field split, shared by route\n * registration (`add`/`replace`) and `update` so both classify patch keys\n * identically. `name`/`path`/`children` define route identity and are not\n * patchable via `update`; the remaining six are the structural/guard config.\n */\nexport const STANDARD_ROUTE_KEYS: ReadonlySet<string> = new Set([\n \"name\",\n \"path\",\n \"children\",\n \"canActivate\",\n \"canDeactivate\",\n \"forwardTo\",\n \"encodeParams\",\n \"decodeParams\",\n \"defaultParams\",\n]);\n"],"mappings":"AAiBA,MAAa,EAA2C,IAAI,IAAI,CAC9D,OACA,OACA,WACA,cACA,gBACA,YACA,eACA,eACA,eACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ //#region src/namespaces/RoutesNamespace/forwardChain.d.ts
2
+ declare function resolveForwardChain(startRoute: string, forwardMap: Record<string, string>, maxDepth?: number): string;
3
+ //#endregion
4
+ export { resolveForwardChain };
5
+ //# sourceMappingURL=forwardChain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forwardChain.d.ts","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/forwardChain.ts"],"mappings":";iBAEgB,oBACd,oBACA,YAAY,wBACZ"}
@@ -0,0 +1,2 @@
1
+ function e(e,t,n=100){let r=new Set,i=[e],a=e;for(;t[a];){let e=t[a];if(r.has(e)){let t=i.indexOf(e),n=[...i.slice(t),e];throw Error(`Circular forwardTo: ${n.join(` → `)}`)}if(r.add(a),i.push(e),a=e,i.length>n)throw Error(`forwardTo chain exceeds maximum depth (${n}): ${i.join(` → `)}`)}return a}exports.resolveForwardChain=e;
2
+ //# sourceMappingURL=forwardChain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forwardChain.js","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/forwardChain.ts"],"sourcesContent":["// packages/core/src/namespaces/RoutesNamespace/forwardChain.ts\n\nexport function resolveForwardChain(\n startRoute: string,\n forwardMap: Record<string, string>,\n maxDepth = 100,\n): string {\n const visited = new Set<string>();\n const chain: string[] = [startRoute];\n let current = startRoute;\n\n while (forwardMap[current]) {\n const next = forwardMap[current];\n\n if (visited.has(next)) {\n const cycleStart = chain.indexOf(next);\n const cycle = [...chain.slice(cycleStart), next];\n\n throw new Error(`Circular forwardTo: ${cycle.join(\" → \")}`);\n }\n\n visited.add(current);\n chain.push(next);\n current = next;\n\n if (chain.length > maxDepth) {\n throw new Error(\n `forwardTo chain exceeds maximum depth (${maxDepth}): ${chain.join(\" → \")}`,\n );\n }\n }\n\n return current;\n}\n"],"mappings":"AAEA,SAAgB,EACd,EACA,EACA,EAAW,IACH,CACR,IAAM,EAAU,IAAI,IACd,EAAkB,CAAC,CAAU,EAC/B,EAAU,EAEd,KAAO,EAAW,IAAU,CAC1B,IAAM,EAAO,EAAW,GAExB,GAAI,EAAQ,IAAI,CAAI,EAAG,CACrB,IAAM,EAAa,EAAM,QAAQ,CAAI,EAC/B,EAAQ,CAAC,GAAG,EAAM,MAAM,CAAU,EAAG,CAAI,EAE/C,MAAU,MAAM,uBAAuB,EAAM,KAAK,KAAK,GAAG,CAC5D,CAMA,GAJA,EAAQ,IAAI,CAAO,EACnB,EAAM,KAAK,CAAI,EACf,EAAU,EAEN,EAAM,OAAS,EACjB,MAAU,MACR,0CAA0C,EAAS,KAAK,EAAM,KAAK,KAAK,GAC1E,CAEJ,CAEA,OAAO,CACT"}
@@ -0,0 +1,2 @@
1
+ function e(){return{decoders:Object.create(null),encoders:Object.create(null),defaultParams:Object.create(null),forwardMap:Object.create(null),forwardFnMap:Object.create(null)}}function t(e,t){for(let n of Object.keys(t))Object.assign(e[n],t[n])}function n(e,t){for(let n in e)if(e[n]!==t[n])return!1;return!0}function r(e,t,n){for(let r in e)if(!(r in n)&&e[r]!==t[r])return!1;return!0}function i(e,t){if(!t||!a(e,t))return e;let n={};for(let r in e)t[r]!==`query`&&(n[r]=e[r]);return n}function a(e,t){for(let n in e)if(t[n]===`query`)return!0;return!1}function o(e){let t={name:e.name,path:e.path};return e.children&&(t.children=e.children.map(e=>o(e))),t}function s(e,t,n=``){for(let r=0;r<e.length;r++){let i=e[r],a=n?`${n}.${i.name}`:i.name;if(a===t)return e.splice(r,1),!0;if(i.children&&t.startsWith(`${a}.`)&&s(i.children,t,a))return!0}return!1}function c(e,t){for(let n of Object.keys(e))t(n)&&delete e[n]}function l(e,t){let n=t.search(/[?#]/),r=n===-1?t:t.slice(0,n);if(r===`/`||r.endsWith(`/`))return t;let i=e.search(/[?#]/),a=i===-1?e:e.slice(0,i);return a.length>1&&a.endsWith(`/`)?`${r}/${n===-1?``:t.slice(n)}`:t}exports.assignConfigEntries=t,exports.clearConfigEntries=c,exports.createEmptyConfig=e,exports.matchSourceTrailingSlash=l,exports.paramsMatch=n,exports.paramsMatchExcluding=r,exports.removeFromDefinitions=s,exports.sanitizeRoute=o,exports.stripQueryDefaults=i;
2
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/helpers.ts"],"sourcesContent":["// packages/core/src/namespaces/RoutesNamespace/helpers.ts\n\nimport type { RouteConfig } from \"./types\";\nimport type { RouteDefinition } from \"../../engine\";\nimport type {\n DefaultDependencies,\n ForwardToCallback,\n Params,\n Route,\n} from \"../../types\";\n\n/**\n * Creates an empty RouteConfig.\n */\nexport function createEmptyConfig(): RouteConfig {\n return {\n decoders: Object.create(null) as Record<string, (params: Params) => Params>,\n encoders: Object.create(null) as Record<string, (params: Params) => Params>,\n defaultParams: Object.create(null) as Record<string, Params>,\n forwardMap: Object.create(null) as Record<string, string>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n forwardFnMap: Object.create(null) as Record<string, ForwardToCallback<any>>,\n };\n}\n\n/**\n * Copies every {@link RouteConfig} sub-map's entries from `source` into\n * `target` (shallow per map — entries are shared by reference). Driven by\n * `Object.keys(source)` instead of one `Object.assign` per field, so a newly\n * added config sub-field is carried over automatically with nothing to forget\n * at each copy site (#965). Both configs are produced by\n * {@link createEmptyConfig}, so every key in `source` also exists on `target`,\n * and every value is a record object — the invariant this enumeration relies on.\n */\nexport function assignConfigEntries(\n target: RouteConfig,\n source: RouteConfig,\n): void {\n for (const key of Object.keys(source) as (keyof RouteConfig)[]) {\n Object.assign(target[key], source[key]);\n }\n}\n\n// ============================================================================\n// Route Tree Helpers\n// ============================================================================\n\n/**\n * Checks if all params from source exist with same values in target.\n * Small function body allows V8 inlining.\n */\nexport function paramsMatch(source: Params, target: Params): boolean {\n for (const key in source) {\n if (source[key] !== target[key]) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Checks params match, skipping keys present in skipKeys.\n */\nexport function paramsMatchExcluding(\n source: Params,\n target: Params,\n skipKeys: Params,\n): boolean {\n for (const key in source) {\n if (key in skipKeys) {\n continue;\n }\n if (source[key] !== target[key]) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Returns a copy of `defaultParams` with query-typed keys removed, based on\n * `ownMeta` (the per-route paramTypeMap from the matcher). When no query keys\n * are present, returns the input by reference (zero-allocation fast path).\n *\n * `ownMeta` may be `undefined` for non-registered route names — this is the\n * caller's escape hatch (e.g. `getMetaByName(name)?.[name]`); a missing meta\n * means no query type information is available, so defaults pass through\n * unchanged.\n */\nexport function stripQueryDefaults(\n defaultParams: Params,\n ownMeta: Record<string, \"url\" | \"query\"> | undefined,\n): Params {\n if (!ownMeta || !hasQueryDefault(defaultParams, ownMeta)) {\n return defaultParams;\n }\n\n const filtered: Params = {};\n\n for (const key in defaultParams) {\n if (ownMeta[key] !== \"query\") {\n filtered[key] = defaultParams[key];\n }\n }\n\n return filtered;\n}\n\nfunction hasQueryDefault(\n defaultParams: Params,\n ownMeta: Record<string, \"url\" | \"query\">,\n): boolean {\n for (const key in defaultParams) {\n if (ownMeta[key] === \"query\") {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Sanitizes a route by keeping only essential properties.\n */\nexport function sanitizeRoute<Dependencies extends DefaultDependencies>(\n route: Route<Dependencies>,\n): RouteDefinition {\n const sanitized: RouteDefinition = {\n name: route.name,\n path: route.path,\n };\n\n if (route.children) {\n sanitized.children = route.children.map((child) => sanitizeRoute(child));\n }\n\n return sanitized;\n}\n\n/**\n * Recursively removes a route from definitions array.\n */\nexport function removeFromDefinitions(\n definitions: RouteDefinition[],\n routeName: string,\n parentPrefix = \"\",\n): boolean {\n for (let i = 0; i < definitions.length; i++) {\n const route = definitions[i];\n const fullName = parentPrefix\n ? `${parentPrefix}.${route.name}`\n : route.name;\n\n if (fullName === routeName) {\n definitions.splice(i, 1);\n\n return true;\n }\n\n if (\n route.children &&\n routeName.startsWith(`${fullName}.`) &&\n removeFromDefinitions(route.children, routeName, fullName)\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Clears configuration entries that match the predicate.\n */\nexport function clearConfigEntries<T>(\n config: Record<string, T>,\n matcher: (key: string) => boolean,\n): void {\n for (const key of Object.keys(config)) {\n if (matcher(key)) {\n delete config[key];\n }\n }\n}\n\n/**\n * Used by matchPath() when trailingSlash is \"preserve\": the matcher's\n * buildPath() with an unset trailingSlash mode strips trailing slashes,\n * but \"preserve\" means the source path's trailing-slash choice wins.\n * If the source had a trailing slash, re-attach it to the rewritten path.\n * The reverse case (rewritten has trailing, source does not) is not\n * reachable with the current matcher — it never adds a trailing slash\n * with undefined mode.\n */\nexport function matchSourceTrailingSlash(\n sourcePath: string,\n rewrittenPath: string,\n): string {\n const queryIndex = rewrittenPath.search(/[?#]/);\n const pathPart =\n queryIndex === -1 ? rewrittenPath : rewrittenPath.slice(0, queryIndex);\n\n // Stryker disable next-line LogicalOperator: equivalent — buildPath strips trailing slashes, so the rewritten path never ends with \"/\" unless it IS \"/\" (already caught by the `=== \"/\"` operand). `endsWith(\"/\")` is unreachable-true, so `||` ≡ `&&`.\n if (pathPart === \"/\" || pathPart.endsWith(\"/\")) {\n return rewrittenPath;\n }\n\n const sourceQueryIndex = sourcePath.search(/[?#]/);\n const sourcePathPart =\n sourceQueryIndex === -1\n ? sourcePath\n : sourcePath.slice(0, sourceQueryIndex);\n\n if (!(sourcePathPart.length > 1 && sourcePathPart.endsWith(\"/\"))) {\n return rewrittenPath;\n }\n\n const querySuffix = queryIndex === -1 ? \"\" : rewrittenPath.slice(queryIndex);\n\n return `${pathPart}/${querySuffix}`;\n}\n"],"mappings":"AAcA,SAAgB,GAAiC,CAC/C,MAAO,CACL,SAAU,OAAO,OAAO,IAAI,EAC5B,SAAU,OAAO,OAAO,IAAI,EAC5B,cAAe,OAAO,OAAO,IAAI,EACjC,WAAY,OAAO,OAAO,IAAI,EAE9B,aAAc,OAAO,OAAO,IAAI,CAClC,CACF,CAWA,SAAgB,EACd,EACA,EACM,CACN,IAAK,IAAM,KAAO,OAAO,KAAK,CAAM,EAClC,OAAO,OAAO,EAAO,GAAM,EAAO,EAAI,CAE1C,CAUA,SAAgB,EAAY,EAAgB,EAAyB,CACnE,IAAK,IAAM,KAAO,EAChB,GAAI,EAAO,KAAS,EAAO,GACzB,MAAO,GAIX,MAAO,EACT,CAKA,SAAgB,EACd,EACA,EACA,EACS,CACT,IAAK,IAAM,KAAO,EACZ,UAAO,IAGP,EAAO,KAAS,EAAO,GACzB,MAAO,GAIX,MAAO,EACT,CAYA,SAAgB,EACd,EACA,EACQ,CACR,GAAI,CAAC,GAAW,CAAC,EAAgB,EAAe,CAAO,EACrD,OAAO,EAGT,IAAM,EAAmB,CAAC,EAE1B,IAAK,IAAM,KAAO,EACZ,EAAQ,KAAS,UACnB,EAAS,GAAO,EAAc,IAIlC,OAAO,CACT,CAEA,SAAS,EACP,EACA,EACS,CACT,IAAK,IAAM,KAAO,EAChB,GAAI,EAAQ,KAAS,QACnB,MAAO,GAIX,MAAO,EACT,CAKA,SAAgB,EACd,EACiB,CACjB,IAAM,EAA6B,CACjC,KAAM,EAAM,KACZ,KAAM,EAAM,IACd,EAMA,OAJI,EAAM,WACR,EAAU,SAAW,EAAM,SAAS,IAAK,GAAU,EAAc,CAAK,CAAC,GAGlE,CACT,CAKA,SAAgB,EACd,EACA,EACA,EAAe,GACN,CACT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CAC3C,IAAM,EAAQ,EAAY,GACpB,EAAW,EACb,GAAG,EAAa,GAAG,EAAM,OACzB,EAAM,KAEV,GAAI,IAAa,EAGf,OAFA,EAAY,OAAO,EAAG,CAAC,EAEhB,GAGT,GACE,EAAM,UACN,EAAU,WAAW,GAAG,EAAS,EAAE,GACnC,EAAsB,EAAM,SAAU,EAAW,CAAQ,EAEzD,MAAO,EAEX,CAEA,MAAO,EACT,CAKA,SAAgB,EACd,EACA,EACM,CACN,IAAK,IAAM,KAAO,OAAO,KAAK,CAAM,EAC9B,EAAQ,CAAG,GACb,OAAO,EAAO,EAGpB,CAWA,SAAgB,EACd,EACA,EACQ,CACR,IAAM,EAAa,EAAc,OAAO,MAAM,EACxC,EACJ,IAAe,GAAK,EAAgB,EAAc,MAAM,EAAG,CAAU,EAGvE,GAAI,IAAa,KAAO,EAAS,SAAS,GAAG,EAC3C,OAAO,EAGT,IAAM,EAAmB,EAAW,OAAO,MAAM,EAC3C,EACJ,IAAqB,GACjB,EACA,EAAW,MAAM,EAAG,CAAgB,EAQ1C,OANM,EAAe,OAAS,GAAK,EAAe,SAAS,GAAG,EAMvD,GAAG,EAAS,GAFC,IAAe,GAAK,GAAK,EAAc,MAAM,CAAU,IAHlE,CAMX"}
@@ -0,0 +1,2 @@
1
+ function e(e,t,n,r){if(t){let n=t===e,i=t.startsWith(`${e}.`);if(n||i){let i=n?``:` (current: "${t}")`;return r.warn(`router.removeRoute`,`Cannot remove route "${e}" — it is currently active${i}. Navigate away first.`),!1}}return n&&r.warn(`router.removeRoute`,`Route "${e}" removed while navigation is in progress. This may cause unexpected behavior.`),!0}function t(e,t){return e?(t.error(`router.clearRoutes`,`Cannot clear routes while navigation is in progress. Wait for navigation to complete.`),!1):!0}exports.validateClearRoutes=t,exports.validateRemoveRoute=e;
2
+ //# sourceMappingURL=routeGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routeGuards.js","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/routeGuards.ts"],"sourcesContent":["import type { RouterLogger } from \"../../types\";\n\n/**\n * Validates removeRoute constraints.\n * Returns false if removal should be blocked (route is active).\n * Logs warnings for edge cases.\n *\n * @param name - Route name to remove\n * @param currentStateName - Current active route name (or undefined)\n * @param isNavigating - Whether navigation is in progress\n * @param logger - Per-router logger instance (from `getInternals(router).logger`)\n * @returns true if removal can proceed, false if blocked\n */\nexport function validateRemoveRoute(\n name: string,\n currentStateName: string | undefined,\n isNavigating: boolean,\n logger: RouterLogger,\n): boolean {\n if (currentStateName) {\n const isExactMatch = currentStateName === name;\n const isParentOfCurrent = currentStateName.startsWith(`${name}.`);\n\n if (isExactMatch || isParentOfCurrent) {\n const suffix = isExactMatch ? \"\" : ` (current: \"${currentStateName}\")`;\n\n logger.warn(\n \"router.removeRoute\",\n `Cannot remove route \"${name}\" — it is currently active${suffix}. Navigate away first.`,\n );\n\n return false;\n }\n }\n\n if (isNavigating) {\n logger.warn(\n \"router.removeRoute\",\n `Route \"${name}\" removed while navigation is in progress. This may cause unexpected behavior.`,\n );\n }\n\n return true;\n}\n\n/**\n * Validates clearRoutes operation.\n * Returns false if operation should be blocked (navigation in progress).\n *\n * @param isNavigating - Whether navigation is in progress\n * @param logger - Per-router logger instance (from `getInternals(router).logger`)\n * @returns true if clearRoutes can proceed, false if blocked\n */\nexport function validateClearRoutes(\n isNavigating: boolean,\n logger: RouterLogger,\n): boolean {\n if (isNavigating) {\n logger.error(\n \"router.clearRoutes\",\n \"Cannot clear routes while navigation is in progress. Wait for navigation to complete.\",\n );\n\n return false;\n }\n\n return true;\n}\n"],"mappings":"AAaA,SAAgB,EACd,EACA,EACA,EACA,EACS,CACT,GAAI,EAAkB,CACpB,IAAM,EAAe,IAAqB,EACpC,EAAoB,EAAiB,WAAW,GAAG,EAAK,EAAE,EAEhE,GAAI,GAAgB,EAAmB,CACrC,IAAM,EAAS,EAAe,GAAK,eAAe,EAAiB,IAOnE,OALA,EAAO,KACL,qBACA,wBAAwB,EAAK,4BAA4B,EAAO,uBAClE,EAEO,EACT,CACF,CASA,OAPI,GACF,EAAO,KACL,qBACA,UAAU,EAAK,+EACjB,EAGK,EACT,CAUA,SAAgB,EACd,EACA,EACS,CAUT,OATI,GACF,EAAO,MACL,qBACA,uFACF,EAEO,IAGF,EACT"}
@@ -0,0 +1,42 @@
1
+ import { RouteDefinition, RouteTree } from "../../engine/builder/types.js";
2
+ import { CreateMatcherOptions, Matcher } from "../../engine/createMatcher.js";
3
+ import { DefaultDependencies, GuardFnFactory } from "../../types/router.js";
4
+ import { RouteLifecycleNamespace } from "../RouteLifecycleNamespace/RouteLifecycleNamespace.js";
5
+ import { RouteConfig, RoutesDependencies } from "./types.js";
6
+ //#region src/namespaces/RoutesNamespace/routesStore.d.ts
7
+ interface RoutesStore<Dependencies extends DefaultDependencies = DefaultDependencies> {
8
+ /**
9
+ * DERIVED VIEW, not stored state: reconstructed from `tree` on every access
10
+ * via `routeTreeToDefinitions` (the lossless inverse cloneRouter already
11
+ * relies on — the `~` absolute marker is restored, child order is the
12
+ * definition order). The tree is the single source of truth, so a third
13
+ * retained copy of the route table (~30 B/route) is not kept. Every reader
14
+ * is a cold CRUD/plugin-registration path; the derive is O(N).
15
+ *
16
+ * The returned array is a FRESH snapshot each time — mutating it never
17
+ * affects the store (pass an explicitly-mutated snapshot to
18
+ * `commitTreeChanges` instead, as `remove` does).
19
+ */
20
+ readonly definitions: RouteDefinition[];
21
+ readonly config: RouteConfig;
22
+ tree: RouteTree;
23
+ matcher: Matcher;
24
+ /**
25
+ * Per-route-name cache of URL (path) param names, derived from `matcher` and
26
+ * read by `RoutesNamespace.getUrlParams` (powers `areStatesEqual` /
27
+ * `isActiveRoute`). Cleared on every `matcher` rebuild so comparisons never
28
+ * stay frozen to a route's pre-mutation param shape (#723).
29
+ */
30
+ readonly urlParamsCache: Map<string, string[]>;
31
+ resolvedForwardMap: Record<string, string>;
32
+ routeCustomFields: Record<string, Record<string, unknown>>;
33
+ rootPath: string;
34
+ readonly matcherOptions: CreateMatcherOptions | undefined;
35
+ depsStore: RoutesDependencies<Dependencies> | undefined;
36
+ lifecycleNamespace: RouteLifecycleNamespace<Dependencies> | undefined;
37
+ readonly pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>;
38
+ readonly pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>;
39
+ }
40
+ //#endregion
41
+ export { RoutesStore };
42
+ //# sourceMappingURL=routesStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routesStore.d.ts","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/routesStore.ts"],"mappings":";;;;;;UAsCiB,YACf,qBAAqB,sBAAsB;;;;;;;;;;;;;WAclC,aAAa;WACb,QAAQ;EACjB,MAAM;EACN,SAAS;;;;;;;WAOA,gBAAgB;EACzB,oBAAoB;EACpB,mBAAmB,eAAe;EAClC;WACS,gBAAgB;EACzB,WAAW,mBAAmB;EAC9B,oBAAoB,wBAAwB;WACnC,oBAAoB,YAAY,eAAe;WAC/C,sBAAsB,YAAY,eAAe"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../engine/builder/createRouteTree.js"),t=require("../../engine/operations/routeTreeToDefinitions.js"),n=require("../../engine/createMatcher.js"),r=require("./constants.js"),i=require("./helpers.js"),a=require("./forwardChain.js");function o(t,r,i){let a=e.createRouteTree(``,r,t),o=n.createMatcher(i);return o.registerTree(a),{tree:a,matcher:o}}function s(e,t=e.definitions){let n=o(t,e.rootPath,e.matcherOptions);e.tree=n.tree,e.matcher=n.matcher,e.urlParamsCache.clear()}function c(e,t){s(e,t),e.resolvedForwardMap=d(e.config)}function l(e){u(e),s(e,[])}function u(e){Object.assign(e.config,i.createEmptyConfig()),e.resolvedForwardMap=Object.create(null),e.routeCustomFields=Object.create(null)}function d(e){let t=Object.create(null);for(let n of Object.keys(e.forwardMap))t[n]=a.resolveForwardChain(n,e.forwardMap);return t}function f(e,t){if(typeof e!=`function`)return;let n=e.constructor.name===`AsyncFunction`,r=e.toString().includes(`__awaiter`);if(n||r)throw TypeError(`forwardTo callback cannot be async for route "${t}". Async functions break matchPath/buildPath.`)}function p(e,t,n,r){if(e.canActivate){let n=typeof e.forwardTo==`string`?e.forwardTo:`[dynamic]`;r.warn(`real-router`,`Route "${t}" has both forwardTo and canActivate. canActivate will be ignored because forwardTo creates a redirect (industry standard). Move canActivate to the target route "${n}".`)}if(e.canDeactivate){let n=typeof e.forwardTo==`string`?e.forwardTo:`[dynamic]`;r.warn(`real-router`,`Route "${t}" has both forwardTo and canDeactivate. canDeactivate will be ignored because forwardTo creates a redirect (industry standard). Move canDeactivate to the target route "${n}".`)}f(e.forwardTo,t),typeof e.forwardTo==`string`?n.forwardMap[t]=e.forwardTo:n.forwardFnMap[t]=e.forwardTo}function m(e,t,n,i,a,o,s){let c=Object.fromEntries(Object.entries(e).filter(([e])=>!r.STANDARD_ROUTE_KEYS.has(e)));Object.keys(c).length>0&&(i[t]=c),e.canActivate&&a.set(t,e.canActivate),e.canDeactivate&&o.set(t,e.canDeactivate),e.forwardTo&&p(e,t,n,s),e.decodeParams&&(n.decoders[t]=t=>e.decodeParams?.(t)??t),e.encodeParams&&(n.encoders[t]=t=>e.encodeParams?.(t)??t),e.defaultParams&&(n.defaultParams[t]=e.defaultParams)}function h(e,t,n,r,i,a,o=``){for(let s of e){let e=o?`${o}.${s.name}`:s.name;m(s,e,t,n,r,i,a),s.children&&h(s.children,t,n,r,i,a,e)}}function g(e){let t=i.createEmptyConfig();return i.assignConfigEntries(t,e),t}function _(e,t,n){if(n.length===0)return[...e,...t];let[r,...i]=n;return e.map(e=>{if(e.name!==r)return e;let n=e.children??[];return{...e,children:i.length===0?[...n,...t]:_(n,t,i)}})}function v(e,t,n){for(let r of e){let e=t?`${t}.${r.name}`:r.name;n(e),r.children&&v(r.children,e,n)}}function y(e,t,n){let r=new Set;v(e,t,e=>{if(r.has(e))throw Error(`[router.${n}] Duplicate route "${e}" in batch`);r.add(e)})}function b(e,t){if(e.startsWith(`@@`))throw Error(`[router.${t}] Route name "${e}" uses the reserved "@@" prefix. Routes with this prefix are internal and cannot be modified through the public API.`)}function x(e,t){for(let n of e)b(n.name,t),n.children&&x(n.children,t)}function S(e,t,n){let r=new Map,i=(e,t)=>{for(let a of e){let e=r.get(t);if(e?.has(a.path))throw Error(`[router.${n}] Path "${a.path}" is already defined`);e?e.add(a.path):r.set(t,new Set([a.path])),a.children&&i(a.children,t?`${t}.${a.name}`:a.name)}};i(e,t)}function C(e,t,n){if(x(t,`addRoute`),n!==void 0&&!e.matcher.hasRoute(n))throw Error(`[router.addRoute] Parent route "${n}" does not exist`);v(t,n??``,t=>{if(e.matcher.hasRoute(t))throw Error(`[router.addRoute] Route "${t}" already exists`)}),y(t,n??``,`addRoute`),S(t,n??``,`addRoute`)}function w({definitions:e,routesForHandlers:t,config:n,routeCustomFields:r,handlerParentName:i,rootPath:a,matcherOptions:s,logger:c}){let l=new Map,u=new Map;h(t,n,r,l,u,c,i);let f=d(n),{tree:p,matcher:m}=o(e,a,s);return{config:n,routeCustomFields:r,pendingCanActivate:l,pendingCanDeactivate:u,tree:p,matcher:m,resolvedForwardMap:f}}function T(e,t,n,r){return w({definitions:_(e.definitions,t.map(e=>i.sanitizeRoute(e)),n===void 0?[]:n.split(`.`)),routesForHandlers:t,config:g(e.config),routeCustomFields:Object.assign(Object.create(null),e.routeCustomFields),handlerParentName:n??``,rootPath:e.rootPath,matcherOptions:e.matcherOptions,logger:r})}function E(e,t,n,r){return w({definitions:e.map(e=>i.sanitizeRoute(e)),routesForHandlers:e,config:i.createEmptyConfig(),routeCustomFields:Object.create(null),handlerParentName:``,rootPath:t,matcherOptions:n,logger:r})}function D(e,t,n){let r=[];for(let[i,a]of e)r.push([i,a,t(a,n)]);return r}function O(e,t){return{activate:D(e.pendingCanActivate,t.compileGuard,`canActivate`),deactivate:D(e.pendingCanDeactivate,t.compileGuard,`canDeactivate`)}}function k(e,t,n){let r=e.depsStore,{activate:i,deactivate:a}=n??O(t,r);Object.assign(e.config,t.config),e.routeCustomFields=t.routeCustomFields,e.tree=t.tree,e.matcher=t.matcher,e.urlParamsCache.clear(),e.resolvedForwardMap=t.resolvedForwardMap;for(let[e,t,n]of i)r.addActivateGuard(e,t,n);for(let[e,t,n]of a)r.addDeactivateGuard(e,t,n)}function A(e,t,n,r){let{forwardTo:i,defaultParams:a,decodeParams:o,encodeParams:s,canActivate:c,canDeactivate:l}=r,u=i===void 0?void 0:j(n,i,e.config),d=M(e,n,r),f=c==null?void 0:t.compileGuardFactory(c,`canActivate`),p=l==null?void 0:t.compileGuardFactory(l,`canDeactivate`);return t.preflightHandlerLimit(f===void 0?[]:[n],p===void 0?[]:[n],!1),d!==void 0&&(Object.keys(d).length>0?e.routeCustomFields[n]=d:delete e.routeCustomFields[n]),u!==void 0&&(e.config.forwardMap=u.forwardMap,e.config.forwardFnMap=u.forwardFnMap,e.resolvedForwardMap=u.resolved),N(e,n,{defaultParams:a,decodeParams:o,encodeParams:s}),P(t,`activate`,n,c,f),P(t,`deactivate`,n,l,p),{forwardTo:i,defaultParams:a,decodeParams:o,encodeParams:s}}function j(e,t,n){f(t,e);let r=Object.assign(Object.create(null),n.forwardMap),i=Object.assign(Object.create(null),n.forwardFnMap);return t===null?(delete r[e],delete i[e]):typeof t==`string`?(delete i[e],r[e]=t):(delete r[e],i[e]=t),{forwardMap:r,forwardFnMap:i,resolved:d({...n,forwardMap:r})}}function M(e,t,n){let i;for(let a of Object.keys(n)){if(r.STANDARD_ROUTE_KEYS.has(a))continue;let o=n[a];o!==void 0&&(i??={...e.routeCustomFields[t]},o===null?delete i[a]:i[a]=o)}return i}function N(e,t,n){if(n.defaultParams!==void 0&&(n.defaultParams===null?delete e.config.defaultParams[t]:e.config.defaultParams[t]=n.defaultParams),n.decodeParams!==void 0)if(n.decodeParams===null)delete e.config.decoders[t];else{let r=n.decodeParams;e.config.decoders[t]=e=>r(e)??e}if(n.encodeParams!==void 0)if(n.encodeParams===null)delete e.config.encoders[t];else{let r=n.encodeParams;e.config.encoders[t]=e=>r(e)??e}}function P(e,t,n,r,i){r!==void 0&&(t===`activate`?r===null?e.clearCanActivate(n,`definition`):e.addCanActivate(n,r,!0,i):r===null?e.clearCanDeactivate(n,`definition`):e.addCanDeactivate(n,r,!0,i))}function F(e,n,r){x(e,`addRoute`),y(e,``,`addRoute`);let i=E(e,``,n,r),a={get definitions(){return t.routeTreeToDefinitions(a.tree)},config:i.config,tree:i.tree,matcher:i.matcher,urlParamsCache:new Map,resolvedForwardMap:i.resolvedForwardMap,routeCustomFields:i.routeCustomFields,rootPath:``,matcherOptions:n,depsStore:void 0,lifecycleNamespace:void 0,pendingCanActivate:i.pendingCanActivate,pendingCanDeactivate:i.pendingCanDeactivate};return a}exports.adoptRouteArtifacts=k,exports.assertAddable=C,exports.assertForwardToNotAsync=f,exports.assertNoDuplicateNamesInBatch=y,exports.assertNoDuplicatePathsInBatch=S,exports.assertNoInternalNamesInBatch=x,exports.assertNoInternalRouteName=b,exports.buildAddArtifacts=T,exports.buildReplaceArtifacts=E,exports.clearRouteData=u,exports.commitRouteUpdate=A,exports.commitTreeChanges=c,exports.compileArtifactGuards=O,exports.createRoutesStore=F,exports.rebuildTreeInPlace=s,exports.refreshForwardMap=d,exports.resetStore=l;
2
+ //# sourceMappingURL=routesStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routesStore.js","names":["createRouteTree","createMatcher","createEmptyConfig","resolveForwardChain","STANDARD_ROUTE_KEYS","sanitizeRoute","routeTreeToDefinitions"],"sources":["../../../../src/namespaces/RoutesNamespace/routesStore.ts"],"sourcesContent":["// packages/core/src/namespaces/RoutesNamespace/routesStore.ts\n\nimport { DEFAULT_ROUTE_NAME, STANDARD_ROUTE_KEYS } from \"./constants\";\nimport { resolveForwardChain } from \"./forwardChain\";\nimport {\n assignConfigEntries,\n createEmptyConfig,\n sanitizeRoute,\n} from \"./helpers\";\nimport {\n createMatcher,\n createRouteTree,\n routeTreeToDefinitions,\n} from \"../../engine\";\n\nimport type { RouteConfig, RoutesDependencies } from \"./types\";\nimport type {\n CreateMatcherOptions,\n Matcher,\n RouteDefinition,\n RouteTree,\n} from \"../../engine\";\nimport type {\n DefaultDependencies,\n ForwardToCallback,\n GuardFn,\n Params,\n RouteConfigUpdate,\n RouterLogger,\n GuardFnFactory,\n Route,\n} from \"../../types\";\nimport type { RouteLifecycleNamespace } from \"../RouteLifecycleNamespace\";\n\n// =============================================================================\n// Interfaces\n// =============================================================================\n\nexport interface RoutesStore<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n> {\n /**\n * DERIVED VIEW, not stored state: reconstructed from `tree` on every access\n * via `routeTreeToDefinitions` (the lossless inverse cloneRouter already\n * relies on — the `~` absolute marker is restored, child order is the\n * definition order). The tree is the single source of truth, so a third\n * retained copy of the route table (~30 B/route) is not kept. Every reader\n * is a cold CRUD/plugin-registration path; the derive is O(N).\n *\n * The returned array is a FRESH snapshot each time — mutating it never\n * affects the store (pass an explicitly-mutated snapshot to\n * `commitTreeChanges` instead, as `remove` does).\n */\n readonly definitions: RouteDefinition[];\n readonly config: RouteConfig;\n tree: RouteTree;\n matcher: Matcher;\n /**\n * Per-route-name cache of URL (path) param names, derived from `matcher` and\n * read by `RoutesNamespace.getUrlParams` (powers `areStatesEqual` /\n * `isActiveRoute`). Cleared on every `matcher` rebuild so comparisons never\n * stay frozen to a route's pre-mutation param shape (#723).\n */\n readonly urlParamsCache: Map<string, string[]>;\n resolvedForwardMap: Record<string, string>;\n routeCustomFields: Record<string, Record<string, unknown>>;\n rootPath: string;\n readonly matcherOptions: CreateMatcherOptions | undefined;\n depsStore: RoutesDependencies<Dependencies> | undefined;\n lifecycleNamespace: RouteLifecycleNamespace<Dependencies> | undefined;\n readonly pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>;\n readonly pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>;\n}\n\n// =============================================================================\n// Tree operations\n// =============================================================================\n\nfunction rebuildTree(\n definitions: readonly RouteDefinition[],\n rootPath: string,\n matcherOptions: CreateMatcherOptions | undefined,\n): { tree: RouteTree; matcher: Matcher } {\n const tree = createRouteTree(DEFAULT_ROUTE_NAME, rootPath, definitions);\n const matcher = createMatcher(matcherOptions);\n\n matcher.registerTree(tree);\n\n return { tree, matcher };\n}\n\n/**\n * Rebuilds tree+matcher in place from `definitions` (defaults to the current\n * tree's own derived definitions — the same-table case, e.g. a rootPath\n * change).\n */\nexport function rebuildTreeInPlace<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n store: RoutesStore<Dependencies>,\n definitions: readonly RouteDefinition[] = store.definitions,\n): void {\n const result = rebuildTree(definitions, store.rootPath, store.matcherOptions);\n\n store.tree = result.tree;\n store.matcher = result.matcher;\n store.urlParamsCache.clear();\n}\n\nexport function commitTreeChanges<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n store: RoutesStore<Dependencies>,\n definitions: readonly RouteDefinition[],\n): void {\n rebuildTreeInPlace(store, definitions);\n store.resolvedForwardMap = refreshForwardMap(store.config);\n}\n\n// =============================================================================\n// Store reset\n// =============================================================================\n\n/**\n * Clears all routes and resets config.\n * Does NOT clear lifecycle handlers or state — caller handles that.\n */\nexport function resetStore<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(store: RoutesStore<Dependencies>): void {\n clearRouteData(store);\n rebuildTreeInPlace(store, []);\n}\n\n/**\n * Clears route data without rebuilding the tree.\n * Used by replace() to avoid double rebuild (clearRouteData + commitTreeChanges).\n * `definitions` needs no clearing — it is derived from the tree, which the\n * caller rebuilds (resetStore → empty, replace → the new artifacts).\n */\nexport function clearRouteData<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(store: RoutesStore<Dependencies>): void {\n Object.assign(store.config, createEmptyConfig());\n\n store.resolvedForwardMap = Object.create(null) as Record<string, string>;\n store.routeCustomFields = Object.create(null) as Record<\n string,\n Record<string, unknown>\n >;\n}\n\n// =============================================================================\n// Forward map\n// =============================================================================\n\nexport function refreshForwardMap(config: RouteConfig): Record<string, string> {\n const map = Object.create(null) as Record<string, string>;\n\n for (const fromRoute of Object.keys(config.forwardMap)) {\n map[fromRoute] = resolveForwardChain(fromRoute, config.forwardMap);\n }\n\n return map;\n}\n\n// =============================================================================\n// Route handler registration\n// =============================================================================\n\n/**\n * Throws if `forwardTo` is an async function (native or transpiled). Async\n * forwardTo callbacks break the synchronous matchPath/buildPath contract.\n * Runs inside `registerForwardTo` (the add/replace build path, before any store\n * mutation) AND inside `getRoutesApi`'s `updateForwardTo` (the update path), so\n * `update(name, { forwardTo: async })` is rejected at registration with the same\n * actionable error instead of deferring a generic TypeError to navigation (#967).\n */\nexport function assertForwardToNotAsync(\n forwardTo: unknown,\n fullName: string,\n): void {\n if (typeof forwardTo !== \"function\") {\n return;\n }\n\n const isNativeAsync =\n (forwardTo as { constructor: { name: string } }).constructor.name ===\n \"AsyncFunction\";\n const isTranspiledAsync = (forwardTo as { toString: () => string })\n .toString()\n .includes(\"__awaiter\");\n\n if (isNativeAsync || isTranspiledAsync) {\n throw new TypeError(\n `forwardTo callback cannot be async for route \"${fullName}\". ` +\n `Async functions break matchPath/buildPath.`,\n );\n }\n}\n\nfunction registerForwardTo<Dependencies extends DefaultDependencies>(\n route: Route<Dependencies>,\n fullName: string,\n config: RouteConfig,\n logger: RouterLogger,\n): void {\n if (route.canActivate) {\n /* v8 ignore next -- @preserve: edge case, both string and function tested separately */\n const forwardTarget =\n typeof route.forwardTo === \"string\" ? route.forwardTo : \"[dynamic]\";\n\n logger.warn(\n \"real-router\",\n `Route \"${fullName}\" has both forwardTo and canActivate. ` +\n `canActivate will be ignored because forwardTo creates a redirect (industry standard). ` +\n `Move canActivate to the target route \"${forwardTarget}\".`,\n );\n }\n\n if (route.canDeactivate) {\n /* v8 ignore next -- @preserve: edge case, both string and function tested separately */\n const forwardTarget =\n typeof route.forwardTo === \"string\" ? route.forwardTo : \"[dynamic]\";\n\n logger.warn(\n \"real-router\",\n `Route \"${fullName}\" has both forwardTo and canDeactivate. ` +\n `canDeactivate will be ignored because forwardTo creates a redirect (industry standard). ` +\n `Move canDeactivate to the target route \"${forwardTarget}\".`,\n );\n }\n\n assertForwardToNotAsync(route.forwardTo, fullName);\n\n // forwardTo is guaranteed to exist at this point\n if (typeof route.forwardTo === \"string\") {\n config.forwardMap[fullName] = route.forwardTo;\n } else {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n config.forwardFnMap[fullName] = route.forwardTo!;\n }\n}\n\nfunction registerSingleRouteHandlers<Dependencies extends DefaultDependencies>(\n route: Route<Dependencies>,\n fullName: string,\n config: RouteConfig,\n routeCustomFields: Record<string, Record<string, unknown>>,\n pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>,\n pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>,\n logger: RouterLogger,\n): void {\n const customFields = Object.fromEntries(\n Object.entries(route).filter(([key]) => !STANDARD_ROUTE_KEYS.has(key)),\n );\n\n if (Object.keys(customFields).length > 0) {\n routeCustomFields[fullName] = customFields;\n }\n\n // Guards are collected here and registered into the lifecycle later — by\n // `adoptRouteArtifacts` (add/replace) or `RoutesNamespace.flushPendingGuards`\n // (initial routes, the final step of the Router constructor — #1331) — so\n // the build stays a pure, side-effect-free preparation step.\n if (route.canActivate) {\n pendingCanActivate.set(fullName, route.canActivate);\n }\n\n if (route.canDeactivate) {\n pendingCanDeactivate.set(fullName, route.canDeactivate);\n }\n\n if (route.forwardTo) {\n registerForwardTo(route, fullName, config, logger);\n }\n\n if (route.decodeParams) {\n config.decoders[fullName] = (params: Params): Params =>\n route.decodeParams?.(params) ?? params;\n }\n\n if (route.encodeParams) {\n config.encoders[fullName] = (params: Params): Params =>\n route.encodeParams?.(params) ?? params;\n }\n\n if (route.defaultParams) {\n config.defaultParams[fullName] = route.defaultParams;\n }\n}\n\nfunction registerAllRouteHandlers<Dependencies extends DefaultDependencies>(\n routes: readonly Route<Dependencies>[],\n config: RouteConfig,\n routeCustomFields: Record<string, Record<string, unknown>>,\n pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>,\n pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>,\n logger: RouterLogger,\n parentName = \"\",\n): void {\n for (const route of routes) {\n const fullName = parentName ? `${parentName}.${route.name}` : route.name;\n\n registerSingleRouteHandlers(\n route,\n fullName,\n config,\n routeCustomFields,\n pendingCanActivate,\n pendingCanDeactivate,\n logger,\n );\n\n if (route.children) {\n registerAllRouteHandlers(\n route.children,\n config,\n routeCustomFields,\n pendingCanActivate,\n pendingCanDeactivate,\n logger,\n fullName,\n );\n }\n }\n}\n\n// =============================================================================\n// Prepare-then-commit (issue #698)\n//\n// add()/replace() build the complete new store state into LOCAL structures, and\n// only swap it into the store once every core-level error has surfaced from the\n// build itself (async/circular forwardTo throw in registerAllRouteHandlers /\n// refreshForwardMap; invalid path constraint throws in rebuildTree). The store\n// is mutated only by `adoptRouteArtifacts`, which compiles every prepared guard\n// factory BEFORE the swap (#956): a factory that throws on compile (or returns a\n// non-function) aborts there, with the store still untouched. So all error\n// classes — core-level build errors AND malformed guard factories — surface\n// before any mutation, leaving the existing routes intact (full atomicity). The\n// silent-corruption cases route-tree never throws on (duplicate name vs an\n// existing route, a name duplicated within the batch, missing parent) are caught\n// up front by `assertAddable`.\n// =============================================================================\n\n/**\n * The fully-built, ready-to-swap result of preparing a route mutation. Holds\n * everything `adoptRouteArtifacts` assigns into the store.\n */\ninterface RouteArtifacts<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n> {\n readonly config: RouteConfig;\n readonly routeCustomFields: Record<string, Record<string, unknown>>;\n readonly pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>;\n readonly pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>;\n readonly tree: RouteTree;\n readonly matcher: Matcher;\n readonly resolvedForwardMap: Record<string, string>;\n}\n\n/** Null-proto shallow clone of a RouteConfig (preserves every sub-map's contents). */\nfunction cloneConfig(config: RouteConfig): RouteConfig {\n const clone = createEmptyConfig();\n\n assignConfigEntries(clone, config);\n\n return clone;\n}\n\n/**\n * Returns a new definitions array with `added` inserted, without mutating the\n * input. For a top-level add the existing definitions are shallow-copied and\n * `added` appended. For a parented add the spine down to the parent is cloned\n * (siblings/other branches are shared by reference) and `added` appended to the\n * parent's children. Caller guarantees the parent path exists (see assertAddable).\n */\nfunction insertAddedDefinitions(\n definitions: readonly RouteDefinition[],\n added: RouteDefinition[],\n parentSegments: readonly string[],\n): RouteDefinition[] {\n if (parentSegments.length === 0) {\n return [...definitions, ...added];\n }\n\n const [head, ...rest] = parentSegments;\n\n return definitions.map((def) => {\n if (def.name !== head) {\n return def;\n }\n\n const children = def.children ?? [];\n\n return {\n ...def,\n children:\n rest.length === 0\n ? [...children, ...added]\n : insertAddedDefinitions(children, added, rest),\n };\n });\n}\n\n/** Depth-first walk yielding each route's full dotted name (no side effects). */\nfunction walkRouteNames<Dependencies extends DefaultDependencies>(\n routes: readonly Route<Dependencies>[],\n parentName: string,\n onName: (fullName: string) => void,\n): void {\n for (const route of routes) {\n const fullName = parentName ? `${parentName}.${route.name}` : route.name;\n\n onName(fullName);\n\n if (route.children) {\n walkRouteNames(route.children, fullName, onName);\n }\n }\n}\n\n/**\n * Rejects a route name duplicated WITHIN a single batch — the silent-overwrite\n * case route-tree stays last-wins on (#953 for `add`, #968 for `replace`). Walks\n * the same depth-first dotted names, but tracks them in a local Set: a name seen\n * twice in one array means the caller's second route would silently shadow the\n * first (`matchPath` for the first route's path becomes unreachable). Mirrors\n * validation-plugin's batch-dup message (route-tree `checkBatchNameDuplicate`)\n * so the no-plugin error matches the with-plugin one. `methodName` is \"addRoute\"\n * for both add and replace — the plugin reports \"addRoute\" for replace batches\n * too, so this keeps with/without-plugin parity.\n */\nexport function assertNoDuplicateNamesInBatch<\n Dependencies extends DefaultDependencies,\n>(\n routes: readonly Route<Dependencies>[],\n parentName: string,\n methodName: string,\n): void {\n const seen = new Set<string>();\n\n walkRouteNames(routes, parentName, (fullName) => {\n if (seen.has(fullName)) {\n throw new Error(\n `[router.${methodName}] Duplicate route \"${fullName}\" in batch`,\n );\n }\n\n seen.add(fullName);\n });\n}\n\nconst INTERNAL_ROUTE_PREFIX = \"@@\";\n\n/**\n * Rejects a single (bare) route name that uses the reserved \"@@\" prefix —\n * internal / system names such as UNKNOWN_ROUTE (`\"@@router/UNKNOWN_ROUTE\"`).\n * Mutating such a name would let a real URL `matchPath` to a state with\n * `name === UNKNOWN_ROUTE`, silently conflating a genuine route with \"not\n * found\". This always-on guard protected all four mutators (#238) until the\n * validation-extraction (`d1ebff80`) demoted it to the opt-in\n * validation-plugin; only `add` was restored (#954), so `remove`/`update`\n * regained it via this helper (#1047). Mirrors validation-plugin's\n * `throwIfInternalRoute` message so the no-plugin error matches the with-plugin\n * one.\n */\nexport function assertNoInternalRouteName(\n name: string,\n methodName: string,\n): void {\n if (name.startsWith(INTERNAL_ROUTE_PREFIX)) {\n throw new Error(\n `[router.${methodName}] Route name \"${name}\" uses the reserved \"${INTERNAL_ROUTE_PREFIX}\" prefix. Routes with this prefix are internal and cannot be modified through the public API.`,\n );\n }\n}\n\n/**\n * Batch counterpart to {@link assertNoInternalRouteName}: rejects any route in\n * the batch (recursing children) whose BARE leaf name uses the reserved \"@@\"\n * prefix (the prefix is on the leaf, not the dotted fullName). Used by `add`\n * (#954) and `replace` (#1047).\n */\nexport function assertNoInternalNamesInBatch<\n Dependencies extends DefaultDependencies,\n>(routes: readonly Route<Dependencies>[], methodName: string): void {\n for (const route of routes) {\n assertNoInternalRouteName(route.name, methodName);\n\n if (route.children) {\n assertNoInternalNamesInBatch(route.children, methodName);\n }\n }\n}\n\n/**\n * Rejects two routes that share the same `path` at the same parent level WITHIN\n * a single `add` batch (#955). The matcher resolves a path collision last-wins,\n * so the earlier route stays addressable by name (`has` / `buildPath`) but is\n * unreachable by URL (`matchPath` returns the later route) — a silent shadow.\n * Paths only collide among siblings, so seen paths are tracked per parent\n * fullName. Mirrors validation-plugin's message (route-tree\n * `checkBatchPathDuplicate`) so the no-plugin error matches the with-plugin one.\n * Scoped to the batch (not the existing tree) per #955 — the in-batch case the\n * issue describes.\n */\nexport function assertNoDuplicatePathsInBatch<\n Dependencies extends DefaultDependencies,\n>(\n routes: readonly Route<Dependencies>[],\n parentName: string,\n methodName: string,\n): void {\n const seenByParent = new Map<string, Set<string>>();\n\n const walk = (\n siblings: readonly Route<Dependencies>[],\n parent: string,\n ): void => {\n for (const route of siblings) {\n const paths = seenByParent.get(parent);\n\n if (paths?.has(route.path)) {\n throw new Error(\n `[router.${methodName}] Path \"${route.path}\" is already defined`,\n );\n }\n\n if (paths) {\n paths.add(route.path);\n } else {\n seenByParent.set(parent, new Set([route.path]));\n }\n\n if (route.children) {\n walk(route.children, parent ? `${parent}.${route.name}` : route.name);\n }\n }\n };\n\n walk(routes, parentName);\n}\n\n/**\n * Up-front guard for `add` against the corruptions route-tree stays silent on: a\n * missing `parent`, a name that collides with an EXISTING route, a name\n * duplicated WITHIN the batch, a reserved \"@@\"-prefixed name (which would shadow\n * an internal/system route name), and a path duplicated among siblings WITHIN\n * the batch (any of which would otherwise be silently overwritten/shadowed).\n * Throws before any build.\n */\nexport function assertAddable<Dependencies extends DefaultDependencies>(\n store: RoutesStore<Dependencies>,\n routes: readonly Route<Dependencies>[],\n parentName: string | undefined,\n): void {\n assertNoInternalNamesInBatch(routes, \"addRoute\");\n\n if (parentName !== undefined && !store.matcher.hasRoute(parentName)) {\n throw new Error(\n `[router.addRoute] Parent route \"${parentName}\" does not exist`,\n );\n }\n\n walkRouteNames(routes, parentName ?? \"\", (fullName) => {\n if (store.matcher.hasRoute(fullName)) {\n throw new Error(`[router.addRoute] Route \"${fullName}\" already exists`);\n }\n });\n\n assertNoDuplicateNamesInBatch(routes, parentName ?? \"\", \"addRoute\");\n assertNoDuplicatePathsInBatch(routes, parentName ?? \"\", \"addRoute\");\n}\n\n/**\n * Builds RouteArtifacts from a final definitions array and the routes whose\n * handlers (config + guards) populate `config`/`routeCustomFields`. Guards are\n * collected into the returned pending maps (depsStore is intentionally omitted\n * so nothing compiles or touches the lifecycle here). THROWS on async/circular\n * forwardTo and invalid path constraint — before the caller mutates the store.\n *\n * Takes a single args object: the positional list hit 8 parameters (S107) when\n * the per-router `logger` (#724) joined it, and named fields read better at the\n * two call sites anyway.\n */\nfunction buildArtifacts<Dependencies extends DefaultDependencies>({\n definitions,\n routesForHandlers,\n config,\n routeCustomFields,\n handlerParentName,\n rootPath,\n matcherOptions,\n logger,\n}: {\n definitions: readonly RouteDefinition[];\n routesForHandlers: readonly Route<Dependencies>[];\n config: RouteConfig;\n routeCustomFields: Record<string, Record<string, unknown>>;\n handlerParentName: string;\n rootPath: string;\n matcherOptions: CreateMatcherOptions | undefined;\n logger: RouterLogger;\n}): RouteArtifacts<Dependencies> {\n const pendingCanActivate = new Map<string, GuardFnFactory<Dependencies>>();\n const pendingCanDeactivate = new Map<string, GuardFnFactory<Dependencies>>();\n\n registerAllRouteHandlers(\n routesForHandlers,\n config,\n routeCustomFields,\n pendingCanActivate,\n pendingCanDeactivate,\n logger,\n handlerParentName,\n );\n\n const resolvedForwardMap = refreshForwardMap(config);\n const { tree, matcher } = rebuildTree(definitions, rootPath, matcherOptions);\n\n return {\n config,\n routeCustomFields,\n pendingCanActivate,\n pendingCanDeactivate,\n tree,\n matcher,\n resolvedForwardMap,\n };\n}\n\n/** Builds the merged artifacts for an incremental `add` (existing ∪ new). */\nexport function buildAddArtifacts<Dependencies extends DefaultDependencies>(\n store: RoutesStore<Dependencies>,\n routes: readonly Route<Dependencies>[],\n parentName: string | undefined,\n logger: RouterLogger,\n): RouteArtifacts<Dependencies> {\n const definitions = insertAddedDefinitions(\n store.definitions,\n routes.map((route) => sanitizeRoute(route)),\n parentName === undefined ? [] : parentName.split(\".\"),\n );\n\n return buildArtifacts({\n definitions,\n routesForHandlers: routes,\n config: cloneConfig(store.config),\n routeCustomFields: Object.assign(\n Object.create(null) as Record<string, Record<string, unknown>>,\n store.routeCustomFields,\n ),\n handlerParentName: parentName ?? \"\",\n rootPath: store.rootPath,\n matcherOptions: store.matcherOptions,\n logger,\n });\n}\n\n/** Builds the fresh artifacts for a full `replace` (standalone new set). */\nexport function buildReplaceArtifacts<Dependencies extends DefaultDependencies>(\n routes: readonly Route<Dependencies>[],\n rootPath: string,\n matcherOptions: CreateMatcherOptions | undefined,\n logger: RouterLogger,\n): RouteArtifacts<Dependencies> {\n return buildArtifacts({\n definitions: routes.map((route) => sanitizeRoute(route)),\n routesForHandlers: routes,\n config: createEmptyConfig(),\n routeCustomFields: Object.create(null) as Record<\n string,\n Record<string, unknown>\n >,\n handlerParentName: \"\",\n rootPath,\n matcherOptions,\n logger,\n });\n}\n\n/**\n * Compiles every pending guard factory up front, returning\n * `[name, factory, compiledFn]` triples for installation. THROWS from `compile`\n * on the first factory that throws on compile or returns a non-function — the\n * pre-swap validation that makes `adoptRouteArtifacts` atomic for malformed\n * guards (#956). Compiling here (not at install) means a factory with\n * compile-time side effects runs exactly once.\n */\nfunction compilePendingGuards<Dependencies extends DefaultDependencies>(\n pending: Map<string, GuardFnFactory<Dependencies>>,\n compile: (\n handler: GuardFnFactory<Dependencies>,\n methodName: string,\n ) => GuardFn,\n methodName: string,\n): [string, GuardFnFactory<Dependencies>, GuardFn][] {\n const compiled: [string, GuardFnFactory<Dependencies>, GuardFn][] = [];\n\n for (const [name, factory] of pending) {\n compiled.push([name, factory, compile(factory, methodName)]);\n }\n\n return compiled;\n}\n\n/** Pre-compiled guard triples for {@link adoptRouteArtifacts} install. */\nexport interface CompiledArtifactGuards<\n Dependencies extends DefaultDependencies,\n> {\n activate: [string, GuardFnFactory<Dependencies>, GuardFn][];\n deactivate: [string, GuardFnFactory<Dependencies>, GuardFn][];\n}\n\n/**\n * Compiles an artifacts' pending guard factories up front (#956), THROWING on\n * the first factory that throws on compile or returns a non-function.\n *\n * `replaceRoutes` calls this in its PREPARE phase — **before**\n * `clearDefinitionGuards()` — and hands the result to `adoptRouteArtifacts`, so\n * a compile-throw aborts with BOTH the tree AND the old definition guards intact\n * (#1193, mirroring #1046's handler-limit hoist). `add` has no clear step, so\n * `adoptRouteArtifacts` compiles inline for it.\n */\nexport function compileArtifactGuards<Dependencies extends DefaultDependencies>(\n artifacts: RouteArtifacts<Dependencies>,\n deps: RoutesDependencies<Dependencies>,\n): CompiledArtifactGuards<Dependencies> {\n return {\n activate: compilePendingGuards(\n artifacts.pendingCanActivate,\n deps.compileGuard,\n \"canActivate\",\n ),\n deactivate: compilePendingGuards(\n artifacts.pendingCanDeactivate,\n deps.compileGuard,\n \"canDeactivate\",\n ),\n };\n}\n\n/**\n * Commits prepared artifacts into the store in place. Every pending guard\n * factory is compiled BEFORE the tree/config swap (#956): a factory that throws\n * on compile (or returns a non-function) aborts here with the store untouched,\n * so `add`/`replace` are atomic for malformed guards too — not just core build\n * errors. The tree/config assignments are pure and cannot throw; the\n * pre-compiled guards are then installed without re-compiling (the factory ran\n * once, at the pre-compile above). `depsStore` is always set on a wired router,\n * which is the only path that reaches `add`/`replace`.\n */\nexport function adoptRouteArtifacts<Dependencies extends DefaultDependencies>(\n store: RoutesStore<Dependencies>,\n artifacts: RouteArtifacts<Dependencies>,\n precompiled?: CompiledArtifactGuards<Dependencies>,\n): void {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- depsStore is set once the router is wired; add/replace only run on a wired router (constructor-time registration uses createRoutesStore)\n const deps = store.depsStore!;\n\n // Pre-swap compile: surfaces a malformed guard factory before any mutation.\n // `replace()` pre-compiles in its PREPARE phase (BEFORE clearDefinitionGuards)\n // and passes the result here, so a compile-throw never erases the old\n // definition guards (#1193); `add` has no clear step and compiles inline.\n const { activate: compiledActivate, deactivate: compiledDeactivate } =\n precompiled ?? compileArtifactGuards(artifacts, deps);\n\n // Atomic swap — pure assignments, cannot throw. (`definitions` is derived\n // from `tree`, so swapping the tree IS the definitions swap.)\n Object.assign(store.config, artifacts.config);\n store.routeCustomFields = artifacts.routeCustomFields;\n store.tree = artifacts.tree;\n store.matcher = artifacts.matcher;\n store.urlParamsCache.clear();\n store.resolvedForwardMap = artifacts.resolvedForwardMap;\n\n // Install pre-compiled guards — no re-compile, no throw.\n for (const [name, factory, fn] of compiledActivate) {\n deps.addActivateGuard(name, factory, fn);\n }\n\n for (const [name, factory, fn] of compiledDeactivate) {\n deps.addDeactivateGuard(name, factory, fn);\n }\n}\n\n/**\n * COMMIT core for `update()` — the field-patch counterpart to\n * {@link adoptRouteArtifacts} (add/replace) / {@link commitTreeChanges} (remove)\n * / {@link resetStore} (clear), co-located here so all four route-CRUD commit\n * cores live in one file. Stays **NO_TREE_REBUILD**: an O(1) per-field patch\n * that never rebuilds the tree/matcher (so it must NOT funnel through\n * `adoptRouteArtifacts`).\n *\n * Prepare-then-commit (#951): every throwing step runs in PREPARE, before any\n * store write, so a rejected update leaves the route's prior config fully intact\n * — an async/cyclic `forwardTo` (#967), a guard factory that throws on compile\n * (#956 seam), a throwing custom-field getter, and the #961 handler-limit\n * pre-flight (#1046). Returns the structural fields for the caller's conditional\n * TREE_CHANGED emit, computed from the single destructure here so core invokes\n * each user getter once (#797 / #952 `null`-clears-definition-only preserved).\n */\nexport function commitRouteUpdate<Dependencies extends DefaultDependencies>(\n store: RoutesStore<Dependencies>,\n lifecycle: RouteLifecycleNamespace<Dependencies>,\n name: string,\n updates: RouteConfigUpdate<Dependencies>,\n): {\n forwardTo?: string | ForwardToCallback<Dependencies> | null | undefined;\n defaultParams?: Params | null | undefined;\n decodeParams?: ((params: Params) => Params) | null | undefined;\n encodeParams?: ((params: Params) => Params) | null | undefined;\n} {\n const {\n forwardTo,\n defaultParams,\n decodeParams,\n encodeParams,\n canActivate,\n canDeactivate,\n } = updates;\n\n // ===== PREPARE — compute every change into LOCALS. Any throw here aborts\n // before a single store write, so the whole field set is applied\n // all-or-nothing (#951).\n const forwardToPlan =\n forwardTo === undefined\n ? undefined\n : prepareForwardTo(name, forwardTo, store.config);\n\n const nextCustomFields = prepareCustomFields(store, name, updates);\n\n // Guard factories are compiled NOW (a throwing factory surfaces in PREPARE);\n // the precompiled function is installed in COMMIT without re-invoking the\n // factory, so a factory side effect runs exactly once (reuses the #956\n // compile-then-install seam). Compiled after the other prepares so a throw\n // upstream skips invoking the factory at all.\n const activateFn =\n canActivate === undefined || canActivate === null\n ? undefined\n : lifecycle.compileGuardFactory(canActivate, \"canActivate\");\n const deactivateFn =\n canDeactivate === undefined || canDeactivate === null\n ? undefined\n : lifecycle.compileGuardFactory(canDeactivate, \"canDeactivate\");\n\n // Pre-flight the #961 handler-limit before the COMMIT writes, so an at-limit\n // update that adds a NEW guard slot aborts before forwardTo / scalar config\n // land (#1046, #951). A slot is new only when `name` does not already hold a\n // guard of that type — an overwrite does not count.\n lifecycle.preflightHandlerLimit(\n activateFn === undefined ? [] : [name],\n deactivateFn === undefined ? [] : [name],\n false,\n );\n\n // ===== COMMIT — pure writes from here; nothing below throws.\n // Custom (plugin-defined) fields. Consumers read these lazily via\n // getRouteConfig (lifecycle hooks, preload, searchSchema), so no TREE_CHANGED\n // is needed — the next read sees the new value; the caller's emit stays\n // structural-only by design (О-7).\n if (nextCustomFields !== undefined) {\n if (Object.keys(nextCustomFields).length > 0) {\n store.routeCustomFields[name] = nextCustomFields;\n } else {\n delete store.routeCustomFields[name];\n }\n }\n\n if (forwardToPlan !== undefined) {\n store.config.forwardMap = forwardToPlan.forwardMap;\n store.config.forwardFnMap = forwardToPlan.forwardFnMap;\n store.resolvedForwardMap = forwardToPlan.resolved;\n }\n\n commitScalarConfig(store, name, {\n defaultParams,\n decodeParams,\n encodeParams,\n });\n\n // Install the guards from their PREPARE-phase precompiled functions; a `null`\n // clears the definition-origin guard only (#952). See commitGuardUpdate.\n commitGuardUpdate(lifecycle, \"activate\", name, canActivate, activateFn);\n commitGuardUpdate(lifecycle, \"deactivate\", name, canDeactivate, deactivateFn);\n\n return { forwardTo, defaultParams, decodeParams, encodeParams };\n}\n\n/**\n * PREPARE step for a `forwardTo` update (#951 atomicity): computes the new\n * forward maps and the resolved forward chain into LOCALS and returns them\n * WITHOUT touching the store. A throw here — an async `forwardTo` (#967) or a\n * cycle surfaced by `refreshForwardMap` — aborts `update()` before any field is\n * committed. The caller writes the returned bundle into the store in its COMMIT\n * phase. (Mirrors the build-then-swap shape of #698, but the swap is deferred to\n * the caller so it can be sequenced with the other prepared fields.)\n */\nfunction prepareForwardTo<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n name: string,\n forwardTo: string | ForwardToCallback<Dependencies> | null,\n config: RouteConfig,\n): {\n forwardMap: RouteConfig[\"forwardMap\"];\n forwardFnMap: RouteConfig[\"forwardFnMap\"];\n resolved: Record<string, string>;\n} {\n // #967: reject an async forwardTo at update time — parity with add/replace\n // (registerForwardTo runs the same check on the build path). A no-op for\n // string/null. Without this the async callback is stored silently and\n // surfaces later as a generic \"must return a string, got object\" TypeError\n // from #resolveDynamicForward at navigation. Runs first, before any clone.\n assertForwardToNotAsync(forwardTo, name);\n\n const forwardMap = Object.assign(\n Object.create(null) as RouteConfig[\"forwardMap\"],\n config.forwardMap,\n );\n const forwardFnMap = Object.assign(\n Object.create(null) as RouteConfig[\"forwardFnMap\"],\n config.forwardFnMap,\n );\n\n if (forwardTo === null) {\n delete forwardMap[name];\n delete forwardFnMap[name];\n } else if (typeof forwardTo === \"string\") {\n delete forwardFnMap[name];\n forwardMap[name] = forwardTo;\n } else {\n delete forwardMap[name];\n forwardFnMap[name] = forwardTo;\n }\n\n const resolved = refreshForwardMap({ ...config, forwardMap });\n\n return { forwardMap, forwardFnMap, resolved };\n}\n\n/**\n * PREPARE step for a route's plugin-defined **custom fields** (#951) — the\n * `update` counterpart to how `add`/`replace` register them\n * (`registerSingleRouteHandlers`). A custom field is any patch key not in\n * {@link STANDARD_ROUTE_KEYS}.\n *\n * Computes the merged record and RETURNS it for the caller to commit;\n * `undefined` means no custom-field key was present, so the caller leaves the\n * store untouched. Semantics mirror the scalar fields in\n * {@link commitScalarConfig}: shallow-merge by patch key, `null` removes a\n * single field, `undefined` is a no-op (leaves the field untouched). When the\n * merge empties the record, the caller drops the whole entry so `getRouteConfig`\n * returns `undefined` — symmetric with `add`, which only stores a record when at\n * least one custom field exists.\n *\n * Reading the custom-field getters HERE (in PREPARE, not at commit) is what lets\n * a throwing getter abort the whole update before any field is written. The\n * merged record is a **fresh object**, never mutated in place: `cloneRouter`\n * shares per-route custom-field records by reference (`Object.assign`), so\n * replacing the reference keeps a clone isolated from post-clone updates on the\n * source.\n */\nfunction prepareCustomFields<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n store: RoutesStore<Dependencies>,\n name: string,\n updates: RouteConfigUpdate<Dependencies>,\n): Record<string, unknown> | undefined {\n let next: Record<string, unknown> | undefined;\n\n // `Object.keys` (not `Object.entries`): a value is read only AFTER the\n // standard-key guard, so structural-field getters — already read once by\n // `update`'s destructuring — are not re-invoked. `Object.entries` would read\n // every value eagerly, double-invoking a `defaultParams`/`forwardTo` getter\n // and breaking the \"user getter called once\" invariant.\n // eslint-disable-next-line unicorn/prefer-object-iterable-methods -- see above\n for (const key of Object.keys(updates)) {\n if (STANDARD_ROUTE_KEYS.has(key)) {\n continue;\n }\n\n const value = (updates as Record<string, unknown>)[key];\n\n // `undefined` mirrors the structural path: leave the field untouched.\n if (value === undefined) {\n continue;\n }\n\n // Clone-on-first-write — keeps clones (which alias this record) isolated.\n next ??= { ...store.routeCustomFields[name] };\n\n if (value === null) {\n delete next[key];\n } else {\n next[key] = value;\n }\n }\n\n return next;\n}\n\n/**\n * COMMIT step for the scalar config fields of an update (#951): writes\n * `defaultParams` / `decodeParams` / `encodeParams` in place. These assignments\n * are pure and never throw, so they run in the COMMIT phase after every throwing\n * field has been validated in PREPARE. `forwardTo` is handled separately — it\n * has its own throwing prepare step ({@link prepareForwardTo}).\n */\nfunction commitScalarConfig<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n store: RoutesStore<Dependencies>,\n name: string,\n updates: {\n defaultParams?: Params | null | undefined;\n decodeParams?: ((params: Params) => Params) | null | undefined;\n encodeParams?: ((params: Params) => Params) | null | undefined;\n },\n): void {\n if (updates.defaultParams !== undefined) {\n if (updates.defaultParams === null) {\n delete store.config.defaultParams[name];\n } else {\n store.config.defaultParams[name] = updates.defaultParams;\n }\n }\n\n if (updates.decodeParams !== undefined) {\n if (updates.decodeParams === null) {\n delete store.config.decoders[name];\n } else {\n const decoder = updates.decodeParams;\n\n store.config.decoders[name] = (params: Params): Params =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime fallback if user-provided decoder violates its return type\n decoder(params) ?? params;\n }\n }\n\n if (updates.encodeParams !== undefined) {\n if (updates.encodeParams === null) {\n delete store.config.encoders[name];\n } else {\n const encoder = updates.encodeParams;\n\n store.config.encoders[name] = (params: Params): Params =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime fallback if user-provided encoder violates its return type\n encoder(params) ?? params;\n }\n }\n}\n\n/**\n * COMMIT step for one guard field of an update (#951). `undefined` is a no-op;\n * `null` clears the DEFINITION-origin guard only, preserving an external guard\n * (#952); a factory installs together with its PREPARE-phase `precompiledFn`\n * (no re-compile — #956 seam). Extracted from `update()` so its prepare/commit\n * orchestration stays within the cognitive-complexity budget.\n */\nfunction commitGuardUpdate<Dependencies extends DefaultDependencies>(\n lifecycle: RouteLifecycleNamespace<Dependencies>,\n kind: \"activate\" | \"deactivate\",\n name: string,\n value: GuardFnFactory<Dependencies> | null | undefined,\n precompiledFn: GuardFn | undefined,\n): void {\n if (value === undefined) {\n return;\n }\n\n if (kind === \"activate\") {\n if (value === null) {\n lifecycle.clearCanActivate(name, \"definition\");\n } else {\n lifecycle.addCanActivate(name, value, true, precompiledFn);\n }\n } else if (value === null) {\n lifecycle.clearCanDeactivate(name, \"definition\");\n } else {\n lifecycle.addCanDeactivate(name, value, true, precompiledFn);\n }\n}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nexport function createRoutesStore<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n routes: Route<Dependencies>[],\n matcherOptions: CreateMatcherOptions | undefined,\n logger: RouterLogger,\n): RoutesStore<Dependencies> {\n // Initial routes are a standalone set at rootPath \"\" — same build the\n // prepare-then-commit `replace` path uses. Guards land in the pending maps,\n // flushed by `flushPendingGuards()` at the end of the Router constructor\n // (#1331); `setDependencies` itself is a pure assignment.\n //\n // Reject the silent-corruption cases BEFORE building, giving the constructor\n // parity with `add()` / `replace()` — the third and last route-population\n // entry point (#1351): within-batch duplicate names (#953/#968) and reserved\n // \"@@\" names (#954). Without these the constructor silently last-wins a\n // duplicate-name sibling (the first route is dropped → its deep-link 404s)\n // while add/replace throw. `methodName` is \"addRoute\" so all three entry\n // points surface the identical bare-core error. (Duplicate PATHS are already\n // rejected downstream by the path-matcher backstop #1153, so they are not\n // re-checked here.)\n assertNoInternalNamesInBatch(routes, \"addRoute\");\n assertNoDuplicateNamesInBatch(routes, \"\", \"addRoute\");\n\n const artifacts = buildReplaceArtifacts(routes, \"\", matcherOptions, logger);\n\n const store: RoutesStore<Dependencies> = {\n // Deferred access: the getter runs only after `store` is initialized.\n get definitions() {\n return routeTreeToDefinitions(store.tree);\n },\n config: artifacts.config,\n tree: artifacts.tree,\n matcher: artifacts.matcher,\n urlParamsCache: new Map(),\n resolvedForwardMap: artifacts.resolvedForwardMap,\n routeCustomFields: artifacts.routeCustomFields,\n rootPath: \"\",\n matcherOptions,\n depsStore: undefined,\n lifecycleNamespace: undefined,\n pendingCanActivate: artifacts.pendingCanActivate,\n pendingCanDeactivate: artifacts.pendingCanDeactivate,\n };\n\n return store;\n}\n"],"mappings":"0PA8EA,SAAS,EACP,EACA,EACA,EACuC,CACvC,IAAM,EAAOA,EAAAA,gBAAAA,GAAoC,EAAU,CAAW,EAChE,EAAUC,EAAAA,cAAc,CAAc,EAI5C,OAFA,EAAQ,aAAa,CAAI,EAElB,CAAE,OAAM,SAAQ,CACzB,CAOA,SAAgB,EAGd,EACA,EAA0C,EAAM,YAC1C,CACN,IAAM,EAAS,EAAY,EAAa,EAAM,SAAU,EAAM,cAAc,EAE5E,EAAM,KAAO,EAAO,KACpB,EAAM,QAAU,EAAO,QACvB,EAAM,eAAe,MAAM,CAC7B,CAEA,SAAgB,EAGd,EACA,EACM,CACN,EAAmB,EAAO,CAAW,EACrC,EAAM,mBAAqB,EAAkB,EAAM,MAAM,CAC3D,CAUA,SAAgB,EAEd,EAAwC,CACxC,EAAe,CAAK,EACpB,EAAmB,EAAO,CAAC,CAAC,CAC9B,CAQA,SAAgB,EAEd,EAAwC,CACxC,OAAO,OAAO,EAAM,OAAQC,EAAAA,kBAAkB,CAAC,EAE/C,EAAM,mBAAqB,OAAO,OAAO,IAAI,EAC7C,EAAM,kBAAoB,OAAO,OAAO,IAAI,CAI9C,CAMA,SAAgB,EAAkB,EAA6C,CAC7E,IAAM,EAAM,OAAO,OAAO,IAAI,EAE9B,IAAK,IAAM,KAAa,OAAO,KAAK,EAAO,UAAU,EACnD,EAAI,GAAaC,EAAAA,oBAAoB,EAAW,EAAO,UAAU,EAGnE,OAAO,CACT,CAcA,SAAgB,EACd,EACA,EACM,CACN,GAAI,OAAO,GAAc,WACvB,OAGF,IAAM,EACH,EAAgD,YAAY,OAC7D,gBACI,EAAqB,EACxB,SAAS,CAAC,CACV,SAAS,WAAW,EAEvB,GAAI,GAAiB,EACnB,MAAU,UACR,iDAAiD,EAAS,8CAE5D,CAEJ,CAEA,SAAS,EACP,EACA,EACA,EACA,EACM,CACN,GAAI,EAAM,YAAa,CAErB,IAAM,EACJ,OAAO,EAAM,WAAc,SAAW,EAAM,UAAY,YAE1D,EAAO,KACL,cACA,UAAU,EAAS,oKAEwB,EAAc,GAC3D,CACF,CAEA,GAAI,EAAM,cAAe,CAEvB,IAAM,EACJ,OAAO,EAAM,WAAc,SAAW,EAAM,UAAY,YAE1D,EAAO,KACL,cACA,UAAU,EAAS,0KAE0B,EAAc,GAC7D,CACF,CAEA,EAAwB,EAAM,UAAW,CAAQ,EAG7C,OAAO,EAAM,WAAc,SAC7B,EAAO,WAAW,GAAY,EAAM,UAGpC,EAAO,aAAa,GAAY,EAAM,SAE1C,CAEA,SAAS,EACP,EACA,EACA,EACA,EACA,EACA,EACA,EACM,CACN,IAAM,EAAe,OAAO,YAC1B,OAAO,QAAQ,CAAK,CAAC,CAAC,QAAQ,CAAC,KAAS,CAACC,EAAAA,oBAAoB,IAAI,CAAG,CAAC,CACvE,EAEI,OAAO,KAAK,CAAY,CAAC,CAAC,OAAS,IACrC,EAAkB,GAAY,GAO5B,EAAM,aACR,EAAmB,IAAI,EAAU,EAAM,WAAW,EAGhD,EAAM,eACR,EAAqB,IAAI,EAAU,EAAM,aAAa,EAGpD,EAAM,WACR,EAAkB,EAAO,EAAU,EAAQ,CAAM,EAG/C,EAAM,eACR,EAAO,SAAS,GAAa,GAC3B,EAAM,eAAe,CAAM,GAAK,GAGhC,EAAM,eACR,EAAO,SAAS,GAAa,GAC3B,EAAM,eAAe,CAAM,GAAK,GAGhC,EAAM,gBACR,EAAO,cAAc,GAAY,EAAM,cAE3C,CAEA,SAAS,EACP,EACA,EACA,EACA,EACA,EACA,EACA,EAAa,GACP,CACN,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAW,EAAa,GAAG,EAAW,GAAG,EAAM,OAAS,EAAM,KAEpE,EACE,EACA,EACA,EACA,EACA,EACA,EACA,CACF,EAEI,EAAM,UACR,EACE,EAAM,SACN,EACA,EACA,EACA,EACA,EACA,CACF,CAEJ,CACF,CAoCA,SAAS,EAAY,EAAkC,CACrD,IAAM,EAAQF,EAAAA,kBAAkB,EAIhC,OAFA,EAAA,oBAAoB,EAAO,CAAM,EAE1B,CACT,CASA,SAAS,EACP,EACA,EACA,EACmB,CACnB,GAAI,EAAe,SAAW,EAC5B,MAAO,CAAC,GAAG,EAAa,GAAG,CAAK,EAGlC,GAAM,CAAC,EAAM,GAAG,GAAQ,EAExB,OAAO,EAAY,IAAK,GAAQ,CAC9B,GAAI,EAAI,OAAS,EACf,OAAO,EAGT,IAAM,EAAW,EAAI,UAAY,CAAC,EAElC,MAAO,CACL,GAAG,EACH,SACE,EAAK,SAAW,EACZ,CAAC,GAAG,EAAU,GAAG,CAAK,EACtB,EAAuB,EAAU,EAAO,CAAI,CACpD,CACF,CAAC,CACH,CAGA,SAAS,EACP,EACA,EACA,EACM,CACN,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAW,EAAa,GAAG,EAAW,GAAG,EAAM,OAAS,EAAM,KAEpE,EAAO,CAAQ,EAEX,EAAM,UACR,EAAe,EAAM,SAAU,EAAU,CAAM,CAEnD,CACF,CAaA,SAAgB,EAGd,EACA,EACA,EACM,CACN,IAAM,EAAO,IAAI,IAEjB,EAAe,EAAQ,EAAa,GAAa,CAC/C,GAAI,EAAK,IAAI,CAAQ,EACnB,MAAU,MACR,WAAW,EAAW,qBAAqB,EAAS,WACtD,EAGF,EAAK,IAAI,CAAQ,CACnB,CAAC,CACH,CAgBA,SAAgB,EACd,EACA,EACM,CACN,GAAI,EAAK,WAAW,IAAqB,EACvC,MAAU,MACR,WAAW,EAAW,gBAAgB,EAAK,qHAC7C,CAEJ,CAQA,SAAgB,EAEd,EAAwC,EAA0B,CAClE,IAAK,IAAM,KAAS,EAClB,EAA0B,EAAM,KAAM,CAAU,EAE5C,EAAM,UACR,EAA6B,EAAM,SAAU,CAAU,CAG7D,CAaA,SAAgB,EAGd,EACA,EACA,EACM,CACN,IAAM,EAAe,IAAI,IAEnB,GACJ,EACA,IACS,CACT,IAAK,IAAM,KAAS,EAAU,CAC5B,IAAM,EAAQ,EAAa,IAAI,CAAM,EAErC,GAAI,GAAO,IAAI,EAAM,IAAI,EACvB,MAAU,MACR,WAAW,EAAW,UAAU,EAAM,KAAK,qBAC7C,EAGE,EACF,EAAM,IAAI,EAAM,IAAI,EAEpB,EAAa,IAAI,EAAQ,IAAI,IAAI,CAAC,EAAM,IAAI,CAAC,CAAC,EAG5C,EAAM,UACR,EAAK,EAAM,SAAU,EAAS,GAAG,EAAO,GAAG,EAAM,OAAS,EAAM,IAAI,CAExE,CACF,EAEA,EAAK,EAAQ,CAAU,CACzB,CAUA,SAAgB,EACd,EACA,EACA,EACM,CAGN,GAFA,EAA6B,EAAQ,UAAU,EAE3C,IAAe,IAAA,IAAa,CAAC,EAAM,QAAQ,SAAS,CAAU,EAChE,MAAU,MACR,mCAAmC,EAAW,iBAChD,EAGF,EAAe,EAAQ,GAAc,GAAK,GAAa,CACrD,GAAI,EAAM,QAAQ,SAAS,CAAQ,EACjC,MAAU,MAAM,4BAA4B,EAAS,iBAAiB,CAE1E,CAAC,EAED,EAA8B,EAAQ,GAAc,GAAI,UAAU,EAClE,EAA8B,EAAQ,GAAc,GAAI,UAAU,CACpE,CAaA,SAAS,EAAyD,CAChE,cACA,oBACA,SACA,oBACA,oBACA,WACA,iBACA,UAU+B,CAC/B,IAAM,EAAqB,IAAI,IACzB,EAAuB,IAAI,IAEjC,EACE,EACA,EACA,EACA,EACA,EACA,EACA,CACF,EAEA,IAAM,EAAqB,EAAkB,CAAM,EAC7C,CAAE,OAAM,WAAY,EAAY,EAAa,EAAU,CAAc,EAE3E,MAAO,CACL,SACA,oBACA,qBACA,uBACA,OACA,UACA,oBACF,CACF,CAGA,SAAgB,EACd,EACA,EACA,EACA,EAC8B,CAO9B,OAAO,EAAe,CACpB,YAPkB,EAClB,EAAM,YACN,EAAO,IAAK,GAAUG,EAAAA,cAAc,CAAK,CAAC,EAC1C,IAAe,IAAA,GAAY,CAAC,EAAI,EAAW,MAAM,GAAG,CAI1C,EACV,kBAAmB,EACnB,OAAQ,EAAY,EAAM,MAAM,EAChC,kBAAmB,OAAO,OACxB,OAAO,OAAO,IAAI,EAClB,EAAM,iBACR,EACA,kBAAmB,GAAc,GACjC,SAAU,EAAM,SAChB,eAAgB,EAAM,eACtB,QACF,CAAC,CACH,CAGA,SAAgB,EACd,EACA,EACA,EACA,EAC8B,CAC9B,OAAO,EAAe,CACpB,YAAa,EAAO,IAAK,GAAUA,EAAAA,cAAc,CAAK,CAAC,EACvD,kBAAmB,EACnB,OAAQH,EAAAA,kBAAkB,EAC1B,kBAAmB,OAAO,OAAO,IAAI,EAIrC,kBAAmB,GACnB,WACA,iBACA,QACF,CAAC,CACH,CAUA,SAAS,EACP,EACA,EAIA,EACmD,CACnD,IAAM,EAA8D,CAAC,EAErE,IAAK,GAAM,CAAC,EAAM,KAAY,EAC5B,EAAS,KAAK,CAAC,EAAM,EAAS,EAAQ,EAAS,CAAU,CAAC,CAAC,EAG7D,OAAO,CACT,CAoBA,SAAgB,EACd,EACA,EACsC,CACtC,MAAO,CACL,SAAU,EACR,EAAU,mBACV,EAAK,aACL,aACF,EACA,WAAY,EACV,EAAU,qBACV,EAAK,aACL,eACF,CACF,CACF,CAYA,SAAgB,EACd,EACA,EACA,EACM,CAEN,IAAM,EAAO,EAAM,UAMb,CAAE,SAAU,EAAkB,WAAY,GAC9C,GAAe,EAAsB,EAAW,CAAI,EAItD,OAAO,OAAO,EAAM,OAAQ,EAAU,MAAM,EAC5C,EAAM,kBAAoB,EAAU,kBACpC,EAAM,KAAO,EAAU,KACvB,EAAM,QAAU,EAAU,QAC1B,EAAM,eAAe,MAAM,EAC3B,EAAM,mBAAqB,EAAU,mBAGrC,IAAK,GAAM,CAAC,EAAM,EAAS,KAAO,EAChC,EAAK,iBAAiB,EAAM,EAAS,CAAE,EAGzC,IAAK,GAAM,CAAC,EAAM,EAAS,KAAO,EAChC,EAAK,mBAAmB,EAAM,EAAS,CAAE,CAE7C,CAkBA,SAAgB,EACd,EACA,EACA,EACA,EAMA,CACA,GAAM,CACJ,YACA,gBACA,eACA,eACA,cACA,iBACE,EAKE,EACJ,IAAc,IAAA,GACV,IAAA,GACA,EAAiB,EAAM,EAAW,EAAM,MAAM,EAE9C,EAAmB,EAAoB,EAAO,EAAM,CAAO,EAO3D,EACJ,GAA6C,KACzC,IAAA,GACA,EAAU,oBAAoB,EAAa,aAAa,EACxD,EACJ,GAAiD,KAC7C,IAAA,GACA,EAAU,oBAAoB,EAAe,eAAe,EA0ClE,OApCA,EAAU,sBACR,IAAe,IAAA,GAAY,CAAC,EAAI,CAAC,CAAI,EACrC,IAAiB,IAAA,GAAY,CAAC,EAAI,CAAC,CAAI,EACvC,EACF,EAOI,IAAqB,IAAA,KACnB,OAAO,KAAK,CAAgB,CAAC,CAAC,OAAS,EACzC,EAAM,kBAAkB,GAAQ,EAEhC,OAAO,EAAM,kBAAkB,IAI/B,IAAkB,IAAA,KACpB,EAAM,OAAO,WAAa,EAAc,WACxC,EAAM,OAAO,aAAe,EAAc,aAC1C,EAAM,mBAAqB,EAAc,UAG3C,EAAmB,EAAO,EAAM,CAC9B,gBACA,eACA,cACF,CAAC,EAID,EAAkB,EAAW,WAAY,EAAM,EAAa,CAAU,EACtE,EAAkB,EAAW,aAAc,EAAM,EAAe,CAAY,EAErE,CAAE,YAAW,gBAAe,eAAc,cAAa,CAChE,CAWA,SAAS,EAGP,EACA,EACA,EAKA,CAMA,EAAwB,EAAW,CAAI,EAEvC,IAAM,EAAa,OAAO,OACxB,OAAO,OAAO,IAAI,EAClB,EAAO,UACT,EACM,EAAe,OAAO,OAC1B,OAAO,OAAO,IAAI,EAClB,EAAO,YACT,EAeA,OAbI,IAAc,MAChB,OAAO,EAAW,GAClB,OAAO,EAAa,IACX,OAAO,GAAc,UAC9B,OAAO,EAAa,GACpB,EAAW,GAAQ,IAEnB,OAAO,EAAW,GAClB,EAAa,GAAQ,GAKhB,CAAE,aAAY,eAAc,SAFlB,EAAkB,CAAE,GAAG,EAAQ,YAAW,CAEjB,CAAE,CAC9C,CAwBA,SAAS,EAGP,EACA,EACA,EACqC,CACrC,IAAI,EAQJ,IAAK,IAAM,KAAO,OAAO,KAAK,CAAO,EAAG,CACtC,GAAIE,EAAAA,oBAAoB,IAAI,CAAG,EAC7B,SAGF,IAAM,EAAS,EAAoC,GAG/C,IAAU,IAAA,KAKd,IAAS,CAAE,GAAG,EAAM,kBAAkB,EAAM,EAExC,IAAU,KACZ,OAAO,EAAK,GAEZ,EAAK,GAAO,EAEhB,CAEA,OAAO,CACT,CASA,SAAS,EAGP,EACA,EACA,EAKM,CASN,GARI,EAAQ,gBAAkB,IAAA,KACxB,EAAQ,gBAAkB,KAC5B,OAAO,EAAM,OAAO,cAAc,GAElC,EAAM,OAAO,cAAc,GAAQ,EAAQ,eAI3C,EAAQ,eAAiB,IAAA,GAC3B,GAAI,EAAQ,eAAiB,KAC3B,OAAO,EAAM,OAAO,SAAS,OACxB,CACL,IAAM,EAAU,EAAQ,aAExB,EAAM,OAAO,SAAS,GAAS,GAE7B,EAAQ,CAAM,GAAK,CACvB,CAGF,GAAI,EAAQ,eAAiB,IAAA,GAC3B,GAAI,EAAQ,eAAiB,KAC3B,OAAO,EAAM,OAAO,SAAS,OACxB,CACL,IAAM,EAAU,EAAQ,aAExB,EAAM,OAAO,SAAS,GAAS,GAE7B,EAAQ,CAAM,GAAK,CACvB,CAEJ,CASA,SAAS,EACP,EACA,EACA,EACA,EACA,EACM,CACF,IAAU,IAAA,KAIV,IAAS,WACP,IAAU,KACZ,EAAU,iBAAiB,EAAM,YAAY,EAE7C,EAAU,eAAe,EAAM,EAAO,GAAM,CAAa,EAElD,IAAU,KACnB,EAAU,mBAAmB,EAAM,YAAY,EAE/C,EAAU,iBAAiB,EAAM,EAAO,GAAM,CAAa,EAE/D,CAMA,SAAgB,EAGd,EACA,EACA,EAC2B,CAe3B,EAA6B,EAAQ,UAAU,EAC/C,EAA8B,EAAQ,GAAI,UAAU,EAEpD,IAAM,EAAY,EAAsB,EAAQ,GAAI,EAAgB,CAAM,EAEpE,EAAmC,CAEvC,IAAI,aAAc,CAChB,OAAOE,EAAAA,uBAAuB,EAAM,IAAI,CAC1C,EACA,OAAQ,EAAU,OAClB,KAAM,EAAU,KAChB,QAAS,EAAU,QACnB,eAAgB,IAAI,IACpB,mBAAoB,EAAU,mBAC9B,kBAAmB,EAAU,kBAC7B,SAAU,GACV,iBACA,UAAW,IAAA,GACX,mBAAoB,IAAA,GACpB,mBAAoB,EAAU,mBAC9B,qBAAsB,EAAU,oBAClC,EAEA,OAAO,CACT"}
@@ -0,0 +1,57 @@
1
+ import { Params, SimpleState, State } from "../../types/base.js";
2
+ import { DefaultDependencies, ForwardToCallback, GuardFn, GuardFnFactory, RouterLogger } from "../../types/router.js";
3
+ //#region src/namespaces/RoutesNamespace/types.d.ts
4
+ /**
5
+ * Dependencies injected into RoutesNamespace.
6
+ *
7
+ * These are function references from the Router facade,
8
+ * avoiding the need to pass the entire Router object.
9
+ */
10
+ interface RoutesDependencies<Dependencies extends DefaultDependencies = DefaultDependencies> {
11
+ /** Per-router logger instance (from `getInternals(router).logger`) */
12
+ logger: RouterLogger;
13
+ /**
14
+ * Register a canActivate handler for a route. `precompiledFn` installs an
15
+ * already-compiled `GuardFn` (from {@link compileGuard}) without re-invoking
16
+ * the factory — used by the #956 prepare-then-commit path so guards compile
17
+ * once, before the store swap.
18
+ */
19
+ addActivateGuard: (name: string, handler: GuardFnFactory<Dependencies>, precompiledFn?: GuardFn) => void;
20
+ /** Register a canDeactivate handler for a route (see {@link addActivateGuard}). */
21
+ addDeactivateGuard: (name: string, handler: GuardFnFactory<Dependencies>, precompiledFn?: GuardFn) => void;
22
+ /**
23
+ * Compile a guard factory to its `GuardFn` WITHOUT registering it — surfaces a
24
+ * throwing / non-function factory eagerly so the add/replace commit can
25
+ * validate every guard before swapping the store (#956).
26
+ */
27
+ compileGuard: (handler: GuardFnFactory<Dependencies>, methodName: string) => GuardFn;
28
+ /** Create state object */
29
+ makeState: <P extends Params = Params>(name: string, params?: P, path?: string, meta?: Record<string, Record<string, "url" | "query">>) => State<P>;
30
+ /** Get current router state */
31
+ getState: () => State | undefined;
32
+ /** Compare two states for equality */
33
+ areStatesEqual: (state1: State | undefined, state2: State | undefined, ignoreQueryParams?: boolean) => boolean;
34
+ /** Get a dependency by name */
35
+ getDependency: <K extends keyof Dependencies>(name: K) => Dependencies[K];
36
+ /** Forward state through facade (allows plugin interception) */
37
+ forwardState: <P extends Params = Params>(name: string, params: P) => SimpleState<P>;
38
+ }
39
+ /**
40
+ * Configuration storage for routes.
41
+ * Stores decoders, encoders, default params, and forward mappings.
42
+ */
43
+ interface RouteConfig {
44
+ /** Custom param decoders per route */
45
+ decoders: Record<string, (params: Params) => Params>;
46
+ /** Custom param encoders per route */
47
+ encoders: Record<string, (params: Params) => Params>;
48
+ /** Default params per route */
49
+ defaultParams: Record<string, Params>;
50
+ /** Forward mappings (source -> target) */
51
+ forwardMap: Record<string, string>;
52
+ /** Dynamic forward callbacks (source -> callback) */
53
+ forwardFnMap: Record<string, ForwardToCallback<any>>;
54
+ }
55
+ //#endregion
56
+ export { RouteConfig, RoutesDependencies };
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/namespaces/RoutesNamespace/types.ts"],"mappings":";;;;;;;;;UAmBiB,mBACf,qBAAqB,sBAAsB;;EAG3C,QAAQ;;;;;;;EAQR,mBACE,cACA,SAAS,eAAe,eACxB,gBAAgB;;EAIlB,qBACE,cACA,SAAS,eAAe,eACxB,gBAAgB;;;;;;EAQlB,eACE,SAAS,eAAe,eACxB,uBACG;;EAGL,YAAY,UAAU,SAAS,QAC7B,cACA,SAAS,GACT,eACA,OAAO,eAAe,qCACnB,MAAM;;EAGX,gBAAgB;;EAGhB,iBACE,QAAQ,mBACR,QAAQ,mBACR;;EAIF,gBAAgB,gBAAgB,cAAc,MAAM,MAAM,aAAa;;EAGvE,eAAe,UAAU,SAAS,QAChC,cACA,QAAQ,MACL,YAAY;;;;;;UAOF;;EAEf,UAAU,gBAAgB,QAAQ,WAAW;;EAG7C,UAAU,gBAAgB,QAAQ,WAAW;;EAG7C,eAAe,eAAe;;EAG9B,YAAY;;EAIZ,cAAc,eAAe"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../constants.js"),t=require("../../helpers.js"),n=require("./helpers.js"),r=require("../../stateMetaStore.js");var i=class{#e=void 0;#t=void 0;#n;get(){return this.#e}set(e){this.#t=this.#e,this.#e=e?t.freezeStateInPlace(e):void 0}getPrevious(){return this.#t}reset(){this.#e=void 0,this.#t=void 0}setDependencies(e){this.#n=e}makeState(n,i,a,o,s){let c=this.#n.getDefaultParams(),l=Object.hasOwn(c,n),u;u=l?Object.freeze({...c[n],...i}):!i||i===e.EMPTY_PARAMS?e.EMPTY_PARAMS:Object.freeze({...i});let d={name:n,params:u,path:a??this.#n.buildPath(n,i),context:{},...!s&&{transition:e.DEFAULT_TRANSITION}};return o&&r.setStateMetaParams(d,o),s?d:t.freezeStateInPlace(d)}areStatesEqual(e,t,r=!0){if(!e||!t)return!!e==!!t;if(e.name!==t.name)return!1;if(r){let r=this.#n.getUrlParams(e.name);for(let i of r)if(!n.areParamValuesEqual(e.params[i],t.params[i]))return!1;return!0}let i=Object.keys(e.params),a=Object.keys(t.params);if(i.length!==a.length)return!1;for(let r of i)if(!(r in t.params)||!n.areParamValuesEqual(e.params[r],t.params[r]))return!1;return!0}};exports.StateNamespace=i;
2
+ //# sourceMappingURL=StateNamespace.js.map