@real-router/core 0.56.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.
- package/dist/cjs/Router-BSGzVINO.js +6 -0
- package/dist/cjs/Router-BSGzVINO.js.map +1 -0
- package/dist/cjs/api.d.ts +1 -1
- package/dist/cjs/api.js +1 -1
- package/dist/cjs/{cloneRouter-DRieJvam.js → cloneRouter-7z-60z_f.js} +2 -2
- package/dist/cjs/{cloneRouter-DRieJvam.js.map → cloneRouter-7z-60z_f.js.map} +1 -1
- package/dist/cjs/{index-C-i6vx5Y.d.ts → index-BWUmnecT.d.ts} +1 -2
- package/dist/cjs/index-BWUmnecT.d.ts.map +1 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/utils.js +1 -1
- package/dist/cjs/validation.d.ts +1 -1
- package/dist/esm/Router-B7txWo9N.mjs +6 -0
- package/dist/esm/Router-B7txWo9N.mjs.map +1 -0
- package/dist/esm/api.d.mts +1 -1
- package/dist/esm/api.mjs +1 -1
- package/dist/esm/{cloneRouter-DHrH6D_z.mjs → cloneRouter-BNCQ7tIa.mjs} +2 -2
- package/dist/esm/{cloneRouter-DHrH6D_z.mjs.map → cloneRouter-BNCQ7tIa.mjs.map} +1 -1
- package/dist/esm/{index-C-i6vx5Y.d.mts → index-BWUmnecT.d.mts} +1 -2
- package/dist/esm/index-BWUmnecT.d.mts.map +1 -0
- package/dist/esm/index.d.mts +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/utils.mjs +1 -1
- package/dist/esm/validation.d.mts +1 -1
- package/package.json +2 -3
- package/dist/cjs/Router-IEGavTKk.js +0 -6
- package/dist/cjs/Router-IEGavTKk.js.map +0 -1
- package/dist/cjs/index-C-i6vx5Y.d.ts.map +0 -1
- package/dist/esm/Router-B3aeavRb.mjs +0 -6
- package/dist/esm/Router-B3aeavRb.mjs.map +0 -1
- package/dist/esm/index-C-i6vx5Y.d.mts.map +0 -1
- package/src/Router.ts +0 -737
- package/src/RouterError.ts +0 -324
- package/src/api/cloneRouter.ts +0 -159
- package/src/api/getDependenciesApi.ts +0 -160
- package/src/api/getLifecycleApi.ts +0 -65
- package/src/api/getPluginApi.ts +0 -228
- package/src/api/getRoutesApi.ts +0 -831
- package/src/api/helpers.ts +0 -10
- package/src/api/index.ts +0 -16
- package/src/api/types.ts +0 -12
- package/src/constants.ts +0 -101
- package/src/createRouter.ts +0 -32
- package/src/fsm/index.ts +0 -5
- package/src/fsm/routerFSM.ts +0 -130
- package/src/getNavigator.ts +0 -30
- package/src/guards.ts +0 -46
- package/src/helpers.ts +0 -197
- package/src/index.ts +0 -66
- package/src/internals.ts +0 -228
- package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +0 -30
- package/src/namespaces/DependenciesNamespace/index.ts +0 -5
- package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +0 -522
- package/src/namespaces/EventBusNamespace/index.ts +0 -5
- package/src/namespaces/EventBusNamespace/types.ts +0 -11
- package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -552
- package/src/namespaces/NavigationNamespace/constants.ts +0 -55
- package/src/namespaces/NavigationNamespace/index.ts +0 -5
- package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +0 -108
- package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +0 -124
- package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +0 -283
- package/src/namespaces/NavigationNamespace/types.ts +0 -110
- package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +0 -28
- package/src/namespaces/OptionsNamespace/constants.ts +0 -19
- package/src/namespaces/OptionsNamespace/helpers.ts +0 -50
- package/src/namespaces/OptionsNamespace/index.ts +0 -7
- package/src/namespaces/OptionsNamespace/validators.ts +0 -13
- package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +0 -291
- package/src/namespaces/PluginsNamespace/constants.ts +0 -34
- package/src/namespaces/PluginsNamespace/index.ts +0 -7
- package/src/namespaces/PluginsNamespace/types.ts +0 -22
- package/src/namespaces/PluginsNamespace/validators.ts +0 -28
- package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +0 -558
- package/src/namespaces/RouteLifecycleNamespace/index.ts +0 -5
- package/src/namespaces/RouteLifecycleNamespace/types.ts +0 -10
- package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -81
- package/src/namespaces/RouterLifecycleNamespace/constants.ts +0 -25
- package/src/namespaces/RouterLifecycleNamespace/index.ts +0 -5
- package/src/namespaces/RouterLifecycleNamespace/types.ts +0 -30
- package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +0 -582
- package/src/namespaces/RoutesNamespace/constants.ts +0 -6
- package/src/namespaces/RoutesNamespace/forwardChain.ts +0 -34
- package/src/namespaces/RoutesNamespace/helpers.ts +0 -204
- package/src/namespaces/RoutesNamespace/index.ts +0 -11
- package/src/namespaces/RoutesNamespace/routeGuards.ts +0 -62
- package/src/namespaces/RoutesNamespace/routesStore.ts +0 -566
- package/src/namespaces/RoutesNamespace/types.ts +0 -81
- package/src/namespaces/StateNamespace/StateNamespace.ts +0 -224
- package/src/namespaces/StateNamespace/helpers.ts +0 -24
- package/src/namespaces/StateNamespace/index.ts +0 -5
- package/src/namespaces/StateNamespace/types.ts +0 -15
- package/src/namespaces/index.ts +0 -35
- package/src/stateMetaStore.ts +0 -15
- package/src/transitionPath.ts +0 -440
- package/src/typeGuards.ts +0 -59
- package/src/types/RouterValidator.ts +0 -156
- package/src/types.ts +0 -77
- package/src/utils/createRequestScope.ts +0 -174
- package/src/utils/getStaticPaths.ts +0 -50
- package/src/utils/hydrateRouter.ts +0 -89
- package/src/utils/index.ts +0 -27
- package/src/utils/serializeRouterState.ts +0 -120
- package/src/utils/serializeState.ts +0 -63
- package/src/validation.ts +0 -12
- package/src/wiring/RouterWiringBuilder.ts +0 -275
- package/src/wiring/index.ts +0 -7
- package/src/wiring/types.ts +0 -47
- package/src/wiring/wireRouter.ts +0 -26
package/src/api/helpers.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// packages/core/src/api/helpers.ts
|
|
2
|
-
|
|
3
|
-
import { errorCodes } from "../constants";
|
|
4
|
-
import { RouterError } from "../RouterError";
|
|
5
|
-
|
|
6
|
-
export function throwIfDisposed(isDisposed: () => boolean): void {
|
|
7
|
-
if (isDisposed()) {
|
|
8
|
-
throw new RouterError(errorCodes.ROUTER_DISPOSED);
|
|
9
|
-
}
|
|
10
|
-
}
|
package/src/api/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export { getPluginApi } from "./getPluginApi";
|
|
2
|
-
|
|
3
|
-
export { getRoutesApi } from "./getRoutesApi";
|
|
4
|
-
|
|
5
|
-
export { getDependenciesApi } from "./getDependenciesApi";
|
|
6
|
-
|
|
7
|
-
export { getLifecycleApi } from "./getLifecycleApi";
|
|
8
|
-
|
|
9
|
-
export { cloneRouter } from "./cloneRouter";
|
|
10
|
-
|
|
11
|
-
export type {
|
|
12
|
-
PluginApi,
|
|
13
|
-
RoutesApi,
|
|
14
|
-
DependenciesApi,
|
|
15
|
-
LifecycleApi,
|
|
16
|
-
} from "./types";
|
package/src/api/types.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { PluginApi as BasePluginApi } from "@real-router/types";
|
|
2
|
-
import type { RouteTree } from "route-tree";
|
|
3
|
-
|
|
4
|
-
export interface PluginApi extends Omit<BasePluginApi, "getTree"> {
|
|
5
|
-
getTree: () => RouteTree;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
type RoutesApi,
|
|
10
|
-
type LifecycleApi,
|
|
11
|
-
type DependenciesApi,
|
|
12
|
-
} from "@real-router/types";
|
package/src/constants.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// packages/core/src/constants.ts
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
EventToNameMap,
|
|
5
|
-
EventToPluginMap,
|
|
6
|
-
ErrorCodeToValueMap,
|
|
7
|
-
ErrorCodeKeys,
|
|
8
|
-
ErrorCodeValues,
|
|
9
|
-
TransitionMeta,
|
|
10
|
-
} from "@real-router/types";
|
|
11
|
-
|
|
12
|
-
export type ConstantsKeys = "UNKNOWN_ROUTE";
|
|
13
|
-
|
|
14
|
-
export type Constants = Record<ConstantsKeys, string>;
|
|
15
|
-
|
|
16
|
-
// =============================================================================
|
|
17
|
-
// Error Codes (migrated from router-error)
|
|
18
|
-
// =============================================================================
|
|
19
|
-
|
|
20
|
-
export type ErrorCodes = Record<ErrorCodeKeys, ErrorCodeValues>;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Error codes for router operations.
|
|
24
|
-
* Used to identify specific failure scenarios in navigation and lifecycle.
|
|
25
|
-
* Frozen to prevent accidental modifications.
|
|
26
|
-
*/
|
|
27
|
-
export const errorCodes: ErrorCodeToValueMap = Object.freeze({
|
|
28
|
-
ROUTER_NOT_STARTED: "NOT_STARTED", // navigate() called before start()
|
|
29
|
-
NO_START_PATH_OR_STATE: "NO_START_PATH_OR_STATE", // start() without initial route
|
|
30
|
-
ROUTER_ALREADY_STARTED: "ALREADY_STARTED", // start() called twice
|
|
31
|
-
ROUTE_NOT_FOUND: "ROUTE_NOT_FOUND", // Navigation to non-existent route
|
|
32
|
-
SAME_STATES: "SAME_STATES", // Navigate to current route without reload
|
|
33
|
-
CANNOT_DEACTIVATE: "CANNOT_DEACTIVATE", // canDeactivate guard blocked navigation
|
|
34
|
-
CANNOT_ACTIVATE: "CANNOT_ACTIVATE", // canActivate guard blocked navigation
|
|
35
|
-
TRANSITION_ERR: "TRANSITION_ERR", // Generic transition failure
|
|
36
|
-
TRANSITION_CANCELLED: "CANCELLED", // Navigation cancelled by user or new navigation
|
|
37
|
-
ROUTER_DISPOSED: "DISPOSED", // Router has been disposed
|
|
38
|
-
PLUGIN_CONFLICT: "PLUGIN_CONFLICT", // Plugin tried to extend router with already-existing property
|
|
39
|
-
CONTEXT_NAMESPACE_ALREADY_CLAIMED: "CONTEXT_NAMESPACE_ALREADY_CLAIMED", // Plugin tried to claim a context namespace already owned by another plugin
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* General router constants.
|
|
44
|
-
* Special route names and identifiers.
|
|
45
|
-
*/
|
|
46
|
-
export const UNKNOWN_ROUTE = "@@router/UNKNOWN_ROUTE";
|
|
47
|
-
|
|
48
|
-
export const constants: Constants = {
|
|
49
|
-
UNKNOWN_ROUTE,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Plugin method names.
|
|
54
|
-
* Maps to methods that plugins can implement to hook into router lifecycle.
|
|
55
|
-
*/
|
|
56
|
-
export const plugins: EventToPluginMap = {
|
|
57
|
-
ROUTER_START: "onStart", // Plugin method called when router starts
|
|
58
|
-
ROUTER_STOP: "onStop", // Plugin method called when router stops
|
|
59
|
-
TRANSITION_START: "onTransitionStart", // Plugin method called when navigation begins
|
|
60
|
-
TRANSITION_LEAVE_APPROVE: "onTransitionLeaveApprove", // Plugin method called when deactivation guards pass
|
|
61
|
-
TRANSITION_CANCEL: "onTransitionCancel", // Plugin method called when navigation cancelled
|
|
62
|
-
TRANSITION_SUCCESS: "onTransitionSuccess", // Plugin method called when navigation succeeds
|
|
63
|
-
TRANSITION_ERROR: "onTransitionError", // Plugin method called when navigation fails
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Event names for router event system.
|
|
68
|
-
* Used with addEventListener/removeEventListener for reactive subscriptions.
|
|
69
|
-
*/
|
|
70
|
-
export const events: EventToNameMap = {
|
|
71
|
-
ROUTER_START: "$start", // Emitted when router.start() succeeds
|
|
72
|
-
ROUTER_STOP: "$stop", // Emitted when router.stop() is called
|
|
73
|
-
TRANSITION_START: "$$start", // Emitted when navigation begins
|
|
74
|
-
TRANSITION_LEAVE_APPROVE: "$$leaveApprove", // Emitted when deactivation guards pass
|
|
75
|
-
TRANSITION_CANCEL: "$$cancel", // Emitted when navigation is cancelled
|
|
76
|
-
TRANSITION_SUCCESS: "$$success", // Emitted when navigation completes successfully
|
|
77
|
-
TRANSITION_ERROR: "$$error", // Emitted when navigation fails
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export const DEFAULT_LIMITS = {
|
|
81
|
-
maxDependencies: 100,
|
|
82
|
-
maxPlugins: 50,
|
|
83
|
-
maxListeners: 10_000,
|
|
84
|
-
warnListeners: 1000,
|
|
85
|
-
maxEventDepth: 5,
|
|
86
|
-
maxLifecycleHandlers: 200,
|
|
87
|
-
} as const;
|
|
88
|
-
|
|
89
|
-
export const EMPTY_PARAMS: Readonly<Record<string, never>> = Object.freeze({});
|
|
90
|
-
|
|
91
|
-
const FROZEN_EMPTY_SEGMENTS = Object.freeze({
|
|
92
|
-
deactivated: Object.freeze([]) as unknown as string[],
|
|
93
|
-
activated: Object.freeze([]) as unknown as string[],
|
|
94
|
-
intersection: "",
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
export const DEFAULT_TRANSITION = Object.freeze({
|
|
98
|
-
phase: "activating",
|
|
99
|
-
reason: "success",
|
|
100
|
-
segments: FROZEN_EMPTY_SEGMENTS,
|
|
101
|
-
}) as TransitionMeta;
|
package/src/createRouter.ts
DELETED
|
@@ -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
package/src/fsm/routerFSM.ts
DELETED
|
@@ -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
|
-
}
|
package/src/getNavigator.ts
DELETED
|
@@ -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,66 +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
|
-
// Route-tree mutation event payloads (observed via getRoutesApi().subscribeChanges)
|
|
38
|
-
export type {
|
|
39
|
-
TreeChangedEvent,
|
|
40
|
-
TreeChangedAdd,
|
|
41
|
-
TreeChangedRemove,
|
|
42
|
-
TreeChangedUpdate,
|
|
43
|
-
TreeChangedReplace,
|
|
44
|
-
TreeChangedClear,
|
|
45
|
-
TreeStructuralPatch,
|
|
46
|
-
} from "@real-router/types";
|
|
47
|
-
|
|
48
|
-
export type { ErrorCodes, Constants } from "./constants";
|
|
49
|
-
|
|
50
|
-
export { events, constants, errorCodes, UNKNOWN_ROUTE } from "./constants";
|
|
51
|
-
|
|
52
|
-
// RouterError class (migrated from router-error package)
|
|
53
|
-
export { RouterError } from "./RouterError";
|
|
54
|
-
|
|
55
|
-
// Re-exported so end users can `instanceof RecursionDepthError` at CRUD call
|
|
56
|
-
// sites — the only error that escapes a `subscribeChanges` handler (depth-limit
|
|
57
|
-
// overflow propagates, unlike ordinary listener errors which are isolated).
|
|
58
|
-
export { RecursionDepthError } from "event-emitter";
|
|
59
|
-
|
|
60
|
-
export { createRouter } from "./createRouter";
|
|
61
|
-
|
|
62
|
-
export { getNavigator } from "./getNavigator";
|
|
63
|
-
|
|
64
|
-
export { resolveForwardChain } from "./namespaces/RoutesNamespace/forwardChain";
|
|
65
|
-
|
|
66
|
-
export type { RouteTree } from "route-tree";
|