@real-router/core 0.55.0 → 0.57.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 (145) hide show
  1. package/dist/cjs/Router-BSGzVINO.js +6 -0
  2. package/dist/cjs/Router-BSGzVINO.js.map +1 -0
  3. package/dist/{esm/Router-Dg-zk8AS.d.mts → cjs/Router-hW6ivqrX.d.ts} +2 -2
  4. package/dist/cjs/Router-hW6ivqrX.d.ts.map +1 -0
  5. package/dist/cjs/api.d.ts +2 -2
  6. package/dist/cjs/api.d.ts.map +1 -1
  7. package/dist/cjs/api.js +1 -1
  8. package/dist/cjs/api.js.map +1 -1
  9. package/dist/cjs/{cloneRouter-C9Rth_8U.js → cloneRouter-7z-60z_f.js} +2 -2
  10. package/dist/cjs/{cloneRouter-C9Rth_8U.js.map → cloneRouter-7z-60z_f.js.map} +1 -1
  11. package/dist/cjs/{index-C-i6vx5Y.d.ts → index-BWUmnecT.d.ts} +1 -2
  12. package/dist/cjs/index-BWUmnecT.d.ts.map +1 -0
  13. package/dist/cjs/{RouterError-WhCzIWuc.d.ts → index-CYpAZCoc.d.ts} +19 -2
  14. package/dist/cjs/index-CYpAZCoc.d.ts.map +1 -0
  15. package/dist/cjs/{index-K1U_fqfJ.d.ts → index-D2WRiyWS.d.ts} +2 -2
  16. package/dist/cjs/index-D2WRiyWS.d.ts.map +1 -0
  17. package/dist/cjs/index.d.ts +5 -5
  18. package/dist/cjs/index.js +1 -1
  19. package/dist/cjs/{internals-CWMOL1B8.js → internals-DJjgSePy.js} +2 -2
  20. package/dist/cjs/internals-DJjgSePy.js.map +1 -0
  21. package/dist/cjs/utils.d.ts +1 -1
  22. package/dist/cjs/utils.js +1 -1
  23. package/dist/cjs/utils.js.map +1 -1
  24. package/dist/cjs/validation.d.ts +17 -5
  25. package/dist/cjs/validation.d.ts.map +1 -1
  26. package/dist/cjs/validation.js +1 -1
  27. package/dist/esm/Router-B7txWo9N.mjs +6 -0
  28. package/dist/esm/Router-B7txWo9N.mjs.map +1 -0
  29. package/dist/{cjs/Router-Dg-zk8AS.d.ts → esm/Router-hW6ivqrX.d.mts} +2 -2
  30. package/dist/esm/Router-hW6ivqrX.d.mts.map +1 -0
  31. package/dist/esm/api.d.mts +2 -2
  32. package/dist/esm/api.d.mts.map +1 -1
  33. package/dist/esm/api.mjs +1 -1
  34. package/dist/esm/api.mjs.map +1 -1
  35. package/dist/esm/{cloneRouter-BYNiwchg.mjs → cloneRouter-BNCQ7tIa.mjs} +2 -2
  36. package/dist/esm/{cloneRouter-BYNiwchg.mjs.map → cloneRouter-BNCQ7tIa.mjs.map} +1 -1
  37. package/dist/esm/{index-C-i6vx5Y.d.mts → index-BWUmnecT.d.mts} +1 -2
  38. package/dist/esm/index-BWUmnecT.d.mts.map +1 -0
  39. package/dist/esm/{RouterError-WhCzIWuc.d.mts → index-CYpAZCoc.d.mts} +19 -2
  40. package/dist/esm/index-CYpAZCoc.d.mts.map +1 -0
  41. package/dist/esm/{index-DKzxav48.d.mts → index-CjWKWPY6.d.mts} +2 -2
  42. package/dist/esm/index-CjWKWPY6.d.mts.map +1 -0
  43. package/dist/esm/index.d.mts +5 -5
  44. package/dist/esm/index.mjs +1 -1
  45. package/dist/esm/index.mjs.map +1 -1
  46. package/dist/esm/{internals-DT4mneSz.mjs → internals-C8mRvTxc.mjs} +2 -2
  47. package/dist/esm/internals-C8mRvTxc.mjs.map +1 -0
  48. package/dist/esm/utils.d.mts +1 -1
  49. package/dist/esm/utils.mjs +1 -1
  50. package/dist/esm/utils.mjs.map +1 -1
  51. package/dist/esm/validation.d.mts +17 -5
  52. package/dist/esm/validation.d.mts.map +1 -1
  53. package/dist/esm/validation.mjs +1 -1
  54. package/package.json +3 -4
  55. package/dist/cjs/Router-C7eE1kIK.js +0 -6
  56. package/dist/cjs/Router-C7eE1kIK.js.map +0 -1
  57. package/dist/cjs/Router-Dg-zk8AS.d.ts.map +0 -1
  58. package/dist/cjs/RouterError-WhCzIWuc.d.ts.map +0 -1
  59. package/dist/cjs/index-C-i6vx5Y.d.ts.map +0 -1
  60. package/dist/cjs/index-K1U_fqfJ.d.ts.map +0 -1
  61. package/dist/cjs/internals-CWMOL1B8.js.map +0 -1
  62. package/dist/esm/Router-Dg-zk8AS.d.mts.map +0 -1
  63. package/dist/esm/Router-DiZbYMLx.mjs +0 -6
  64. package/dist/esm/Router-DiZbYMLx.mjs.map +0 -1
  65. package/dist/esm/RouterError-WhCzIWuc.d.mts.map +0 -1
  66. package/dist/esm/index-C-i6vx5Y.d.mts.map +0 -1
  67. package/dist/esm/index-DKzxav48.d.mts.map +0 -1
  68. package/dist/esm/internals-DT4mneSz.mjs.map +0 -1
  69. package/src/Router.ts +0 -725
  70. package/src/RouterError.ts +0 -324
  71. package/src/api/cloneRouter.ts +0 -159
  72. package/src/api/getDependenciesApi.ts +0 -160
  73. package/src/api/getLifecycleApi.ts +0 -65
  74. package/src/api/getPluginApi.ts +0 -228
  75. package/src/api/getRoutesApi.ts +0 -546
  76. package/src/api/helpers.ts +0 -10
  77. package/src/api/index.ts +0 -16
  78. package/src/api/types.ts +0 -12
  79. package/src/constants.ts +0 -101
  80. package/src/createRouter.ts +0 -32
  81. package/src/fsm/index.ts +0 -5
  82. package/src/fsm/routerFSM.ts +0 -130
  83. package/src/getNavigator.ts +0 -30
  84. package/src/guards.ts +0 -46
  85. package/src/helpers.ts +0 -197
  86. package/src/index.ts +0 -50
  87. package/src/internals.ts +0 -200
  88. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +0 -30
  89. package/src/namespaces/DependenciesNamespace/index.ts +0 -5
  90. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +0 -485
  91. package/src/namespaces/EventBusNamespace/index.ts +0 -5
  92. package/src/namespaces/EventBusNamespace/types.ts +0 -11
  93. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -552
  94. package/src/namespaces/NavigationNamespace/constants.ts +0 -55
  95. package/src/namespaces/NavigationNamespace/index.ts +0 -5
  96. package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +0 -108
  97. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +0 -124
  98. package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +0 -283
  99. package/src/namespaces/NavigationNamespace/types.ts +0 -110
  100. package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +0 -28
  101. package/src/namespaces/OptionsNamespace/constants.ts +0 -19
  102. package/src/namespaces/OptionsNamespace/helpers.ts +0 -50
  103. package/src/namespaces/OptionsNamespace/index.ts +0 -7
  104. package/src/namespaces/OptionsNamespace/validators.ts +0 -13
  105. package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +0 -291
  106. package/src/namespaces/PluginsNamespace/constants.ts +0 -34
  107. package/src/namespaces/PluginsNamespace/index.ts +0 -7
  108. package/src/namespaces/PluginsNamespace/types.ts +0 -22
  109. package/src/namespaces/PluginsNamespace/validators.ts +0 -28
  110. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +0 -558
  111. package/src/namespaces/RouteLifecycleNamespace/index.ts +0 -5
  112. package/src/namespaces/RouteLifecycleNamespace/types.ts +0 -10
  113. package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -81
  114. package/src/namespaces/RouterLifecycleNamespace/constants.ts +0 -25
  115. package/src/namespaces/RouterLifecycleNamespace/index.ts +0 -5
  116. package/src/namespaces/RouterLifecycleNamespace/types.ts +0 -30
  117. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +0 -582
  118. package/src/namespaces/RoutesNamespace/constants.ts +0 -6
  119. package/src/namespaces/RoutesNamespace/forwardChain.ts +0 -34
  120. package/src/namespaces/RoutesNamespace/helpers.ts +0 -204
  121. package/src/namespaces/RoutesNamespace/index.ts +0 -11
  122. package/src/namespaces/RoutesNamespace/routeGuards.ts +0 -62
  123. package/src/namespaces/RoutesNamespace/routesStore.ts +0 -566
  124. package/src/namespaces/RoutesNamespace/types.ts +0 -81
  125. package/src/namespaces/StateNamespace/StateNamespace.ts +0 -224
  126. package/src/namespaces/StateNamespace/helpers.ts +0 -24
  127. package/src/namespaces/StateNamespace/index.ts +0 -5
  128. package/src/namespaces/StateNamespace/types.ts +0 -15
  129. package/src/namespaces/index.ts +0 -35
  130. package/src/stateMetaStore.ts +0 -15
  131. package/src/transitionPath.ts +0 -436
  132. package/src/typeGuards.ts +0 -59
  133. package/src/types/RouterValidator.ts +0 -156
  134. package/src/types.ts +0 -69
  135. package/src/utils/createRequestScope.ts +0 -174
  136. package/src/utils/getStaticPaths.ts +0 -50
  137. package/src/utils/hydrateRouter.ts +0 -89
  138. package/src/utils/index.ts +0 -27
  139. package/src/utils/serializeRouterState.ts +0 -120
  140. package/src/utils/serializeState.ts +0 -63
  141. package/src/validation.ts +0 -12
  142. package/src/wiring/RouterWiringBuilder.ts +0 -275
  143. package/src/wiring/index.ts +0 -7
  144. package/src/wiring/types.ts +0 -47
  145. package/src/wiring/wireRouter.ts +0 -26
@@ -1,32 +0,0 @@
1
- // packages/core/src/createRouter.ts
2
-
3
- import { Router } from "./Router";
4
-
5
- import type { Route } from "./types";
6
- import type { DefaultDependencies, Options } from "@real-router/types";
7
-
8
- /**
9
- * Creates a new router instance.
10
- *
11
- * @param routes - Array of route definitions
12
- * @param options - Router configuration options
13
- * @param dependencies - Dependencies to inject into the router
14
- * @returns A new Router instance
15
- *
16
- * @example
17
- * const router = createRouter([
18
- * { name: 'home', path: '/' },
19
- * { name: 'users', path: '/users' },
20
- * ]);
21
- *
22
- * router.start('/');
23
- */
24
- export const createRouter = <
25
- Dependencies extends DefaultDependencies = DefaultDependencies,
26
- >(
27
- routes: Route<Dependencies>[] = [],
28
- options: Partial<Options> = {},
29
- dependencies: Dependencies = {} as Dependencies,
30
- ): Router<Dependencies> => {
31
- return new Router<Dependencies>(routes, options, dependencies);
32
- };
package/src/fsm/index.ts DELETED
@@ -1,5 +0,0 @@
1
- // packages/core/src/fsm/index.ts
2
-
3
- export { createRouterFSM, routerStates, routerEvents } from "./routerFSM";
4
-
5
- export type { RouterEvent, RouterPayloads, RouterState } from "./routerFSM";
@@ -1,130 +0,0 @@
1
- // packages/core/src/fsm/routerFSM.ts
2
-
3
- import { FSM } from "@real-router/fsm";
4
-
5
- import type { FSMConfig } from "@real-router/fsm";
6
-
7
- /**
8
- * Router FSM states.
9
- *
10
- * - IDLE: Router not started or stopped
11
- * - STARTING: Router is initializing
12
- * - READY: Router is ready for navigation
13
- * - TRANSITION_STARTED: Navigation in progress (before deactivation guards)
14
- * - LEAVE_APPROVED: Deactivation guards passed, activation guards pending
15
- * - DISPOSED: Router has been disposed (R2+)
16
- */
17
- export const routerStates = {
18
- IDLE: "IDLE",
19
- STARTING: "STARTING",
20
- READY: "READY",
21
- TRANSITION_STARTED: "TRANSITION_STARTED",
22
- LEAVE_APPROVED: "LEAVE_APPROVED",
23
- DISPOSED: "DISPOSED",
24
- } as const;
25
-
26
- export type RouterState = (typeof routerStates)[keyof typeof routerStates];
27
-
28
- /**
29
- * Router FSM events.
30
- *
31
- * - START: Begin router initialization
32
- * - STARTED: Router initialization complete
33
- * - NAVIGATE: Begin navigation
34
- * - COMPLETE: Navigation completed successfully
35
- * - FAIL: Navigation or initialization failed
36
- * - CANCEL: Navigation cancelled
37
- * - STOP: Stop router
38
- * - DISPOSE: Dispose router (R2+)
39
- */
40
- export const routerEvents = {
41
- START: "START",
42
- STARTED: "STARTED",
43
- NAVIGATE: "NAVIGATE",
44
- LEAVE_APPROVE: "LEAVE_APPROVE",
45
- COMPLETE: "COMPLETE",
46
- FAIL: "FAIL",
47
- CANCEL: "CANCEL",
48
- STOP: "STOP",
49
- DISPOSE: "DISPOSE",
50
- } as const;
51
-
52
- export type RouterEvent = (typeof routerEvents)[keyof typeof routerEvents];
53
-
54
- /**
55
- * Typed payloads for router FSM events.
56
- *
57
- * Events without entries have no payload.
58
- */
59
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- payloads stored in EventBusNamespace fields (N8+N9 optimization)
60
- export interface RouterPayloads {}
61
-
62
- /**
63
- * Router FSM configuration.
64
- *
65
- * Transitions:
66
- * - IDLE → STARTING (START), DISPOSED (DISPOSE)
67
- * - STARTING → READY (STARTED), IDLE (FAIL), DISPOSED (DISPOSE)
68
- * - READY → TRANSITION_STARTED (NAVIGATE), READY (FAIL, self-loop for early validation errors), IDLE (STOP), DISPOSED (DISPOSE)
69
- * - TRANSITION_STARTED → LEAVE_APPROVED (LEAVE_APPROVE), TRANSITION_STARTED (NAVIGATE, self-loop), READY (CANCEL, FAIL), DISPOSED (DISPOSE)
70
- * - LEAVE_APPROVED → READY (COMPLETE, CANCEL, FAIL), TRANSITION_STARTED (NAVIGATE), DISPOSED (DISPOSE)
71
- * - DISPOSED → (no transitions)
72
- *
73
- * DISPOSE is wired from every non-DISPOSED state so `router.dispose()` always
74
- * settles the FSM at DISPOSED. The facade orchestrates cleanup through IDLE
75
- * for healthy flows; the direct transitions guarantee the FSM is not left
76
- * stuck if cleanup is skipped (e.g. dispose mid-STARTING when the start
77
- * pipeline threw before STARTED/FAIL).
78
- */
79
- const routerFSMConfig: FSMConfig<RouterState, RouterEvent, null> = {
80
- initial: routerStates.IDLE,
81
- context: null,
82
- transitions: {
83
- [routerStates.IDLE]: {
84
- [routerEvents.START]: routerStates.STARTING,
85
- [routerEvents.DISPOSE]: routerStates.DISPOSED,
86
- },
87
- [routerStates.STARTING]: {
88
- [routerEvents.STARTED]: routerStates.READY,
89
- [routerEvents.FAIL]: routerStates.IDLE,
90
- [routerEvents.DISPOSE]: routerStates.DISPOSED,
91
- },
92
- [routerStates.READY]: {
93
- [routerEvents.NAVIGATE]: routerStates.TRANSITION_STARTED,
94
- [routerEvents.FAIL]: routerStates.READY,
95
- [routerEvents.STOP]: routerStates.IDLE,
96
- [routerEvents.DISPOSE]: routerStates.DISPOSED,
97
- },
98
- [routerStates.TRANSITION_STARTED]: {
99
- [routerEvents.NAVIGATE]: routerStates.TRANSITION_STARTED,
100
- [routerEvents.LEAVE_APPROVE]: routerStates.LEAVE_APPROVED,
101
- [routerEvents.CANCEL]: routerStates.READY,
102
- [routerEvents.FAIL]: routerStates.READY,
103
- [routerEvents.DISPOSE]: routerStates.DISPOSED,
104
- },
105
- [routerStates.LEAVE_APPROVED]: {
106
- [routerEvents.NAVIGATE]: routerStates.TRANSITION_STARTED,
107
- [routerEvents.COMPLETE]: routerStates.READY,
108
- [routerEvents.CANCEL]: routerStates.READY,
109
- [routerEvents.FAIL]: routerStates.READY,
110
- [routerEvents.DISPOSE]: routerStates.DISPOSED,
111
- },
112
- [routerStates.DISPOSED]: {},
113
- },
114
- };
115
-
116
- /**
117
- * Factory function to create a router FSM instance.
118
- *
119
- * @returns FSM instance with initial state "IDLE"
120
- */
121
- export function createRouterFSM(): FSM<
122
- RouterState,
123
- RouterEvent,
124
- null,
125
- RouterPayloads
126
- > {
127
- return new FSM<RouterState, RouterEvent, null, RouterPayloads>(
128
- routerFSMConfig,
129
- );
130
- }
@@ -1,30 +0,0 @@
1
- import type {
2
- Navigator,
3
- DefaultDependencies,
4
- Router,
5
- } from "@real-router/types";
6
-
7
- const cache = new WeakMap<Router, Navigator>();
8
-
9
- export const getNavigator = <
10
- Dependencies extends DefaultDependencies = DefaultDependencies,
11
- >(
12
- router: Router<Dependencies>,
13
- ): Navigator => {
14
- let nav = cache.get(router);
15
-
16
- if (!nav) {
17
- nav = Object.freeze({
18
- navigate: router.navigate,
19
- getState: router.getState,
20
- isActiveRoute: router.isActiveRoute,
21
- canNavigateTo: router.canNavigateTo,
22
- subscribe: router.subscribe,
23
- subscribeLeave: router.subscribeLeave,
24
- isLeaveApproved: router.isLeaveApproved,
25
- } as Navigator);
26
- cache.set(router, nav);
27
- }
28
-
29
- return nav;
30
- };
package/src/guards.ts DELETED
@@ -1,46 +0,0 @@
1
- // packages/core/src/guards.ts
2
-
3
- import type { Route } from "./types";
4
- import type { RouterValidator } from "./types/RouterValidator";
5
-
6
- export function guardDependencies(deps: unknown): void {
7
- if (
8
- !deps ||
9
- typeof deps !== "object" ||
10
- (deps as { constructor: unknown }).constructor !== Object
11
- ) {
12
- throw new TypeError("dependencies must be a plain object");
13
- }
14
- for (const key in deps as Record<string, unknown>) {
15
- if (Object.getOwnPropertyDescriptor(deps, key)?.get) {
16
- throw new TypeError(`dependencies cannot contain getters: "${key}"`);
17
- }
18
- }
19
- }
20
-
21
- /* eslint-disable @typescript-eslint/no-explicit-any -- accepts any Route type */
22
- export function guardRouteStructure(
23
- routes: Route<any>[],
24
- validator?: RouterValidator | null,
25
- ): void {
26
- /* eslint-enable @typescript-eslint/no-explicit-any */
27
- for (const route of routes) {
28
- const routeValue: unknown = route;
29
-
30
- if (
31
- routeValue === null ||
32
- typeof routeValue !== "object" ||
33
- Array.isArray(routeValue)
34
- ) {
35
- throw new TypeError("route must be a non-array object");
36
- }
37
-
38
- validator?.routes.guardRouteCallbacks(route as Route);
39
- validator?.routes.guardNoAsyncCallbacks(route as Route);
40
- const children = (route as Route).children;
41
-
42
- if (children) {
43
- guardRouteStructure(children, validator);
44
- }
45
- }
46
- }
package/src/helpers.ts DELETED
@@ -1,197 +0,0 @@
1
- // packages/core/src/helpers.ts
2
-
3
- import { DEFAULT_LIMITS } from "./constants";
4
-
5
- import type { Limits } from "./types";
6
- import type { Params, State, LimitsConfig } from "@real-router/types";
7
-
8
- // =============================================================================
9
- // State Helpers
10
- // =============================================================================
11
-
12
- /**
13
- * Structural type guard for State object.
14
- * Only checks required fields exist with correct types.
15
- * Does NOT validate params serializability (allows circular refs).
16
- *
17
- * Use `isState` from type-guards for full validation (serializable params).
18
- * Use this for internal operations like deepFreezeState that handle any object structure.
19
- *
20
- * @param value - Value to check
21
- * @returns true if value has State structure
22
- * @internal
23
- */
24
- function isStateStructural(value: unknown): value is State {
25
- if (value === null || typeof value !== "object") {
26
- return false;
27
- }
28
-
29
- const obj = value as Record<string, unknown>;
30
-
31
- return (
32
- typeof obj.name === "string" &&
33
- typeof obj.path === "string" &&
34
- typeof obj.params === "object" &&
35
- obj.params !== null
36
- );
37
- }
38
-
39
- /**
40
- * Deep freezes State object to prevent mutations.
41
- * Creates a deep clone first, then recursively freezes the clone and all nested objects.
42
- * Uses simple recursive freezing after cloning (no need for WeakSet since clone has no circular refs).
43
- *
44
- * @param state - The State object to freeze
45
- * @returns A frozen deep clone of the state
46
- * @throws {TypeError} If state is not a valid State object
47
- *
48
- * @example
49
- * const state = { name: 'home', params: {}, path: '/' };
50
- * const frozen = deepFreezeState(state);
51
- * // frozen.params is now immutable
52
- * // original state is unchanged
53
- */
54
- export function deepFreezeState<T extends State>(state: T): T {
55
- // Early return for null/undefined
56
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
57
- if (!state) {
58
- return state;
59
- }
60
-
61
- // Validate State structure (structural check, allows circular refs)
62
- if (!isStateStructural(state)) {
63
- throw new TypeError(
64
- `[deepFreezeState] Expected valid State object, got: ${typeof state}`,
65
- );
66
- }
67
-
68
- // Create a deep clone to avoid mutating the original
69
- // structuredClone preserves circular references, so we need to track visited objects
70
- const clonedState = structuredClone(state);
71
-
72
- // WeakSet to track visited objects (prevent infinite recursion with circular refs)
73
- const visited = new WeakSet<object>();
74
-
75
- // Recursive freeze function with circular reference protection
76
- function freezeClonedRecursive(obj: unknown): void {
77
- // Skip primitives, null, undefined
78
- // Note: typeof undefined === "undefined" !== "object", so checking undefined is redundant
79
- if (obj === null || typeof obj !== "object") {
80
- return;
81
- }
82
-
83
- // Skip already visited objects (circular reference protection)
84
- if (visited.has(obj)) {
85
- return;
86
- }
87
-
88
- // Mark as visited
89
- visited.add(obj);
90
-
91
- // Freeze the object/array itself
92
- Object.freeze(obj);
93
-
94
- // Iterate without Object.values() allocation
95
- if (Array.isArray(obj)) {
96
- for (const item of obj) {
97
- freezeClonedRecursive(item);
98
- }
99
- } else {
100
- for (const key in obj) {
101
- freezeClonedRecursive((obj as Record<string, unknown>)[key]);
102
- }
103
- }
104
- }
105
-
106
- // Freeze the entire cloned state tree
107
- freezeClonedRecursive(clonedState);
108
-
109
- return clonedState;
110
- }
111
-
112
- /**
113
- * Shallow-freezes a State object in place.
114
- *
115
- * Freezes only the top-level State object (blocks reassignment of `name`,
116
- * `params`, `path`, `transition`, `context`). Nested objects (`params`,
117
- * `transition`, `transition.segments`, `transition.segments.{deactivated,activated}`)
118
- * are expected to be **already frozen at creation time** by their producers:
119
- *
120
- * - `params` frozen in `makeState()` / `navigateToNotFound()`
121
- * - `transition`, `segments`, `deactivated`, `activated` frozen in
122
- * `buildTransitionMeta()` (or inline in `navigateToNotFound()`)
123
- *
124
- * `state.context` is **intentionally not frozen** — plugins write to it via
125
- * `claim.write(state, value)` after state creation.
126
- *
127
- * @internal
128
- */
129
- export function freezeStateInPlace<T extends State>(state: T): T {
130
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- defensive guard against external misuse
131
- if (!state) {
132
- return state;
133
- }
134
-
135
- return Object.freeze(state);
136
- }
137
-
138
- /**
139
- * Merges user limits with defaults.
140
- * Returns frozen object for immutability.
141
- */
142
- export function createLimits(userLimits: Partial<LimitsConfig> = {}): Limits {
143
- return { ...DEFAULT_LIMITS, ...userLimits };
144
- }
145
-
146
- // =============================================================================
147
- // Params Helpers
148
- // =============================================================================
149
-
150
- /**
151
- * Strips `undefined` values from a params object before handoff to the query
152
- * string engine and state storage.
153
- *
154
- * **Why this exists:** `router.navigate(name, { x: undefined })` must not put
155
- * `x` into the resulting URL (publicly documented contract). The underlying
156
- * query engine (`search-params`) already does this, but the contract belongs
157
- * to `@real-router/core` — this function guarantees it at the core boundary
158
- * so that:
159
- * - Plugin interceptors on `forwardState` that inject `undefined` values are
160
- * caught before they reach the engine
161
- * - `state.params` never contains `undefined` values (roundtrip consistent
162
- * with URL)
163
- * - The contract is verifiable at core's own test surface (doesn't depend on
164
- * engine behavior for regression detection)
165
- *
166
- * Single pass. Always returns a fresh object when input is defined
167
- * (reference identity is not preserved — callers must not rely on it).
168
- */
169
- export function normalizeParams(params: Params): Params;
170
-
171
- export function normalizeParams(params: undefined): undefined;
172
-
173
- export function normalizeParams(params: Params | undefined): Params | undefined;
174
-
175
- export function normalizeParams(
176
- params: Params | undefined,
177
- ): Params | undefined {
178
- if (params === undefined) {
179
- return params;
180
- }
181
-
182
- const normalized: Params = {};
183
-
184
- for (const key in params) {
185
- if (!Object.hasOwn(params, key)) {
186
- continue;
187
- }
188
-
189
- const value = params[key];
190
-
191
- if (value !== undefined) {
192
- normalized[key] = value;
193
- }
194
- }
195
-
196
- return normalized;
197
- }
package/src/index.ts DELETED
@@ -1,50 +0,0 @@
1
- // packages/core/src/index.ts
2
-
3
- // Router-dependent types (re-exported from @real-router/types)
4
-
5
- export type {
6
- BuildStateResultWithSegments,
7
- GuardFnFactory,
8
- PluginFactory,
9
- Route,
10
- RouteConfigUpdate,
11
- } from "./types";
12
-
13
- export type { RouterValidator } from "./types/RouterValidator";
14
-
15
- // Router class (replaces Router interface from core-types)
16
- export { Router } from "./Router";
17
-
18
- // Types (re-exported from core-types - no Router dependency)
19
- export type {
20
- Config,
21
- DefaultDependencies,
22
- GuardFn,
23
- Listener,
24
- Navigator,
25
- NavigationOptions,
26
- Options,
27
- Params,
28
- Plugin,
29
- SimpleState,
30
- State,
31
- SubscribeFn,
32
- SubscribeState,
33
- Subscription,
34
- Unsubscribe,
35
- } from "@real-router/types";
36
-
37
- export type { ErrorCodes, Constants } from "./constants";
38
-
39
- export { events, constants, errorCodes, UNKNOWN_ROUTE } from "./constants";
40
-
41
- // RouterError class (migrated from router-error package)
42
- export { RouterError } from "./RouterError";
43
-
44
- export { createRouter } from "./createRouter";
45
-
46
- export { getNavigator } from "./getNavigator";
47
-
48
- export { resolveForwardChain } from "./namespaces/RoutesNamespace/forwardChain";
49
-
50
- export type { RouteTree } from "route-tree";
package/src/internals.ts DELETED
@@ -1,200 +0,0 @@
1
- import type { DependenciesStore } from "./namespaces";
2
- import type { RoutesStore } from "./namespaces/RoutesNamespace";
3
- import type { Router as RouterClass } from "./Router";
4
- import type { EventMethodMap, GuardFnFactory, PluginFactory } from "./types";
5
- import type { RouterValidator } from "./types/RouterValidator";
6
- import type { SerializedRouterState } from "./utils";
7
- import type {
8
- DefaultDependencies,
9
- EventName,
10
- NavigationOptions,
11
- Options,
12
- Params,
13
- Plugin,
14
- Router as RouterInterface,
15
- RouteTreeState,
16
- SimpleState,
17
- State,
18
- Unsubscribe,
19
- } from "@real-router/types";
20
- import type { RouteTree } from "route-tree";
21
-
22
- export interface RouterInternals<
23
- D extends DefaultDependencies = DefaultDependencies,
24
- > {
25
- readonly makeState: <P extends Params = Params>(
26
- name: string,
27
- params?: P,
28
- path?: string,
29
- meta?: Record<string, Record<string, "url" | "query">>,
30
- ) => State<P>;
31
-
32
- readonly forwardState: <P extends Params = Params>(
33
- routeName: string,
34
- routeParams: P,
35
- ) => SimpleState<P>;
36
-
37
- readonly buildStateResolved: (
38
- resolvedName: string,
39
- resolvedParams: Params,
40
- ) => RouteTreeState | undefined;
41
-
42
- readonly matchPath: <P extends Params = Params>(
43
- path: string,
44
- options?: Options,
45
- ) => State<P> | undefined;
46
-
47
- readonly getOptions: () => Options;
48
-
49
- readonly addEventListener: <E extends EventName>(
50
- eventName: E,
51
- cb: Plugin[EventMethodMap[E]],
52
- ) => Unsubscribe;
53
-
54
- readonly buildPath: (route: string, params?: Params) => string;
55
-
56
- readonly emitTransitionError: (error: Error) => void;
57
-
58
- readonly start: (path: string) => Promise<State>;
59
-
60
- /**
61
- * Plugin-only navigation entry point — delegates to
62
- * `NavigationNamespace.navigateToState` (`getPluginApi(router).navigateToState`).
63
- * Hidden from `Router`/`Navigator` to keep the userland surface minimal;
64
- * see `core-types/src/api.ts` for usage docs.
65
- */
66
- readonly navigateToState: (
67
- state: State,
68
- options?: NavigationOptions,
69
- ) => Promise<State>;
70
-
71
- /* eslint-disable @typescript-eslint/no-explicit-any -- heterogeneous map: stores different InterceptorFn<M> types under different keys */
72
- readonly interceptors: Map<
73
- string,
74
- ((next: (...args: any[]) => any, ...args: any[]) => any)[]
75
- >;
76
- /* eslint-enable @typescript-eslint/no-explicit-any */
77
-
78
- readonly setRootPath: (rootPath: string) => void;
79
- readonly getRootPath: () => string;
80
-
81
- readonly getTree: () => RouteTree;
82
-
83
- readonly isDisposed: () => boolean;
84
-
85
- validator: RouterValidator | null;
86
-
87
- // Dependencies (issue #172)
88
- readonly dependenciesGetStore: () => DependenciesStore<D>;
89
-
90
- // Clone support (issue #173)
91
- readonly cloneOptions: () => Options;
92
- readonly cloneDependencies: () => Record<string, unknown>;
93
- readonly getLifecycleFactories: () => [
94
- Record<string, GuardFnFactory<D>>,
95
- Record<string, GuardFnFactory<D>>,
96
- ];
97
- readonly getPluginFactories: () => PluginFactory<D>[];
98
-
99
- // Consolidated route data store (issue #174 Phase 2)
100
- readonly routeGetStore: () => RoutesStore<D>;
101
-
102
- // Cross-namespace state (issue #174)
103
- readonly getStateName: () => string | undefined;
104
- readonly isTransitioning: () => boolean;
105
- readonly clearState: () => void;
106
- readonly setState: (state: State) => void;
107
- readonly routerExtensions: { keys: string[] }[];
108
- readonly contextClaimRecords: Set<string>;
109
-
110
- /**
111
- * One-shot hydration scratchpad populated by `hydrateRouter` immediately
112
- * before delegating to `router.start(parsed.path)` and cleared in the
113
- * matching `finally`. SSR loader plugins read this slot directly via
114
- * `getInternals(router).hydrationState` to short-circuit their own loader
115
- * call when the server-resolved namespace value is already present in the
116
- * parsed state (#596). `null` outside of an active `hydrateRouter`
117
- * invocation.
118
- */
119
- hydrationState: SerializedRouterState | null;
120
- }
121
-
122
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- existential type: stores RouterInternals for all Dependencies types
123
- const internals = new WeakMap<object, RouterInternals<any>>();
124
-
125
- export function getInternals<D extends DefaultDependencies>(
126
- router: RouterInterface<D>,
127
- ): RouterInternals<D> {
128
- const ctx = internals.get(router);
129
-
130
- if (!ctx) {
131
- throw new TypeError(
132
- "[real-router] Invalid router instance — not found in internals registry",
133
- );
134
- }
135
-
136
- return ctx as RouterInternals<D>;
137
- }
138
-
139
- export function registerInternals<D extends DefaultDependencies>(
140
- router: RouterClass<D>,
141
- ctx: RouterInternals<D>,
142
- ): void {
143
- internals.set(router, ctx);
144
- }
145
-
146
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument -- internal chain execution: type safety enforced at public API boundary (PluginApi.addInterceptor) */
147
- function executeInterceptorChain<T>(
148
- interceptors: ((next: (...args: any[]) => any, ...args: any[]) => any)[],
149
- original: (...args: any[]) => T,
150
- args: any[],
151
- ): T {
152
- let chain = original as (...args: any[]) => any;
153
-
154
- for (const interceptor of interceptors) {
155
- const prev = chain;
156
-
157
- chain = (...chainArgs: any[]) => interceptor(prev, ...chainArgs);
158
- }
159
-
160
- return chain(...args) as T;
161
- }
162
-
163
- export function createInterceptable<T extends (...args: any[]) => any>(
164
- name: string,
165
- original: T,
166
- interceptors: Map<
167
- string,
168
- ((next: (...args: any[]) => any, ...args: any[]) => any)[]
169
- >,
170
- ): T {
171
- return ((...args: any[]) => {
172
- const chain = interceptors.get(name);
173
-
174
- if (!chain || chain.length === 0) {
175
- return original(...args);
176
- }
177
-
178
- return executeInterceptorChain(chain, original, args);
179
- }) as T;
180
- }
181
-
182
- export function createInterceptable2<A, B, R>(
183
- name: string,
184
- original: (a: A, b: B) => R,
185
- interceptors: Map<
186
- string,
187
- ((next: (...args: any[]) => any, ...args: any[]) => any)[]
188
- >,
189
- ): (a: A, b: B) => R {
190
- return (arg1: A, arg2: B) => {
191
- const chain = interceptors.get(name);
192
-
193
- if (!chain || chain.length === 0) {
194
- return original(arg1, arg2);
195
- }
196
-
197
- return executeInterceptorChain(chain, original, [arg1, arg2]);
198
- };
199
- }
200
- /* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument */