@real-router/core 0.56.0 → 0.57.1

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 (112) hide show
  1. package/dist/cjs/Router-Brp6_4FE.js +6 -0
  2. package/dist/cjs/Router-Brp6_4FE.js.map +1 -0
  3. package/dist/cjs/api.d.ts +1 -1
  4. package/dist/cjs/api.js +1 -1
  5. package/dist/cjs/{cloneRouter-DRieJvam.js → cloneRouter-CZx0T0RQ.js} +2 -2
  6. package/dist/cjs/{cloneRouter-DRieJvam.js.map → cloneRouter-CZx0T0RQ.js.map} +1 -1
  7. package/dist/cjs/{index-C-i6vx5Y.d.ts → index-BWUmnecT.d.ts} +1 -2
  8. package/dist/cjs/index-BWUmnecT.d.ts.map +1 -0
  9. package/dist/cjs/index-CYpAZCoc.d.ts.map +1 -1
  10. package/dist/cjs/index.d.ts +1 -1
  11. package/dist/cjs/index.js +1 -1
  12. package/dist/cjs/utils.js +1 -1
  13. package/dist/cjs/utils.js.map +1 -1
  14. package/dist/cjs/validation.d.ts +1 -1
  15. package/dist/esm/Router-LT61erYH.mjs +6 -0
  16. package/dist/esm/Router-LT61erYH.mjs.map +1 -0
  17. package/dist/esm/api.d.mts +1 -1
  18. package/dist/esm/api.mjs +1 -1
  19. package/dist/esm/{cloneRouter-DHrH6D_z.mjs → cloneRouter-DAscsmmF.mjs} +2 -2
  20. package/dist/esm/{cloneRouter-DHrH6D_z.mjs.map → cloneRouter-DAscsmmF.mjs.map} +1 -1
  21. package/dist/esm/{index-C-i6vx5Y.d.mts → index-BWUmnecT.d.mts} +1 -2
  22. package/dist/esm/index-BWUmnecT.d.mts.map +1 -0
  23. package/dist/esm/index-CYpAZCoc.d.mts.map +1 -1
  24. package/dist/esm/index.d.mts +1 -1
  25. package/dist/esm/index.mjs +1 -1
  26. package/dist/esm/utils.mjs +1 -1
  27. package/dist/esm/utils.mjs.map +1 -1
  28. package/dist/esm/validation.d.mts +1 -1
  29. package/package.json +4 -5
  30. package/dist/cjs/Router-IEGavTKk.js +0 -6
  31. package/dist/cjs/Router-IEGavTKk.js.map +0 -1
  32. package/dist/cjs/index-C-i6vx5Y.d.ts.map +0 -1
  33. package/dist/esm/Router-B3aeavRb.mjs +0 -6
  34. package/dist/esm/Router-B3aeavRb.mjs.map +0 -1
  35. package/dist/esm/index-C-i6vx5Y.d.mts.map +0 -1
  36. package/src/Router.ts +0 -737
  37. package/src/RouterError.ts +0 -324
  38. package/src/api/cloneRouter.ts +0 -159
  39. package/src/api/getDependenciesApi.ts +0 -160
  40. package/src/api/getLifecycleApi.ts +0 -65
  41. package/src/api/getPluginApi.ts +0 -228
  42. package/src/api/getRoutesApi.ts +0 -831
  43. package/src/api/helpers.ts +0 -10
  44. package/src/api/index.ts +0 -16
  45. package/src/api/types.ts +0 -12
  46. package/src/constants.ts +0 -101
  47. package/src/createRouter.ts +0 -32
  48. package/src/fsm/index.ts +0 -5
  49. package/src/fsm/routerFSM.ts +0 -130
  50. package/src/getNavigator.ts +0 -30
  51. package/src/guards.ts +0 -46
  52. package/src/helpers.ts +0 -197
  53. package/src/index.ts +0 -66
  54. package/src/internals.ts +0 -228
  55. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +0 -30
  56. package/src/namespaces/DependenciesNamespace/index.ts +0 -5
  57. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +0 -522
  58. package/src/namespaces/EventBusNamespace/index.ts +0 -5
  59. package/src/namespaces/EventBusNamespace/types.ts +0 -11
  60. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -552
  61. package/src/namespaces/NavigationNamespace/constants.ts +0 -55
  62. package/src/namespaces/NavigationNamespace/index.ts +0 -5
  63. package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +0 -108
  64. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +0 -124
  65. package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +0 -283
  66. package/src/namespaces/NavigationNamespace/types.ts +0 -110
  67. package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +0 -28
  68. package/src/namespaces/OptionsNamespace/constants.ts +0 -19
  69. package/src/namespaces/OptionsNamespace/helpers.ts +0 -50
  70. package/src/namespaces/OptionsNamespace/index.ts +0 -7
  71. package/src/namespaces/OptionsNamespace/validators.ts +0 -13
  72. package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +0 -291
  73. package/src/namespaces/PluginsNamespace/constants.ts +0 -34
  74. package/src/namespaces/PluginsNamespace/index.ts +0 -7
  75. package/src/namespaces/PluginsNamespace/types.ts +0 -22
  76. package/src/namespaces/PluginsNamespace/validators.ts +0 -28
  77. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +0 -558
  78. package/src/namespaces/RouteLifecycleNamespace/index.ts +0 -5
  79. package/src/namespaces/RouteLifecycleNamespace/types.ts +0 -10
  80. package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -81
  81. package/src/namespaces/RouterLifecycleNamespace/constants.ts +0 -25
  82. package/src/namespaces/RouterLifecycleNamespace/index.ts +0 -5
  83. package/src/namespaces/RouterLifecycleNamespace/types.ts +0 -30
  84. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +0 -582
  85. package/src/namespaces/RoutesNamespace/constants.ts +0 -6
  86. package/src/namespaces/RoutesNamespace/forwardChain.ts +0 -34
  87. package/src/namespaces/RoutesNamespace/helpers.ts +0 -204
  88. package/src/namespaces/RoutesNamespace/index.ts +0 -11
  89. package/src/namespaces/RoutesNamespace/routeGuards.ts +0 -62
  90. package/src/namespaces/RoutesNamespace/routesStore.ts +0 -566
  91. package/src/namespaces/RoutesNamespace/types.ts +0 -81
  92. package/src/namespaces/StateNamespace/StateNamespace.ts +0 -224
  93. package/src/namespaces/StateNamespace/helpers.ts +0 -24
  94. package/src/namespaces/StateNamespace/index.ts +0 -5
  95. package/src/namespaces/StateNamespace/types.ts +0 -15
  96. package/src/namespaces/index.ts +0 -35
  97. package/src/stateMetaStore.ts +0 -15
  98. package/src/transitionPath.ts +0 -440
  99. package/src/typeGuards.ts +0 -59
  100. package/src/types/RouterValidator.ts +0 -156
  101. package/src/types.ts +0 -77
  102. package/src/utils/createRequestScope.ts +0 -174
  103. package/src/utils/getStaticPaths.ts +0 -50
  104. package/src/utils/hydrateRouter.ts +0 -89
  105. package/src/utils/index.ts +0 -27
  106. package/src/utils/serializeRouterState.ts +0 -120
  107. package/src/utils/serializeState.ts +0 -63
  108. package/src/validation.ts +0 -12
  109. package/src/wiring/RouterWiringBuilder.ts +0 -275
  110. package/src/wiring/index.ts +0 -7
  111. package/src/wiring/types.ts +0 -47
  112. package/src/wiring/wireRouter.ts +0 -26
@@ -1,566 +0,0 @@
1
- // packages/core/src/namespaces/RoutesNamespace/routesStore.ts
2
-
3
- import { logger } from "@real-router/logger";
4
- import { createMatcher, createRouteTree, nodeToDefinition } from "route-tree";
5
-
6
- import { DEFAULT_ROUTE_NAME } from "./constants";
7
- import { resolveForwardChain } from "./forwardChain";
8
- import { createEmptyConfig, sanitizeRoute } from "./helpers";
9
-
10
- import type { RouteConfig, RoutesDependencies } from "./types";
11
- import type { GuardFnFactory, Route } from "../../types";
12
- import type { RouteLifecycleNamespace } from "../RouteLifecycleNamespace";
13
- import type { DefaultDependencies, Params } from "@real-router/types";
14
- import type {
15
- CreateMatcherOptions,
16
- Matcher,
17
- RouteDefinition,
18
- RouteTree,
19
- } from "route-tree";
20
-
21
- // =============================================================================
22
- // Interfaces
23
- // =============================================================================
24
-
25
- export interface RoutesStore<
26
- Dependencies extends DefaultDependencies = DefaultDependencies,
27
- > {
28
- readonly definitions: RouteDefinition[];
29
- readonly config: RouteConfig;
30
- tree: RouteTree;
31
- matcher: Matcher;
32
- resolvedForwardMap: Record<string, string>;
33
- routeCustomFields: Record<string, Record<string, unknown>>;
34
- rootPath: string;
35
- readonly matcherOptions: CreateMatcherOptions | undefined;
36
- depsStore: RoutesDependencies<Dependencies> | undefined;
37
- lifecycleNamespace: RouteLifecycleNamespace<Dependencies> | undefined;
38
- readonly pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>;
39
- readonly pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>;
40
- readonly treeOperations: {
41
- readonly commitTreeChanges: (store: RoutesStore<Dependencies>) => void;
42
- readonly resetStore: (store: RoutesStore<Dependencies>) => void;
43
- readonly nodeToDefinition: (node: RouteTree) => RouteDefinition;
44
- };
45
- }
46
-
47
- // =============================================================================
48
- // Tree operations
49
- // =============================================================================
50
-
51
- function rebuildTree(
52
- definitions: RouteDefinition[],
53
- rootPath: string,
54
- matcherOptions: CreateMatcherOptions | undefined,
55
- ): { tree: RouteTree; matcher: Matcher } {
56
- const tree = createRouteTree(DEFAULT_ROUTE_NAME, rootPath, definitions);
57
- const matcher = createMatcher(matcherOptions);
58
-
59
- matcher.registerTree(tree);
60
-
61
- return { tree, matcher };
62
- }
63
-
64
- export function rebuildTreeInPlace<
65
- Dependencies extends DefaultDependencies = DefaultDependencies,
66
- >(store: RoutesStore<Dependencies>): void {
67
- const result = rebuildTree(
68
- store.definitions,
69
- store.rootPath,
70
- store.matcherOptions,
71
- );
72
-
73
- store.tree = result.tree;
74
- store.matcher = result.matcher;
75
- }
76
-
77
- export function commitTreeChanges<
78
- Dependencies extends DefaultDependencies = DefaultDependencies,
79
- >(store: RoutesStore<Dependencies>): void {
80
- rebuildTreeInPlace(store);
81
- store.resolvedForwardMap = refreshForwardMap(store.config);
82
- }
83
-
84
- // =============================================================================
85
- // Store reset
86
- // =============================================================================
87
-
88
- /**
89
- * Clears all routes and resets config.
90
- * Does NOT clear lifecycle handlers or state — caller handles that.
91
- */
92
- export function resetStore<
93
- Dependencies extends DefaultDependencies = DefaultDependencies,
94
- >(store: RoutesStore<Dependencies>): void {
95
- clearRouteData(store);
96
- rebuildTreeInPlace(store);
97
- }
98
-
99
- /**
100
- * Clears route data without rebuilding the tree.
101
- * Used by replace() to avoid double rebuild (clearRouteData + commitTreeChanges).
102
- */
103
- export function clearRouteData<
104
- Dependencies extends DefaultDependencies = DefaultDependencies,
105
- >(store: RoutesStore<Dependencies>): void {
106
- store.definitions.length = 0;
107
-
108
- Object.assign(store.config, createEmptyConfig());
109
-
110
- store.resolvedForwardMap = Object.create(null) as Record<string, string>;
111
- store.routeCustomFields = Object.create(null) as Record<
112
- string,
113
- Record<string, unknown>
114
- >;
115
- }
116
-
117
- // =============================================================================
118
- // Forward map
119
- // =============================================================================
120
-
121
- export function refreshForwardMap(config: RouteConfig): Record<string, string> {
122
- const map = Object.create(null) as Record<string, string>;
123
-
124
- for (const fromRoute of Object.keys(config.forwardMap)) {
125
- map[fromRoute] = resolveForwardChain(fromRoute, config.forwardMap);
126
- }
127
-
128
- return map;
129
- }
130
-
131
- // =============================================================================
132
- // Route handler registration
133
- // =============================================================================
134
-
135
- /**
136
- * Throws if `forwardTo` is an async function (native or transpiled). Async
137
- * forwardTo callbacks break the synchronous matchPath/buildPath contract.
138
- * Runs inside `registerForwardTo`, which the prepare-phase build invokes via
139
- * `registerAllRouteHandlers` — so the check fires before any store mutation.
140
- */
141
- function assertForwardToNotAsync(forwardTo: unknown, fullName: string): void {
142
- if (typeof forwardTo !== "function") {
143
- return;
144
- }
145
-
146
- const isNativeAsync =
147
- (forwardTo as { constructor: { name: string } }).constructor.name ===
148
- "AsyncFunction";
149
- const isTranspiledAsync = (forwardTo as { toString: () => string })
150
- .toString()
151
- .includes("__awaiter");
152
-
153
- if (isNativeAsync || isTranspiledAsync) {
154
- throw new TypeError(
155
- `forwardTo callback cannot be async for route "${fullName}". ` +
156
- `Async functions break matchPath/buildPath.`,
157
- );
158
- }
159
- }
160
-
161
- function registerForwardTo<Dependencies extends DefaultDependencies>(
162
- route: Route<Dependencies>,
163
- fullName: string,
164
- config: RouteConfig,
165
- ): void {
166
- if (route.canActivate) {
167
- /* v8 ignore next -- @preserve: edge case, both string and function tested separately */
168
- const forwardTarget =
169
- typeof route.forwardTo === "string" ? route.forwardTo : "[dynamic]";
170
-
171
- logger.warn(
172
- "real-router",
173
- `Route "${fullName}" has both forwardTo and canActivate. ` +
174
- `canActivate will be ignored because forwardTo creates a redirect (industry standard). ` +
175
- `Move canActivate to the target route "${forwardTarget}".`,
176
- );
177
- }
178
-
179
- if (route.canDeactivate) {
180
- /* v8 ignore next -- @preserve: edge case, both string and function tested separately */
181
- const forwardTarget =
182
- typeof route.forwardTo === "string" ? route.forwardTo : "[dynamic]";
183
-
184
- logger.warn(
185
- "real-router",
186
- `Route "${fullName}" has both forwardTo and canDeactivate. ` +
187
- `canDeactivate will be ignored because forwardTo creates a redirect (industry standard). ` +
188
- `Move canDeactivate to the target route "${forwardTarget}".`,
189
- );
190
- }
191
-
192
- assertForwardToNotAsync(route.forwardTo, fullName);
193
-
194
- // forwardTo is guaranteed to exist at this point
195
- if (typeof route.forwardTo === "string") {
196
- config.forwardMap[fullName] = route.forwardTo;
197
- } else {
198
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
199
- config.forwardFnMap[fullName] = route.forwardTo!;
200
- }
201
- }
202
-
203
- function registerSingleRouteHandlers<Dependencies extends DefaultDependencies>(
204
- route: Route<Dependencies>,
205
- fullName: string,
206
- config: RouteConfig,
207
- routeCustomFields: Record<string, Record<string, unknown>>,
208
- pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>,
209
- pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>,
210
- ): void {
211
- const standardKeys = new Set([
212
- "name",
213
- "path",
214
- "children",
215
- "canActivate",
216
- "canDeactivate",
217
- "forwardTo",
218
- "encodeParams",
219
- "decodeParams",
220
- "defaultParams",
221
- ]);
222
- const customFields = Object.fromEntries(
223
- Object.entries(route).filter(([key]) => !standardKeys.has(key)),
224
- );
225
-
226
- if (Object.keys(customFields).length > 0) {
227
- routeCustomFields[fullName] = customFields;
228
- }
229
-
230
- // Guards are collected here and registered into the lifecycle later — by
231
- // `adoptRouteArtifacts` (add/replace) or `setDependencies` (initial routes) —
232
- // so the build stays a pure, side-effect-free preparation step.
233
- if (route.canActivate) {
234
- pendingCanActivate.set(fullName, route.canActivate);
235
- }
236
-
237
- if (route.canDeactivate) {
238
- pendingCanDeactivate.set(fullName, route.canDeactivate);
239
- }
240
-
241
- if (route.forwardTo) {
242
- registerForwardTo(route, fullName, config);
243
- }
244
-
245
- if (route.decodeParams) {
246
- config.decoders[fullName] = (params: Params): Params =>
247
- route.decodeParams?.(params) ?? params;
248
- }
249
-
250
- if (route.encodeParams) {
251
- config.encoders[fullName] = (params: Params): Params =>
252
- route.encodeParams?.(params) ?? params;
253
- }
254
-
255
- if (route.defaultParams) {
256
- config.defaultParams[fullName] = route.defaultParams;
257
- }
258
- }
259
-
260
- function registerAllRouteHandlers<Dependencies extends DefaultDependencies>(
261
- routes: readonly Route<Dependencies>[],
262
- config: RouteConfig,
263
- routeCustomFields: Record<string, Record<string, unknown>>,
264
- pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>,
265
- pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>,
266
- parentName = "",
267
- ): void {
268
- for (const route of routes) {
269
- const fullName = parentName ? `${parentName}.${route.name}` : route.name;
270
-
271
- registerSingleRouteHandlers(
272
- route,
273
- fullName,
274
- config,
275
- routeCustomFields,
276
- pendingCanActivate,
277
- pendingCanDeactivate,
278
- );
279
-
280
- if (route.children) {
281
- registerAllRouteHandlers(
282
- route.children,
283
- config,
284
- routeCustomFields,
285
- pendingCanActivate,
286
- pendingCanDeactivate,
287
- fullName,
288
- );
289
- }
290
- }
291
- }
292
-
293
- // =============================================================================
294
- // Prepare-then-commit (issue #698)
295
- //
296
- // add()/replace() build the complete new store state into LOCAL structures, and
297
- // only swap it into the store once every core-level error has surfaced from the
298
- // build itself (async/circular forwardTo throw in registerAllRouteHandlers /
299
- // refreshForwardMap; invalid path constraint throws in rebuildTree). The store
300
- // is mutated only by `adoptRouteArtifacts`, which cannot throw — so a rejected
301
- // build leaves the existing routes untouched. The two silent-corruption cases
302
- // route-tree never throws on (duplicate name vs an existing route, missing
303
- // parent) are caught up front by `assertAddable`.
304
- // =============================================================================
305
-
306
- /**
307
- * The fully-built, ready-to-swap result of preparing a route mutation. Holds
308
- * everything `adoptRouteArtifacts` assigns into the store.
309
- */
310
- interface RouteArtifacts<
311
- Dependencies extends DefaultDependencies = DefaultDependencies,
312
- > {
313
- readonly definitions: RouteDefinition[];
314
- readonly config: RouteConfig;
315
- readonly routeCustomFields: Record<string, Record<string, unknown>>;
316
- readonly pendingCanActivate: Map<string, GuardFnFactory<Dependencies>>;
317
- readonly pendingCanDeactivate: Map<string, GuardFnFactory<Dependencies>>;
318
- readonly tree: RouteTree;
319
- readonly matcher: Matcher;
320
- readonly resolvedForwardMap: Record<string, string>;
321
- }
322
-
323
- /** Null-proto shallow clone of a RouteConfig (preserves the 5 maps' contents). */
324
- function cloneConfig(config: RouteConfig): RouteConfig {
325
- const clone = createEmptyConfig();
326
-
327
- Object.assign(clone.decoders, config.decoders);
328
- Object.assign(clone.encoders, config.encoders);
329
- Object.assign(clone.defaultParams, config.defaultParams);
330
- Object.assign(clone.forwardMap, config.forwardMap);
331
- Object.assign(clone.forwardFnMap, config.forwardFnMap);
332
-
333
- return clone;
334
- }
335
-
336
- /**
337
- * Returns a new definitions array with `added` inserted, without mutating the
338
- * input. For a top-level add the existing definitions are shallow-copied and
339
- * `added` appended. For a parented add the spine down to the parent is cloned
340
- * (siblings/other branches are shared by reference) and `added` appended to the
341
- * parent's children. Caller guarantees the parent path exists (see assertAddable).
342
- */
343
- function insertAddedDefinitions(
344
- definitions: readonly RouteDefinition[],
345
- added: RouteDefinition[],
346
- parentSegments: readonly string[],
347
- ): RouteDefinition[] {
348
- if (parentSegments.length === 0) {
349
- return [...definitions, ...added];
350
- }
351
-
352
- const [head, ...rest] = parentSegments;
353
-
354
- return definitions.map((def) => {
355
- if (def.name !== head) {
356
- return def;
357
- }
358
-
359
- const children = def.children ?? [];
360
-
361
- return {
362
- ...def,
363
- children:
364
- rest.length === 0
365
- ? [...children, ...added]
366
- : insertAddedDefinitions(children, added, rest),
367
- };
368
- });
369
- }
370
-
371
- /** Depth-first walk yielding each route's full dotted name (no side effects). */
372
- function walkRouteNames<Dependencies extends DefaultDependencies>(
373
- routes: readonly Route<Dependencies>[],
374
- parentName: string,
375
- onName: (fullName: string) => void,
376
- ): void {
377
- for (const route of routes) {
378
- const fullName = parentName ? `${parentName}.${route.name}` : route.name;
379
-
380
- onName(fullName);
381
-
382
- if (route.children) {
383
- walkRouteNames(route.children, fullName, onName);
384
- }
385
- }
386
- }
387
-
388
- /**
389
- * Up-front guard for `add` against the two corruptions route-tree stays silent
390
- * on: a missing `parent`, and a name that collides with an EXISTING route
391
- * (which would otherwise be silently overwritten). Throws before any build.
392
- */
393
- export function assertAddable<Dependencies extends DefaultDependencies>(
394
- store: RoutesStore<Dependencies>,
395
- routes: readonly Route<Dependencies>[],
396
- parentName: string | undefined,
397
- ): void {
398
- if (parentName !== undefined && !store.matcher.hasRoute(parentName)) {
399
- throw new Error(
400
- `[router.addRoute] Parent route "${parentName}" does not exist`,
401
- );
402
- }
403
-
404
- walkRouteNames(routes, parentName ?? "", (fullName) => {
405
- if (store.matcher.hasRoute(fullName)) {
406
- throw new Error(`[router.addRoute] Route "${fullName}" already exists`);
407
- }
408
- });
409
- }
410
-
411
- /**
412
- * Builds RouteArtifacts from a final definitions array and the routes whose
413
- * handlers (config + guards) populate `config`/`routeCustomFields`. Guards are
414
- * collected into the returned pending maps (depsStore is intentionally omitted
415
- * so nothing compiles or touches the lifecycle here). THROWS on async/circular
416
- * forwardTo and invalid path constraint — before the caller mutates the store.
417
- */
418
- function buildArtifacts<Dependencies extends DefaultDependencies>(
419
- definitions: RouteDefinition[],
420
- routesForHandlers: readonly Route<Dependencies>[],
421
- config: RouteConfig,
422
- routeCustomFields: Record<string, Record<string, unknown>>,
423
- handlerParentName: string,
424
- rootPath: string,
425
- matcherOptions: CreateMatcherOptions | undefined,
426
- ): RouteArtifacts<Dependencies> {
427
- const pendingCanActivate = new Map<string, GuardFnFactory<Dependencies>>();
428
- const pendingCanDeactivate = new Map<string, GuardFnFactory<Dependencies>>();
429
-
430
- registerAllRouteHandlers(
431
- routesForHandlers,
432
- config,
433
- routeCustomFields,
434
- pendingCanActivate,
435
- pendingCanDeactivate,
436
- handlerParentName,
437
- );
438
-
439
- const resolvedForwardMap = refreshForwardMap(config);
440
- const { tree, matcher } = rebuildTree(definitions, rootPath, matcherOptions);
441
-
442
- return {
443
- definitions,
444
- config,
445
- routeCustomFields,
446
- pendingCanActivate,
447
- pendingCanDeactivate,
448
- tree,
449
- matcher,
450
- resolvedForwardMap,
451
- };
452
- }
453
-
454
- /** Builds the merged artifacts for an incremental `add` (existing ∪ new). */
455
- export function buildAddArtifacts<Dependencies extends DefaultDependencies>(
456
- store: RoutesStore<Dependencies>,
457
- routes: readonly Route<Dependencies>[],
458
- parentName: string | undefined,
459
- ): RouteArtifacts<Dependencies> {
460
- const definitions = insertAddedDefinitions(
461
- store.definitions,
462
- routes.map((route) => sanitizeRoute(route)),
463
- parentName === undefined ? [] : parentName.split("."),
464
- );
465
-
466
- return buildArtifacts(
467
- definitions,
468
- routes,
469
- cloneConfig(store.config),
470
- Object.assign(
471
- Object.create(null) as Record<string, Record<string, unknown>>,
472
- store.routeCustomFields,
473
- ),
474
- parentName ?? "",
475
- store.rootPath,
476
- store.matcherOptions,
477
- );
478
- }
479
-
480
- /** Builds the fresh artifacts for a full `replace` (standalone new set). */
481
- export function buildReplaceArtifacts<Dependencies extends DefaultDependencies>(
482
- routes: readonly Route<Dependencies>[],
483
- rootPath: string,
484
- matcherOptions: CreateMatcherOptions | undefined,
485
- ): RouteArtifacts<Dependencies> {
486
- return buildArtifacts(
487
- routes.map((route) => sanitizeRoute(route)),
488
- routes,
489
- createEmptyConfig(),
490
- Object.create(null) as Record<string, Record<string, unknown>>,
491
- "",
492
- rootPath,
493
- matcherOptions,
494
- );
495
- }
496
-
497
- /**
498
- * Commits prepared artifacts into the store in place. Pure assignment — never
499
- * throws — so it is the single atomic swap point of the prepare-then-commit
500
- * pipeline. Guard registration is deferred to here (the build collected guards
501
- * without compiling); `depsStore` is always set on a wired router, which is the
502
- * only path that reaches `add`/`replace`.
503
- */
504
- export function adoptRouteArtifacts<Dependencies extends DefaultDependencies>(
505
- store: RoutesStore<Dependencies>,
506
- artifacts: RouteArtifacts<Dependencies>,
507
- ): void {
508
- store.definitions.length = 0;
509
-
510
- for (const def of artifacts.definitions) {
511
- store.definitions.push(def);
512
- }
513
-
514
- Object.assign(store.config, artifacts.config);
515
- store.routeCustomFields = artifacts.routeCustomFields;
516
- store.tree = artifacts.tree;
517
- store.matcher = artifacts.matcher;
518
- store.resolvedForwardMap = artifacts.resolvedForwardMap;
519
-
520
- // 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)
521
- const deps = store.depsStore!;
522
-
523
- for (const [name, handler] of artifacts.pendingCanActivate) {
524
- deps.addActivateGuard(name, handler);
525
- }
526
-
527
- for (const [name, handler] of artifacts.pendingCanDeactivate) {
528
- deps.addDeactivateGuard(name, handler);
529
- }
530
- }
531
-
532
- // =============================================================================
533
- // Factory
534
- // =============================================================================
535
-
536
- export function createRoutesStore<
537
- Dependencies extends DefaultDependencies = DefaultDependencies,
538
- >(
539
- routes: Route<Dependencies>[],
540
- matcherOptions?: CreateMatcherOptions,
541
- ): RoutesStore<Dependencies> {
542
- // Initial routes are a standalone set at rootPath "" — same build the
543
- // prepare-then-commit `replace` path uses. Guards land in the pending maps
544
- // (depsStore is wired later via setDependencies, which flushes them).
545
- const artifacts = buildReplaceArtifacts(routes, "", matcherOptions);
546
-
547
- return {
548
- definitions: artifacts.definitions,
549
- config: artifacts.config,
550
- tree: artifacts.tree,
551
- matcher: artifacts.matcher,
552
- resolvedForwardMap: artifacts.resolvedForwardMap,
553
- routeCustomFields: artifacts.routeCustomFields,
554
- rootPath: "",
555
- matcherOptions,
556
- depsStore: undefined,
557
- lifecycleNamespace: undefined,
558
- pendingCanActivate: artifacts.pendingCanActivate,
559
- pendingCanDeactivate: artifacts.pendingCanDeactivate,
560
- treeOperations: {
561
- commitTreeChanges,
562
- resetStore,
563
- nodeToDefinition,
564
- },
565
- };
566
- }
@@ -1,81 +0,0 @@
1
- // packages/core/src/namespaces/RoutesNamespace/types.ts
2
-
3
- import type { GuardFnFactory } from "../../types";
4
- import type {
5
- DefaultDependencies,
6
- ForwardToCallback,
7
- Params,
8
- SimpleState,
9
- State,
10
- } from "@real-router/types";
11
-
12
- /**
13
- * Dependencies injected into RoutesNamespace.
14
- *
15
- * These are function references from the Router facade,
16
- * avoiding the need to pass the entire Router object.
17
- */
18
- export interface RoutesDependencies<
19
- Dependencies extends DefaultDependencies = DefaultDependencies,
20
- > {
21
- /** Register canActivate handler for a route */
22
- addActivateGuard: (
23
- name: string,
24
- handler: GuardFnFactory<Dependencies>,
25
- ) => void;
26
-
27
- /** Register canDeactivate handler for a route */
28
- addDeactivateGuard: (
29
- name: string,
30
- handler: GuardFnFactory<Dependencies>,
31
- ) => void;
32
-
33
- /** Create state object */
34
- makeState: <P extends Params = Params>(
35
- name: string,
36
- params?: P,
37
- path?: string,
38
- meta?: Record<string, Record<string, "url" | "query">>,
39
- ) => State<P>;
40
-
41
- /** Get current router state */
42
- getState: () => State | undefined;
43
-
44
- /** Compare two states for equality */
45
- areStatesEqual: (
46
- state1: State | undefined,
47
- state2: State | undefined,
48
- ignoreQueryParams?: boolean,
49
- ) => boolean;
50
-
51
- /** Get a dependency by name */
52
- getDependency: <K extends keyof Dependencies>(name: K) => Dependencies[K];
53
-
54
- /** Forward state through facade (allows plugin interception) */
55
- forwardState: <P extends Params = Params>(
56
- name: string,
57
- params: P,
58
- ) => SimpleState<P>;
59
- }
60
-
61
- /**
62
- * Configuration storage for routes.
63
- * Stores decoders, encoders, default params, and forward mappings.
64
- */
65
- export interface RouteConfig {
66
- /** Custom param decoders per route */
67
- decoders: Record<string, (params: Params) => Params>;
68
-
69
- /** Custom param encoders per route */
70
- encoders: Record<string, (params: Params) => Params>;
71
-
72
- /** Default params per route */
73
- defaultParams: Record<string, Params>;
74
-
75
- /** Forward mappings (source -> target) */
76
- forwardMap: Record<string, string>;
77
-
78
- /** Dynamic forward callbacks (source -> callback) */
79
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
80
- forwardFnMap: Record<string, ForwardToCallback<any>>;
81
- }