@jayalfredprufrock/mobx-toolbox 0.6.5 → 0.7.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.
package/dist/router.d.mts CHANGED
@@ -1,50 +1,6 @@
1
1
  import React$1 from "react";
2
2
  import { History, Location } from "history";
3
3
 
4
- //#region src/router/outlet.d.ts
5
- interface OutletConfig {
6
- component?: Component | LazyComponent;
7
- loader?: Loader;
8
- }
9
- type RouteSegmentState = "preloading" | "loading" | "error" | "ready";
10
- declare const DefaultOutlet: Component;
11
- declare class Outlet {
12
- readonly config: OutletConfig;
13
- state: RouteSegmentState;
14
- promise: Promise<unknown> | undefined;
15
- data: unknown;
16
- component: Component | undefined;
17
- get Component(): Component | undefined;
18
- constructor(config: OutletConfig);
19
- load(route: Route): Promise<void>;
20
- setData(data: unknown): void;
21
- setState(state: RouteSegmentState): void;
22
- private loadData;
23
- private loadComponent;
24
- }
25
- //#endregion
26
- //#region src/router/route.d.ts
27
- interface RouteConfig$1 {
28
- path: string;
29
- outlets: Outlet[];
30
- guards: Guard[];
31
- context?: Obj;
32
- layout?: Component;
33
- params: Obj;
34
- }
35
- declare class Route {
36
- readonly path: string;
37
- readonly outlets: Outlet[];
38
- readonly guards: Guard[];
39
- readonly context: Obj;
40
- readonly params: Obj;
41
- readonly layout?: Component;
42
- get data(): Obj;
43
- constructor(def: RouteConfig$1);
44
- guard(): Promise<void>;
45
- load(): Promise<void>;
46
- }
47
- //#endregion
48
4
  //#region src/router/symbols.d.ts
49
5
  declare const CONTEXT: unique symbol;
50
6
  declare const LAYOUT: unique symbol;
@@ -52,6 +8,7 @@ declare const WRAPPER: unique symbol;
52
8
  declare const LOAD: unique symbol;
53
9
  declare const GUARD: unique symbol;
54
10
  declare const PAGE: unique symbol;
11
+ declare const ERROR: unique symbol;
55
12
  declare const REDIRECT: unique symbol;
56
13
  //#endregion
57
14
  //#region src/router/types.d.ts
@@ -60,12 +17,29 @@ type LazyComponent = () => Promise<any>;
60
17
  type Obj<T = any> = Record<string, T>;
61
18
  type Loader = (route: Route) => Promise<any>;
62
19
  type Guard = (route: Route) => Promise<void>;
20
+ /** The props every `[ERROR]` component receives. */
21
+ interface ErrorComponentProps {
22
+ route: Route;
23
+ error: RouterError;
24
+ }
25
+ /** @internal a guard together with the route level that declared it */
26
+ interface GuardEntry {
27
+ guard: Guard;
28
+ depth: number;
29
+ }
30
+ /** @internal per-level snapshot used to build synthetic error routes */
31
+ interface MatchLevel {
32
+ wrapper?: Component;
33
+ layout?: Component;
34
+ errorComponent?: Component;
35
+ }
63
36
  interface RouteConfig {
64
37
  [CONTEXT]?: Obj;
65
38
  [LAYOUT]?: Component;
66
39
  [WRAPPER]?: Component;
67
40
  [GUARD]?: Guard;
68
41
  [LOAD]?: Loader;
42
+ [ERROR]?: Component;
69
43
  }
70
44
  /**
71
45
  * A route page definition.
@@ -134,9 +108,155 @@ type DynamicRoutePath = Extract<RoutePath, `${string}:${string}`>;
134
108
  type StaticRoutePath = Exclude<RoutePath, `${string}:${string}`>;
135
109
  /********************************************************************************* */
136
110
  type JoinSegments<S1, S2> = `/${S1 extends string ? S1 : ""}${S2 extends string ? S2 : ""}`;
111
+ type SegmentName<S> = S extends `$${infer Param}` ? `:${Param}` : S;
137
112
  type ExtractParam<P, NextPart> = P extends `:${infer Param}` ? Record<Param, string> & NextPart : NextPart;
138
113
  type ExtractParams<P> = P extends `${infer S1}/${infer Rest}` ? ExtractParam<S1, ExtractParams<Rest>> : ExtractParam<P, {}>;
139
- type ExtractPaths<R> = { [S in keyof R]: S extends string ? S extends "index" ? "/" : R[S] extends Leaf ? `/${S}` : JoinSegments<S, ExtractPaths<R[S]>> : never }[keyof R];
114
+ type ExtractPaths<R> = { [S in keyof R]: S extends string ? S extends "index" ? "/" : R[S] extends Leaf ? `/${SegmentName<S> extends string ? SegmentName<S> : ""}` : JoinSegments<SegmentName<S>, ExtractPaths<R[S]>> : never }[keyof R];
115
+ //#endregion
116
+ //#region src/router/route.d.ts
117
+ interface RouteConfig$1 {
118
+ path: string;
119
+ outlets: Outlet[];
120
+ guards: GuardEntry[];
121
+ levels: MatchLevel[];
122
+ context?: Obj;
123
+ layout?: Component;
124
+ params: Obj;
125
+ error?: RouterError;
126
+ }
127
+ declare class Route {
128
+ readonly path: string;
129
+ readonly outlets: Outlet[];
130
+ readonly guards: Guard[];
131
+ readonly context: Obj;
132
+ readonly params: Obj;
133
+ readonly layout?: Component;
134
+ /** set on synthetic error routes; the error being rendered */
135
+ readonly error?: RouterError;
136
+ /** @internal */
137
+ readonly guardEntries: GuardEntry[];
138
+ /** @internal */
139
+ readonly levels: MatchLevel[];
140
+ get data(): Obj;
141
+ constructor(def: RouteConfig$1);
142
+ guard(): Promise<void>;
143
+ load(): Promise<void>;
144
+ }
145
+ //#endregion
146
+ //#region src/router/outlet.d.ts
147
+ interface OutletConfig {
148
+ component?: Component | LazyComponent;
149
+ loader?: Loader;
150
+ errorComponent?: Component;
151
+ }
152
+ type RouteSegmentState = "preloading" | "loading" | "error" | "ready";
153
+ declare const DefaultOutlet: Component;
154
+ declare class Outlet {
155
+ readonly config: OutletConfig;
156
+ state: RouteSegmentState;
157
+ promise: Promise<unknown> | undefined;
158
+ data: unknown;
159
+ error: RouterError | undefined;
160
+ component: Component | undefined;
161
+ get Component(): Component | undefined;
162
+ constructor(config: OutletConfig);
163
+ load(route: Route): Promise<void>;
164
+ setData(data: unknown): void;
165
+ setError(error: RouterError): void;
166
+ setState(state: RouteSegmentState): void;
167
+ private loadData;
168
+ private loadComponent;
169
+ }
170
+ //#endregion
171
+ //#region src/router/make-routes.d.ts
172
+ interface MatchState {
173
+ segments: string[];
174
+ context: Obj;
175
+ params: Obj;
176
+ outlets: (Outlet | undefined)[];
177
+ guards: GuardEntry[];
178
+ levels: MatchLevel[];
179
+ layout?: Component;
180
+ errorComponent?: Component;
181
+ }
182
+ declare const makeRoute: (matchState: MatchState) => Route;
183
+ /**
184
+ * Builds the synthetic route rendered when navigation fails. Bubbles
185
+ * from the failing level (`error.depth`, defaulting to the deepest
186
+ * matched level) to the nearest `[ERROR]` component, preserving the
187
+ * `[LAYOUT]` and `[WRAPPER]`s accumulated up to that level. Ancestor
188
+ * `[LOAD]` loaders are intentionally not run — error routes never
189
+ * fetch data.
190
+ */
191
+ declare const makeErrorRoute: (error: RouterError, pathname: string, source?: {
192
+ levels: MatchLevel[];
193
+ params: Obj;
194
+ context: Obj;
195
+ }) => Route;
196
+ declare const matchRoute: (path: string, routeDef: Routes, matchState?: MatchState) => Route;
197
+ declare const makeRoutes: () => <R extends Routes>(routes: R) => R;
198
+ //#endregion
199
+ //#region src/router/errors.d.ts
200
+ type RouterErrorType = "NOT_FOUND" | "GUARD" | "LOAD" | "RENDER";
201
+ interface RouterErrorOptions {
202
+ message?: string;
203
+ cause?: unknown;
204
+ path?: string;
205
+ }
206
+ /**
207
+ * The single error type surfaced to `[ERROR]` components. `type`
208
+ * discriminates the failure source; when the router wraps an
209
+ * application-level error (thrown by a guard or loader), the original
210
+ * is preserved on the standard `cause` property.
211
+ *
212
+ * Guards and loaders may also throw `RouterError` directly — e.g.
213
+ * `throw new RouterError("NOT_FOUND")` from a loader when an entity
214
+ * doesn't exist — and it passes through unwrapped.
215
+ */
216
+ declare class RouterError extends Error {
217
+ readonly type: RouterErrorType;
218
+ readonly path?: string;
219
+ /** @internal matched-prefix state captured when the matcher throws NOT_FOUND */
220
+ state?: MatchState;
221
+ /** @internal level index of the failing guard, for depth-aware bubbling */
222
+ depth?: number;
223
+ constructor(type: RouterErrorType, options?: RouterErrorOptions);
224
+ }
225
+ //#endregion
226
+ //#region src/router/components/error.d.ts
227
+ /**
228
+ * Rendered when an error occurs and no `[ERROR]` component is defined
229
+ * on the matched prefix. Deliberately minimal and dependency-free —
230
+ * define a root-level `[ERROR]` to replace it.
231
+ */
232
+ declare const DefaultErrorPage: Component;
233
+ interface RouteErrorBoundaryProps {
234
+ route: Route;
235
+ fallback: Component;
236
+ children?: React$1.ReactNode;
237
+ }
238
+ interface RouteErrorBoundaryState {
239
+ error?: RouterError;
240
+ route?: Route;
241
+ }
242
+ /**
243
+ * Catches render-time crashes in page and `[WRAPPER]` components and
244
+ * renders the nearest `[ERROR]` component with `type: "RENDER"`. Mounted
245
+ * inside the `[LAYOUT]` so the layout survives page crashes; crashes in
246
+ * the layout itself (or in the fallback) propagate out of `<Router>` by
247
+ * design — those are developer bugs that should stay loud.
248
+ *
249
+ * Deliberately NOT keyed by location: the boundary must be transparent
250
+ * to reconciliation (a key would remount the entire subtree and re-fire
251
+ * every effect on each navigation). Instead, a captured error is cleared
252
+ * when a new Route object arrives.
253
+ */
254
+ declare class RouteErrorBoundary extends React$1.Component<RouteErrorBoundaryProps, RouteErrorBoundaryState> {
255
+ state: RouteErrorBoundaryState;
256
+ static getDerivedStateFromError(cause: unknown): RouteErrorBoundaryState;
257
+ static getDerivedStateFromProps(props: RouteErrorBoundaryProps, state: RouteErrorBoundaryState): Partial<RouteErrorBoundaryState> | null;
258
+ render(): React$1.ReactNode;
259
+ }
140
260
  //#endregion
141
261
  //#region src/router/components/link.d.ts
142
262
  type LinkComponentProps<C extends React$1.ElementType> = Omit<React$1.ComponentProps<C>, "ref" | "exact" | "to" | "params" | "onClick" | "asChild">;
@@ -182,6 +302,8 @@ declare class RouterStore {
182
302
  doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean;
183
303
  navigate<P extends RoutePath>(options: NavigateOptions<P>): void;
184
304
  _navigate<P extends RoutePath>(options: NavigateOptions<P>): void;
305
+ private resolveLocation;
306
+ private isCurrentLocation;
185
307
  setQueryParam(param: string, value: string): void;
186
308
  removeQueryParam(param: string): string | undefined;
187
309
  setLocation(location: Location): Promise<void>;
@@ -204,19 +326,6 @@ declare const Router: (({
204
326
  displayName: string;
205
327
  };
206
328
  //#endregion
207
- //#region src/router/make-routes.d.ts
208
- interface MatchState {
209
- segments: string[];
210
- context: Obj;
211
- params: Obj;
212
- outlets: (Outlet | undefined)[];
213
- guards: (Guard | undefined)[];
214
- layout?: Component;
215
- }
216
- declare const makeRoute: (matchState: MatchState) => Route;
217
- declare const matchRoute: (path: string, routeDef: Routes, matchState?: MatchState) => Route;
218
- declare const makeRoutes: () => <R extends Routes>(routes: R) => R;
219
- //#endregion
220
329
  //#region src/router/redirect.d.ts
221
330
  declare class Redirect<P extends RoutePath> {
222
331
  readonly options: NavigateOptions<P>;
@@ -232,5 +341,5 @@ declare const isRedirect: (data: any) => data is Redirector;
232
341
  declare const isLeaf: (data: any) => data is Leaf;
233
342
  declare const isLazyComponent: (data: any) => data is LazyComponent;
234
343
  //#endregion
235
- export { CONTEXT, Component, DefaultOutlet, DynamicRoutePath, ExtractParam, ExtractParams, ExtractPaths, GUARD, Guard, HasParam, JoinSegments, LAYOUT, LOAD, LazyComponent, Leaf, LinkComponent, LinkPropsBase, Loader, MatchState, MobxRenderSegment, MobxRouter, MobxRouterConfig, MobxRouterRoutes, Navigate, NavigateOptions, Obj, Outlet, OutletConfig, PAGE, Page, PassThrough, REDIRECT, Redirect, Redirector, Route, RouteConfig, RoutePath, RouteSegmentState, Router, RouterOutlet, RouterProps, RouterStore, Routes, StaticRoutePath, WRAPPER, WithToAndParams, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
344
+ export { CONTEXT, Component, DefaultErrorPage, DefaultOutlet, DynamicRoutePath, ERROR, ErrorComponentProps, ExtractParam, ExtractParams, ExtractPaths, GUARD, Guard, GuardEntry, HasParam, JoinSegments, LAYOUT, LOAD, LazyComponent, Leaf, LinkComponent, LinkPropsBase, Loader, MatchLevel, MatchState, MobxRenderSegment, MobxRouter, MobxRouterConfig, MobxRouterRoutes, Navigate, NavigateOptions, Obj, Outlet, OutletConfig, PAGE, Page, PassThrough, REDIRECT, Redirect, Redirector, Route, RouteConfig, RouteErrorBoundary, RouteErrorBoundaryProps, RoutePath, RouteSegmentState, Router, RouterError, RouterErrorOptions, RouterErrorType, RouterOutlet, RouterProps, RouterStore, Routes, SegmentName, StaticRoutePath, WRAPPER, WithToAndParams, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeErrorRoute, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
236
345
  //# sourceMappingURL=router.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.mts","names":[],"sources":["../src/router/outlet.tsx","../src/router/route.tsx","../src/router/symbols.ts","../src/router/types.ts","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/router.store.ts","../src/router/components/router.tsx","../src/router/make-routes.tsx","../src/router/redirect.ts","../src/router/util.ts"],"mappings":"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"}
1
+ {"version":3,"file":"router.d.mts","names":[],"sources":["../src/router/symbols.ts","../src/router/types.ts","../src/router/route.tsx","../src/router/outlet.tsx","../src/router/make-routes.tsx","../src/router/errors.ts","../src/router/components/error.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/router.store.ts","../src/router/components/router.tsx","../src/router/redirect.ts","../src/router/util.ts"],"mappings":"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"}
package/dist/router.mjs CHANGED
@@ -1,9 +1,89 @@
1
1
  import { observer } from "mobx-react-lite";
2
2
  import React, { createContext, useCallback, useContext, useLayoutEffect } from "react";
3
3
  import { action, computed, makeAutoObservable, makeObservable, observable, runInAction } from "mobx";
4
- import { jsx } from "react/jsx-runtime";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { createBrowserHistory } from "history";
6
6
 
7
+ //#region src/router/errors.ts
8
+ const defaultMessage = (type, path) => {
9
+ switch (type) {
10
+ case "NOT_FOUND": return path ? `No route matches '${path}'.` : "No matching route.";
11
+ case "GUARD": return "A route guard rejected the navigation.";
12
+ case "LOAD": return "A route loader or lazy component failed.";
13
+ case "RENDER": return "A route component failed to render.";
14
+ }
15
+ };
16
+ /**
17
+ * The single error type surfaced to `[ERROR]` components. `type`
18
+ * discriminates the failure source; when the router wraps an
19
+ * application-level error (thrown by a guard or loader), the original
20
+ * is preserved on the standard `cause` property.
21
+ *
22
+ * Guards and loaders may also throw `RouterError` directly — e.g.
23
+ * `throw new RouterError("NOT_FOUND")` from a loader when an entity
24
+ * doesn't exist — and it passes through unwrapped.
25
+ */
26
+ var RouterError = class extends Error {
27
+ type;
28
+ path;
29
+ /** @internal matched-prefix state captured when the matcher throws NOT_FOUND */
30
+ state;
31
+ /** @internal level index of the failing guard, for depth-aware bubbling */
32
+ depth;
33
+ constructor(type, options) {
34
+ super(options?.message ?? defaultMessage(type, options?.path), { cause: options?.cause });
35
+ this.name = "RouterError";
36
+ this.type = type;
37
+ this.path = options?.path;
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ //#region src/router/components/error.tsx
43
+ /**
44
+ * Rendered when an error occurs and no `[ERROR]` component is defined
45
+ * on the matched prefix. Deliberately minimal and dependency-free —
46
+ * define a root-level `[ERROR]` to replace it.
47
+ */
48
+ const DefaultErrorPage = ({ error }) => /* @__PURE__ */ jsxs("div", {
49
+ role: "alert",
50
+ children: [/* @__PURE__ */ jsx("h1", { children: error.type === "NOT_FOUND" ? "Page Not Found" : "Something Went Wrong" }), /* @__PURE__ */ jsx("p", { children: error.message })]
51
+ });
52
+ /**
53
+ * Catches render-time crashes in page and `[WRAPPER]` components and
54
+ * renders the nearest `[ERROR]` component with `type: "RENDER"`. Mounted
55
+ * inside the `[LAYOUT]` so the layout survives page crashes; crashes in
56
+ * the layout itself (or in the fallback) propagate out of `<Router>` by
57
+ * design — those are developer bugs that should stay loud.
58
+ *
59
+ * Deliberately NOT keyed by location: the boundary must be transparent
60
+ * to reconciliation (a key would remount the entire subtree and re-fire
61
+ * every effect on each navigation). Instead, a captured error is cleared
62
+ * when a new Route object arrives.
63
+ */
64
+ var RouteErrorBoundary = class extends React.Component {
65
+ state = {};
66
+ static getDerivedStateFromError(cause) {
67
+ return { error: cause instanceof RouterError ? cause : new RouterError("RENDER", { cause }) };
68
+ }
69
+ static getDerivedStateFromProps(props, state) {
70
+ if (state.route === props.route) return null;
71
+ return {
72
+ route: props.route,
73
+ error: void 0
74
+ };
75
+ }
76
+ render() {
77
+ if (!this.state.error) return this.props.children;
78
+ const Fallback = this.props.fallback;
79
+ return /* @__PURE__ */ jsx(Fallback, {
80
+ route: this.props.route,
81
+ error: this.state.error
82
+ });
83
+ }
84
+ };
85
+
86
+ //#endregion
7
87
  //#region src/router/symbols.ts
8
88
  const CONTEXT = Symbol.for("MOBX_ROUTER_CONTEXT");
9
89
  const LAYOUT = Symbol.for("MOBX_ROUTER_LAYOUT");
@@ -11,6 +91,7 @@ const WRAPPER = Symbol.for("MOBX_ROUTER_WRAPPER");
11
91
  const LOAD = Symbol.for("MOBX_ROUTER_LOAD");
12
92
  const GUARD = Symbol.for("MOBX_ROUTER_GUARD");
13
93
  const PAGE = Symbol.for("MOBX_ROUTER_PAGE");
94
+ const ERROR = Symbol.for("MOBX_ROUTER_ERROR");
14
95
  const REDIRECT = Symbol.for("MOBX_ROUTER_REDIRECT");
15
96
 
16
97
  //#endregion
@@ -18,7 +99,7 @@ const REDIRECT = Symbol.for("MOBX_ROUTER_REDIRECT");
18
99
  const resolvePath = (to, params) => {
19
100
  return to.replaceAll(/:[^/]*/g, (segment) => {
20
101
  const value = params?.[segment.slice(1)];
21
- if (!value) throw new Error(`Unable to resolve route '${to}. Paramater '${segment}' not specified.`);
102
+ if (!value) throw new Error(`Unable to resolve route '${to}'. Parameter '${segment}' not specified.`);
22
103
  return value;
23
104
  });
24
105
  };
@@ -58,16 +139,22 @@ const RouterOutlet = ({ route, components }) => {
58
139
  const routerContext = createContext(null);
59
140
  const useRouter = () => useContext(routerContext);
60
141
  const Router = observer(({ store }) => {
61
- if (!store.activeRoute) return null;
62
- const Layout = store.activeRoute.layout ?? PassThrough;
63
- const components = store.activeRoute.outlets.map((o) => o.Component);
142
+ const route = store.activeRoute;
143
+ if (!route) return null;
144
+ const Layout = route.layout ?? PassThrough;
145
+ const outlet = /* @__PURE__ */ jsx(RouterOutlet, {
146
+ route,
147
+ components: route.outlets.map((o) => o.Component)
148
+ });
149
+ const fallback = route.levels.at(-1)?.errorComponent ?? DefaultErrorPage;
64
150
  return /* @__PURE__ */ jsx(routerContext.Provider, {
65
151
  value: store,
66
152
  children: /* @__PURE__ */ jsx(Layout, {
67
- route: store.activeRoute,
68
- children: /* @__PURE__ */ jsx(RouterOutlet, {
69
- route: store.activeRoute,
70
- components
153
+ route,
154
+ children: route.error ? outlet : /* @__PURE__ */ jsx(RouteErrorBoundary, {
155
+ route,
156
+ fallback,
157
+ children: outlet
71
158
  })
72
159
  })
73
160
  });
@@ -90,7 +177,7 @@ const makeLinkComponent = (C, baseProps) => {
90
177
  router.navigate({
91
178
  to,
92
179
  preserveSearch,
93
- ...params
180
+ params
94
181
  });
95
182
  }, [
96
183
  router,
@@ -112,6 +199,16 @@ const Navigate = (props) => {
112
199
  return null;
113
200
  };
114
201
 
202
+ //#endregion
203
+ //#region src/router/redirect.ts
204
+ var Redirect = class {
205
+ options;
206
+ constructor(options) {
207
+ this.options = options;
208
+ }
209
+ };
210
+ const redirect = (options) => new Redirect(options);
211
+
115
212
  //#endregion
116
213
  //#region src/router/outlet.tsx
117
214
  const DefaultOutlet = ({ children }) => children;
@@ -121,11 +218,20 @@ var Outlet = class {
121
218
  state = "preloading";
122
219
  promise;
123
220
  data;
221
+ error;
124
222
  component;
125
223
  get Component() {
126
224
  switch (this.state) {
127
225
  case "loading": return LoadingPlaceholder;
128
226
  case "ready": return this.component ?? DefaultOutlet;
227
+ case "error": {
228
+ const ErrorComponent = this.config.errorComponent ?? DefaultErrorPage;
229
+ const error = this.error ?? new RouterError("LOAD");
230
+ return (props) => /* @__PURE__ */ jsx(ErrorComponent, {
231
+ ...props,
232
+ error
233
+ });
234
+ }
129
235
  default: return;
130
236
  }
131
237
  }
@@ -135,6 +241,7 @@ var Outlet = class {
135
241
  makeAutoObservable(this, {
136
242
  promise: observable.ref,
137
243
  data: observable.ref,
244
+ error: observable.ref,
138
245
  component: false,
139
246
  config: false
140
247
  });
@@ -156,15 +263,20 @@ var Outlet = class {
156
263
  this.setState("ready");
157
264
  }, 300);
158
265
  else this.setState("ready");
159
- }).catch(() => {
266
+ }).catch((e) => {
160
267
  clearTimeout(preloadingTimer);
161
268
  this.setState("error");
269
+ if (e instanceof Redirect) throw e;
270
+ this.setError(e instanceof RouterError ? e : new RouterError("LOAD", { cause: e }));
162
271
  });
163
272
  await this.promise;
164
273
  }
165
274
  setData(data) {
166
275
  this.data = data;
167
276
  }
277
+ setError(error) {
278
+ this.error = error;
279
+ }
168
280
  setState(state) {
169
281
  this.state = state;
170
282
  }
@@ -182,16 +294,6 @@ var Outlet = class {
182
294
  }
183
295
  };
184
296
 
185
- //#endregion
186
- //#region src/router/redirect.ts
187
- var Redirect = class {
188
- options;
189
- constructor(options) {
190
- this.options = options;
191
- }
192
- };
193
- const redirect = (options) => new Redirect(options);
194
-
195
297
  //#endregion
196
298
  //#region src/router/route.tsx
197
299
  var Route = class {
@@ -201,20 +303,36 @@ var Route = class {
201
303
  context;
202
304
  params;
203
305
  layout;
306
+ /** set on synthetic error routes; the error being rendered */
307
+ error;
308
+ /** @internal */
309
+ guardEntries;
310
+ /** @internal */
311
+ levels;
204
312
  get data() {
205
313
  return Object.assign({}, ...this.outlets.map((o) => o.data));
206
314
  }
207
315
  constructor(def) {
208
316
  this.path = def.path;
209
- this.guards = def.guards;
317
+ this.guardEntries = def.guards;
318
+ this.guards = def.guards.map((entry) => entry.guard);
319
+ this.levels = def.levels;
210
320
  this.context = def.context ?? {};
211
321
  this.outlets = def.outlets;
212
322
  this.params = def.params;
213
323
  this.layout = def.layout;
324
+ this.error = def.error;
214
325
  makeObservable(this, { data: computed });
215
326
  }
216
327
  async guard() {
217
- for (const guard of this.guards) await guard(this);
328
+ for (const { guard, depth } of this.guardEntries) try {
329
+ await guard(this);
330
+ } catch (e) {
331
+ if (e instanceof Redirect) throw e;
332
+ const error = e instanceof RouterError ? e : new RouterError("GUARD", { cause: e });
333
+ error.depth ??= depth;
334
+ throw error;
335
+ }
218
336
  }
219
337
  async load() {
220
338
  await Promise.all(this.outlets.map((outlet) => outlet.load(this)));
@@ -228,59 +346,126 @@ const pathToSegments = (path) => {
228
346
  };
229
347
  const makeRoute = (matchState) => {
230
348
  const outlets = matchState.outlets.filter((o) => o !== void 0);
231
- const guards = matchState.guards.filter((g) => g !== void 0);
232
349
  return new Route({
233
350
  ...matchState,
234
351
  outlets,
235
- guards,
236
352
  path: matchState.segments.join("/")
237
353
  });
238
354
  };
355
+ /**
356
+ * Builds the synthetic route rendered when navigation fails. Bubbles
357
+ * from the failing level (`error.depth`, defaulting to the deepest
358
+ * matched level) to the nearest `[ERROR]` component, preserving the
359
+ * `[LAYOUT]` and `[WRAPPER]`s accumulated up to that level. Ancestor
360
+ * `[LOAD]` loaders are intentionally not run — error routes never
361
+ * fetch data.
362
+ */
363
+ const makeErrorRoute = (error, pathname, source) => {
364
+ const levels = error.state?.levels ?? source?.levels ?? [];
365
+ const depth = Math.min(error.depth ?? levels.length - 1, levels.length - 1);
366
+ const level = depth >= 0 ? levels[depth] : void 0;
367
+ const ErrorComponent = level?.errorComponent ?? DefaultErrorPage;
368
+ const outlets = levels.slice(0, depth + 1).flatMap((l) => l.wrapper ? [new Outlet({ component: l.wrapper })] : []);
369
+ outlets.push(new Outlet({ component: (props) => /* @__PURE__ */ jsx(ErrorComponent, {
370
+ ...props,
371
+ error
372
+ }) }));
373
+ return new Route({
374
+ path: pathname.replace(/^\/+/, ""),
375
+ outlets,
376
+ guards: [],
377
+ levels: [],
378
+ params: error.state?.params ?? source?.params ?? {},
379
+ context: error.state?.context ?? source?.context ?? {},
380
+ layout: level?.layout,
381
+ error
382
+ });
383
+ };
384
+ const notFound = (state, attemptedSegments) => {
385
+ const error = new RouterError("NOT_FOUND", { path: `/${attemptedSegments.filter((s) => s !== "").join("/")}` });
386
+ error.state = state;
387
+ return error;
388
+ };
239
389
  const matchRoute = (path, routeDef, matchState) => {
390
+ const depth = matchState?.levels.length ?? 0;
391
+ const layout = routeDef[LAYOUT] ?? matchState?.layout;
392
+ const errorComponent = routeDef[ERROR] ?? matchState?.errorComponent;
240
393
  const state = {
241
394
  segments: [],
242
395
  params: {},
243
396
  ...matchState,
244
- layout: routeDef[LAYOUT] ?? matchState?.layout,
397
+ layout,
398
+ errorComponent,
245
399
  context: {
246
400
  ...matchState?.context,
247
401
  ...routeDef[CONTEXT]
248
402
  },
249
- guards: [...matchState?.guards ?? [], routeDef[GUARD]],
403
+ guards: [...matchState?.guards ?? [], ...routeDef[GUARD] ? [{
404
+ guard: routeDef[GUARD],
405
+ depth
406
+ }] : []],
250
407
  outlets: [
251
408
  ...matchState?.outlets ?? [],
252
- routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER] }) : void 0,
253
- routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD] }) : void 0
254
- ]
409
+ routeDef[WRAPPER] ? new Outlet({
410
+ component: routeDef[WRAPPER],
411
+ errorComponent
412
+ }) : void 0,
413
+ routeDef[LOAD] ? new Outlet({
414
+ loader: routeDef[LOAD],
415
+ errorComponent
416
+ }) : void 0
417
+ ],
418
+ levels: [...matchState?.levels ?? [], {
419
+ wrapper: routeDef[WRAPPER],
420
+ layout,
421
+ errorComponent
422
+ }]
255
423
  };
256
424
  const [segment, ...remainingSegments] = pathToSegments(path);
257
425
  const remainingPath = remainingSegments.join("/");
258
426
  let defAtSegment = routeDef[segment || "index"];
259
427
  if (!defAtSegment) {
260
- const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith("$"));
428
+ const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith("$") || segment.startsWith(":"));
261
429
  if (matchedSegment) {
262
430
  defAtSegment = routeDef[matchedSegment];
263
431
  state.params[matchedSegment.slice(1)] = segment;
264
432
  }
265
433
  }
266
- if (!defAtSegment) throw new Error("Not Found.");
434
+ if (!defAtSegment) throw notFound(state, [
435
+ ...state.segments,
436
+ segment ?? "",
437
+ ...remainingSegments
438
+ ]);
267
439
  state.segments.push(segment ?? "index");
268
440
  if (isLeaf(defAtSegment)) {
269
- if (remainingPath) throw new Error("Not Found.");
441
+ if (remainingPath) throw notFound(state, [...state.segments, ...remainingSegments]);
270
442
  if (isRedirect(defAtSegment)) throw new Redirect(typeof defAtSegment[REDIRECT] === "string" ? { to: defAtSegment[REDIRECT] } : defAtSegment[REDIRECT]);
271
443
  if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {
272
- state.outlets.push(new Outlet({ component: defAtSegment }));
444
+ state.outlets.push(new Outlet({
445
+ component: defAtSegment,
446
+ errorComponent
447
+ }));
273
448
  return makeRoute(state);
274
449
  }
275
450
  }
276
451
  if (isPage(defAtSegment)) {
277
452
  state.layout = defAtSegment[LAYOUT] ?? state.layout;
453
+ state.errorComponent = defAtSegment[ERROR] ?? state.errorComponent;
278
454
  Object.assign(state.context, defAtSegment[CONTEXT]);
279
- state.guards.push(defAtSegment[GUARD]);
455
+ if (defAtSegment[GUARD]) state.guards.push({
456
+ guard: defAtSegment[GUARD],
457
+ depth
458
+ });
280
459
  state.outlets.push(new Outlet({
281
460
  component: defAtSegment[PAGE],
282
- loader: defAtSegment[LOAD]
461
+ loader: defAtSegment[LOAD],
462
+ errorComponent: state.errorComponent
283
463
  }));
464
+ state.levels[state.levels.length - 1] = {
465
+ ...state.levels[state.levels.length - 1],
466
+ layout: state.layout,
467
+ errorComponent: state.errorComponent
468
+ };
284
469
  return makeRoute(state);
285
470
  }
286
471
  return matchRoute(remainingPath, defAtSegment, state);
@@ -303,14 +488,7 @@ var RouterStore = class {
303
488
  return Object.fromEntries(this.search);
304
489
  }
305
490
  get pathParams() {
306
- const params = {};
307
- const paramSegments = this.activeSegments.filter((segment) => segment.startsWith("$"));
308
- const pathValues = this.location.pathname.split("/").slice(1);
309
- paramSegments.forEach((segment, index) => {
310
- const value = pathValues[index + 1];
311
- if (value) params[segment] = value;
312
- });
313
- return params;
491
+ return { ...this.activeRoute?.params };
314
492
  }
315
493
  get activeSegments() {
316
494
  return this.activeRoute?.path.split("/") ?? [];
@@ -335,36 +513,45 @@ var RouterStore = class {
335
513
  }
336
514
  doesPathMatch(path, exact) {
337
515
  const segments = path.slice(1).split("/");
338
- return segments.every((segment, i) => segment === this.activeSegments[i] || segment.startsWith("$")) && this.activeSegments.length >= segments.length && (!exact || segments.length === this.activeSegments.length);
516
+ return segments.every((segment, i) => segment === this.activeSegments[i] || segment.startsWith(":")) && this.activeSegments.length >= segments.length && (!exact || segments.length === this.activeSegments.length);
339
517
  }
340
518
  navigate(options) {
519
+ if (!options.state && this.isCurrentLocation(options)) return;
341
520
  if (!document.startViewTransition) this._navigate(options);
342
521
  else document.startViewTransition(() => this._navigate(options)).ready.catch((e) => console.log(e, typeof e));
343
522
  }
344
523
  _navigate(options) {
345
- const { to, replace, state, search = {}, preserveSearch, params } = options;
524
+ const location = this.resolveLocation(options);
525
+ if (options.replace) this.history.replace(location, options.state);
526
+ else this.history.push(location, options.state);
527
+ }
528
+ resolveLocation(options) {
529
+ const { to, search = {}, preserveSearch, params } = options;
346
530
  const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);
347
531
  if (preserveSearch) {
348
532
  for (const [name, value] of this.search) if (!searchParams.has(name)) searchParams.set(name, value);
349
533
  }
350
- const location = {
534
+ return {
351
535
  pathname: resolvePath(to, params),
352
536
  search: searchParams.size ? `?${searchParams.toString()}` : void 0
353
537
  };
354
- if (replace) this.history.replace(location, state);
355
- else this.history.push(location, state);
538
+ }
539
+ isCurrentLocation(options) {
540
+ if (!this.location) return false;
541
+ const target = this.resolveLocation(options);
542
+ return target.pathname === this.location.pathname && (target.search ?? "") === this.location.search;
356
543
  }
357
544
  setQueryParam(param, value) {
358
545
  const params = new URLSearchParams(this.location.search);
359
546
  params.set(param, value);
360
- this.history.replace({ search: params.toString() });
547
+ this.history.replace({ search: `?${params.toString()}` });
361
548
  }
362
549
  removeQueryParam(param) {
363
550
  const params = new URLSearchParams(this.location.search);
364
551
  const value = params.get(param) ?? void 0;
365
552
  if (value !== void 0) {
366
553
  params.delete(param);
367
- this.history.replace({ search: params.toString() });
554
+ this.history.replace({ search: params.size ? `?${params.toString()}` : "" });
368
555
  }
369
556
  return value;
370
557
  }
@@ -377,9 +564,14 @@ var RouterStore = class {
377
564
  });
378
565
  return;
379
566
  }
567
+ if (this.activeRoute && this.location?.pathname === location.pathname) {
568
+ this.location = location;
569
+ return;
570
+ }
380
571
  this.location = location;
572
+ let matchedRoute;
381
573
  try {
382
- const matchedRoute = matchRoute(location.pathname, this.routesDef);
574
+ matchedRoute = matchRoute(location.pathname, this.routesDef);
383
575
  await matchedRoute.guard();
384
576
  if (this.location !== location) return;
385
577
  runInAction(() => {
@@ -391,11 +583,21 @@ var RouterStore = class {
391
583
  this.navigate(e.options);
392
584
  return;
393
585
  }
394
- throw e;
586
+ if (this.location !== location) return;
587
+ const error = e instanceof RouterError ? e : new RouterError("RENDER", {
588
+ cause: e,
589
+ path: location.pathname
590
+ });
591
+ console.error(error);
592
+ const errorRoute = makeErrorRoute(error, location.pathname, matchedRoute);
593
+ runInAction(() => {
594
+ this.activeRoute = errorRoute;
595
+ });
596
+ await errorRoute.load();
395
597
  }
396
598
  }
397
599
  };
398
600
 
399
601
  //#endregion
400
- export { CONTEXT, DefaultOutlet, GUARD, LAYOUT, LOAD, Navigate, Outlet, PAGE, PassThrough, REDIRECT, Redirect, Route, Router, RouterOutlet, RouterStore, WRAPPER, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
602
+ export { CONTEXT, DefaultErrorPage, DefaultOutlet, ERROR, GUARD, LAYOUT, LOAD, Navigate, Outlet, PAGE, PassThrough, REDIRECT, Redirect, Route, RouteErrorBoundary, Router, RouterError, RouterOutlet, RouterStore, WRAPPER, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeErrorRoute, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
401
603
  //# sourceMappingURL=router.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.mjs","names":[],"sources":["../src/router/symbols.ts","../src/router/util.ts","../src/router/components/router.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/outlet.tsx","../src/router/redirect.ts","../src/router/route.tsx","../src/router/make-routes.tsx","../src/router/router.store.ts"],"sourcesContent":["export const CONTEXT: unique symbol = Symbol.for(\"MOBX_ROUTER_CONTEXT\");\nexport const LAYOUT: unique symbol = Symbol.for(\"MOBX_ROUTER_LAYOUT\");\nexport const WRAPPER: unique symbol = Symbol.for(\"MOBX_ROUTER_WRAPPER\");\nexport const LOAD: unique symbol = Symbol.for(\"MOBX_ROUTER_LOAD\");\nexport const GUARD: unique symbol = Symbol.for(\"MOBX_ROUTER_GUARD\");\nexport const PAGE: unique symbol = Symbol.for(\"MOBX_ROUTER_PAGE\");\nexport const REDIRECT: unique symbol = Symbol.for(\"MOBX_ROUTER_REDIRECT\");\n","import { PAGE, REDIRECT } from \"./symbols\";\nimport type { Component, LazyComponent, Leaf, Obj, Page, Redirector } from \"./types\";\n\nexport const resolvePath = (to: string, params?: Obj): string => {\n return to.replaceAll(/:[^/]*/g, (segment) => {\n const value = params?.[segment.slice(1)];\n if (!value)\n throw new Error(`Unable to resolve route '${to}. Paramater '${segment}' not specified.`);\n return value;\n });\n};\n\nexport const isComponent = (data: any): data is Component => {\n if (!data) return false;\n return (\n typeof data === \"function\" ||\n (typeof data === \"object\" && data[\"$$typeof\"] === Symbol.for(\"react.memo\"))\n );\n};\n\nexport const isPage = (data: any): data is Page => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(PAGE);\n};\n\nexport const isRedirect = (data: any): data is Redirector => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(REDIRECT);\n};\n\nexport const isLeaf = (data: any): data is Leaf => {\n return isComponent(data) || isPage(data) || isRedirect(data);\n};\n\nexport const isLazyComponent = (data: any): data is LazyComponent => {\n return typeof data === \"function\" && data.toString().startsWith(\"() => import(\");\n};\n","import { observer } from \"mobx-react-lite\";\nimport { createContext, useContext } from \"react\";\nimport type { Route } from \"../route\";\nimport type { RouterStore } from \"../router.store\";\nimport type { Component } from \"../types\";\n\nexport const PassThrough: Component = ({ children }) => children;\n\n// Plain (non-observer) renderer. State observation lives one level up\n// in `Router`, so the page component renders as a child of a plain\n// FunctionComponent — no memo wrapper in the parent chain to interact\n// with React Refresh's family-update propagation.\nexport const RouterOutlet: React.FC<{ route: Route; components: (Component | undefined)[] }> = ({\n route,\n components,\n}) => {\n const [C, ...remaining] = components;\n\n if (!C) return null;\n\n return (\n <C route={route}>\n {remaining.length > 0 && <RouterOutlet route={route} components={remaining} />}\n </C>\n );\n};\n\nexport const routerContext = createContext<RouterStore>(null as any);\nexport const useRouter = () => useContext(routerContext);\n\nexport interface RouterProps {\n store: RouterStore;\n}\n\nexport const Router = observer(({ store }: RouterProps) => {\n if (!store.activeRoute) {\n return null;\n }\n\n const Layout = store.activeRoute.layout ?? PassThrough;\n const components = store.activeRoute.outlets.map((o) => o.Component);\n\n return (\n <routerContext.Provider value={store}>\n <Layout route={store.activeRoute}>\n <RouterOutlet route={store.activeRoute} components={components} />\n </Layout>\n </routerContext.Provider>\n );\n});\n","import { observer } from \"mobx-react-lite\";\nimport React, { useCallback } from \"react\";\nimport type {\n DynamicRoutePath,\n ExtractParams,\n NavigateOptions,\n RoutePath,\n StaticRoutePath,\n} from \"../types\";\nimport { resolvePath } from \"../util\";\nimport { useRouter } from \"./router\";\n\ntype LinkComponentProps<C extends React.ElementType> = Omit<\n React.ComponentProps<C>,\n \"ref\" | \"exact\" | \"to\" | \"params\" | \"onClick\" | \"asChild\"\n>;\n\nexport type LinkPropsBase<\n C extends React.ElementType,\n I extends React.ElementType = C,\n> = LinkComponentProps<C> & {\n exact?: boolean;\n preserveSearch?: boolean;\n ref?: React.Ref<React.ComponentRef<I>>;\n};\n\n// function overloading is much faster than leveraging conditional types\n// but once the typescript go compiler is released and performance is no\n// longer an issue, it might make sense to simplify this a bit so it can\n// be more easily consumed by users\nexport interface LinkComponent<C extends React.ElementType, I extends React.ElementType = C> {\n <P extends StaticRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params?: undefined },\n ): React.ReactNode;\n <P extends DynamicRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params: ExtractParams<P> },\n ): React.ReactNode;\n}\n\n// final thing to do is make sure refs still work in React 19\n\n// this smooths over some of the awkwardness when extending this component\nexport const makeLinkComponent = <C extends React.ElementType, I extends React.ElementType = C>(\n C: C,\n baseProps?: Partial<LinkComponentProps<C>> & { as?: I },\n) => {\n return observer(({ to, params, exact, preserveSearch, children, ...props }: any) => {\n const router = useRouter();\n const mergedProps = { ...baseProps, ...props };\n\n if (props.role !== \"link\") {\n mergedProps.href = resolvePath(to, params);\n }\n\n if (router.doesPathMatch(to, exact)) {\n mergedProps[\"aria-current\"] = \"page\";\n }\n\n mergedProps.onClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.preventDefault();\n if (props.disabled) return;\n router.navigate({ to, preserveSearch, ...(params as any) } as NavigateOptions<RoutePath>);\n },\n [router, params, to, props.disabled],\n );\n\n return React.createElement(C, mergedProps, children);\n }) as LinkComponent<C, I>;\n};\n\n//export const Link = makeLinkComponent('a');\n","import { useLayoutEffect } from \"react\";\nimport type { NavigateOptions, RoutePath } from \"../types\";\nimport { useRouter } from \"./router\";\n\nexport const Navigate = <P extends RoutePath>(props: NavigateOptions<P>) => {\n const router = useRouter();\n\n useLayoutEffect(() => {\n router.navigate(props);\n }, [router, props]);\n\n return null;\n};\n","import { makeAutoObservable, observable } from \"mobx\";\nimport type { Route } from \"./route\";\nimport type { Component, LazyComponent, Loader } from \"./types\";\nimport { isLazyComponent } from \"./util\";\n\nexport interface OutletConfig {\n component?: Component | LazyComponent;\n loader?: Loader;\n}\n\nexport type RouteSegmentState = \"preloading\" | \"loading\" | \"error\" | \"ready\";\n\nexport const DefaultOutlet: Component = ({ children }) => children;\n\nconst LoadingPlaceholder: Component = () => <p>Loading...</p>;\n\nexport class Outlet {\n state: RouteSegmentState = \"preloading\";\n promise: Promise<unknown> | undefined;\n data: unknown;\n\n // Plain (non-observable) reference. The page component must reach\n // React unmediated by MobX — once MobX deep-observes the holder,\n // React Refresh can no longer swap the page identity via family\n // lookup on the original function. This mirrors how Route holds\n // `layout` as a plain field under makeObservable.\n component: Component | undefined;\n\n get Component(): Component | undefined {\n switch (this.state) {\n case \"loading\":\n return LoadingPlaceholder;\n case \"ready\":\n return this.component ?? DefaultOutlet;\n default:\n return undefined;\n }\n }\n\n constructor(readonly config: OutletConfig) {\n if (!isLazyComponent(config.component)) {\n this.component = config.component;\n }\n\n makeAutoObservable<Outlet, \"component\" | \"config\">(this, {\n promise: observable.ref,\n data: observable.ref,\n component: false,\n config: false,\n });\n }\n\n async load(route: Route): Promise<void> {\n const promises: Promise<void>[] = [];\n\n if (isLazyComponent(this.config.component) && !this.component) {\n promises.push(this.loadComponent());\n }\n\n if (this.config.loader) {\n promises.push(this.loadData(route));\n }\n\n if (!promises.length) {\n this.setState(\"ready\");\n return;\n }\n\n // wait to transition to loading to avoid\n // screen flashes when the loader function\n // executes quickly\n const preloadingTimer = setTimeout(() => {\n if (this.state === \"preloading\") {\n this.setState(\"loading\");\n }\n }, 300);\n\n this.promise = Promise.all(promises)\n .then(() => {\n clearTimeout(preloadingTimer);\n if (this.state === \"loading\") {\n // if we had to transition to regular loading because\n // the loader was taking too long, force an additional\n // timeout to prevent a loading flash\n setTimeout(() => {\n this.setState(\"ready\");\n }, 300);\n } else {\n this.setState(\"ready\");\n }\n })\n .catch(() => {\n clearTimeout(preloadingTimer);\n // TODO: check for type of error\n // handle access denied and redirects\n this.setState(\"error\");\n });\n\n await this.promise;\n }\n\n setData(data: unknown) {\n this.data = data;\n }\n\n setState(state: RouteSegmentState) {\n this.state = state;\n }\n\n private async loadData(route: Route): Promise<void> {\n await this.config.loader?.(route).then((data) => this.setData(data));\n }\n\n private async loadComponent(): Promise<void> {\n if (!isLazyComponent(this.config.component)) return;\n const module = await this.config.component();\n for (const exportName in module) {\n if (exportName === \"default\" || exportName.endsWith(\"Page\")) {\n this.component = module[exportName];\n return;\n }\n }\n throw new Error(\n \"Lazy route component module did not export `default` or a `*Page` named export\",\n );\n }\n}\n","import type { NavigateOptions, RoutePath } from \"./types\";\n\nexport class Redirect<P extends RoutePath> {\n constructor(readonly options: NavigateOptions<P>) {}\n}\n\nexport const redirect = <P extends RoutePath>(options: NavigateOptions<P>): Redirect<P> =>\n new Redirect(options);\n","import { computed, makeObservable } from \"mobx\";\nimport type { Outlet } from \"./outlet\";\nimport type { Component, Guard, Obj } from \"./types\";\n\nexport interface RouteConfig {\n path: string;\n outlets: Outlet[];\n guards: Guard[];\n context?: Obj;\n layout?: Component;\n params: Obj;\n}\n\nexport class Route {\n readonly path: string;\n readonly outlets: Outlet[];\n readonly guards: Guard[];\n readonly context: Obj;\n readonly params: Obj;\n readonly layout?: Component;\n\n get data(): Obj {\n return Object.assign({}, ...this.outlets.map((o) => o.data));\n }\n\n constructor(def: RouteConfig) {\n this.path = def.path;\n this.guards = def.guards;\n this.context = def.context ?? {};\n this.outlets = def.outlets;\n this.params = def.params;\n this.layout = def.layout;\n\n makeObservable(this, {\n data: computed,\n });\n }\n\n async guard(): Promise<void> {\n for (const guard of this.guards) {\n await guard(this);\n }\n }\n\n async load(): Promise<void> {\n await Promise.all(this.outlets.map((outlet) => outlet.load(this)));\n }\n}\n","import { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport { Route } from \"./route\";\nimport { CONTEXT, GUARD, LAYOUT, LOAD, PAGE, REDIRECT, WRAPPER } from \"./symbols\";\nimport type { Component, Guard, Obj, Routes } from \"./types\";\nimport { isComponent, isLazyComponent, isLeaf, isPage, isRedirect } from \"./util\";\n\nconst pathToSegments = (path: string): string[] => {\n return path.replace(/^\\/+|\\/+$/g, \"\").split(\"/\");\n};\n\nexport interface MatchState {\n segments: string[];\n context: Obj;\n params: Obj;\n outlets: (Outlet | undefined)[];\n guards: (Guard | undefined)[];\n layout?: Component;\n}\n\nexport const makeRoute = (matchState: MatchState): Route => {\n const outlets = matchState.outlets.filter((o) => o !== undefined);\n const guards = matchState.guards.filter((g) => g !== undefined);\n\n return new Route({ ...matchState, outlets, guards, path: matchState.segments.join(\"/\") });\n};\n\nexport const matchRoute = (path: string, routeDef: Routes, matchState?: MatchState): Route => {\n const state: MatchState = {\n segments: [],\n params: {},\n ...matchState,\n layout: routeDef[LAYOUT] ?? matchState?.layout,\n context: { ...matchState?.context, ...routeDef[CONTEXT] },\n guards: [...(matchState?.guards ?? []), routeDef[GUARD]],\n outlets: [\n ...(matchState?.outlets ?? []),\n routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER] }) : undefined,\n routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD] }) : undefined,\n ],\n };\n\n const [segment, ...remainingSegments] = pathToSegments(path);\n const remainingPath = remainingSegments.join(\"/\");\n\n let defAtSegment = routeDef[segment || \"index\"];\n\n if (!defAtSegment) {\n const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith(\"$\"));\n if (matchedSegment) {\n defAtSegment = routeDef[matchedSegment];\n state.params[matchedSegment.slice(1)] = segment;\n }\n }\n\n if (!defAtSegment) {\n throw new Error(\"Not Found.\");\n }\n\n state.segments.push(segment ?? \"index\");\n\n if (isLeaf(defAtSegment)) {\n if (remainingPath) {\n throw new Error(\"Not Found.\");\n }\n\n if (isRedirect(defAtSegment)) {\n const redirect =\n typeof defAtSegment[REDIRECT] === \"string\"\n ? { to: defAtSegment[REDIRECT] }\n : defAtSegment[REDIRECT];\n throw new Redirect(redirect as any);\n }\n\n if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {\n state.outlets.push(new Outlet({ component: defAtSegment }));\n return makeRoute(state);\n }\n }\n\n // at this point we have a nested route or a [Page] definition\n\n if (isPage(defAtSegment)) {\n state.layout = defAtSegment[LAYOUT] ?? state.layout;\n Object.assign(state.context, defAtSegment[CONTEXT]);\n state.guards.push(defAtSegment[GUARD]);\n state.outlets.push(\n new Outlet({\n component: defAtSegment[PAGE],\n loader: defAtSegment[LOAD],\n }),\n );\n\n return makeRoute(state);\n }\n\n // now we know we have a nested route\n return matchRoute(remainingPath, defAtSegment, state);\n};\n\n// TODO: ideally this could resolve to something less than R,\n// but specific enough to infer all paths as a literal union.\n// As it stands, there are certain things we can't access reliably\n// without the compiler complaining about circular references\n// try \"as const satisfies\" approach which would allow us to\n// exchange a less specific version of MobxRoutesRoot for this\nexport const makeRoutes =\n () =>\n <R extends Routes>(routes: R): R => {\n // todo: perform some validation here\n // - no forward slashes in keys\n // - at most one variable segment per level\n // - only lowercase letters (except variables)\n // - paths/variables cannot contain $ that aren't at the beginning\n // - path variables must be unique across a path\n\n return routes;\n };\n","import { createBrowserHistory, type History, type Location } from \"history\";\nimport { action, computed, makeObservable, observable, runInAction } from \"mobx\";\nimport { matchRoute } from \"./make-routes\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, MobxRouterConfig, NavigateOptions, Obj, RoutePath, Routes } from \"./types\";\nimport { resolvePath } from \"./util\";\n\nexport interface MobxRenderSegment {\n segment: string;\n component: Component;\n props?: Obj;\n}\n\nexport class RouterStore {\n readonly history: History;\n\n routesDef?: Routes;\n\n location!: Location;\n activeRoute: Route | undefined;\n\n get search(): URLSearchParams {\n return new URLSearchParams(this.location?.search);\n }\n\n get query(): Record<string, string> {\n return Object.fromEntries(this.search);\n }\n\n get pathParams(): Record<string, string> {\n const params = {} as Record<string, string>;\n\n const paramSegments = this.activeSegments.filter((segment) => segment.startsWith(\"$\"));\n const pathValues = this.location.pathname.split(\"/\").slice(1);\n\n paramSegments.forEach((segment, index) => {\n const value = pathValues[index + 1];\n if (value) {\n params[segment] = value;\n }\n });\n\n return params as Record<string, string>;\n }\n\n get activeSegments(): string[] {\n return this.activeRoute?.path.split(\"/\") ?? [];\n }\n\n constructor(config?: MobxRouterConfig) {\n makeObservable(this, {\n location: observable.ref,\n activeRoute: observable.ref,\n\n search: computed,\n pathParams: computed,\n activeSegments: computed,\n\n setLocation: action,\n });\n\n this.history = config?.history ?? createBrowserHistory();\n }\n\n initialize(routesDef: Routes): void {\n this.routesDef = routesDef;\n this.history.listen((data) => {\n void this.setLocation(data.location);\n });\n\n void this.setLocation(this.history.location);\n }\n\n doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean {\n const segments = path.slice(1).split(\"/\");\n const segmentsMatch = segments.every(\n (segment, i) => segment === this.activeSegments[i] || segment.startsWith(\"$\"),\n );\n\n return (\n segmentsMatch &&\n this.activeSegments.length >= segments.length &&\n (!exact || segments.length === this.activeSegments.length)\n );\n }\n\n navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n if (!document.startViewTransition) {\n this._navigate(options);\n } else {\n const transition = document.startViewTransition(() => this._navigate(options));\n transition.ready.catch((e) => console.log(e, typeof e));\n }\n }\n\n _navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n const { to, replace, state, search = {}, preserveSearch, params } = options;\n\n const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);\n\n if (preserveSearch) {\n for (const [name, value] of this.search) {\n if (!searchParams.has(name)) {\n searchParams.set(name, value);\n }\n }\n }\n\n const location = {\n pathname: resolvePath(to, params),\n search: searchParams.size ? `?${searchParams.toString()}` : undefined,\n };\n\n if (replace) {\n this.history.replace(location, state);\n } else {\n this.history.push(location, state);\n }\n }\n\n setQueryParam(param: string, value: string): void {\n const params = new URLSearchParams(this.location.search);\n params.set(param, value);\n this.history.replace({ search: params.toString() });\n }\n\n removeQueryParam(param: string): string | undefined {\n const params = new URLSearchParams(this.location.search);\n const value = params.get(param) ?? undefined;\n if (value !== undefined) {\n params.delete(param);\n this.history.replace({ search: params.toString() });\n }\n return value;\n }\n\n async setLocation(location: Location): Promise<void> {\n if (!this.routesDef) return;\n\n // TODO: this should not be the responsibility of mobx-router\n // and should really be handled server-side\n if (location.pathname !== \"/\" && location.pathname.endsWith(\"/\")) {\n this.history.replace({ ...location, pathname: location.pathname.slice(0, -1) });\n return;\n }\n\n this.location = location;\n\n try {\n const matchedRoute = matchRoute(location.pathname, this.routesDef);\n\n await matchedRoute.guard();\n\n // navigating within a guard function\n // is essentially a redirect\n if (this.location !== location) {\n return;\n }\n\n runInAction(() => {\n this.activeRoute = matchedRoute;\n });\n\n await this.activeRoute?.load();\n } catch (e) {\n if (e instanceof Redirect) {\n this.navigate(e.options);\n return;\n }\n throw e;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"router.mjs","names":[],"sources":["../src/router/errors.ts","../src/router/components/error.tsx","../src/router/symbols.ts","../src/router/util.ts","../src/router/components/router.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/redirect.ts","../src/router/outlet.tsx","../src/router/route.tsx","../src/router/make-routes.tsx","../src/router/router.store.ts"],"sourcesContent":["import type { MatchState } from \"./make-routes\";\n\nexport type RouterErrorType = \"NOT_FOUND\" | \"GUARD\" | \"LOAD\" | \"RENDER\";\n\nexport interface RouterErrorOptions {\n message?: string;\n cause?: unknown;\n path?: string;\n}\n\nconst defaultMessage = (type: RouterErrorType, path?: string): string => {\n switch (type) {\n case \"NOT_FOUND\":\n return path ? `No route matches '${path}'.` : \"No matching route.\";\n case \"GUARD\":\n return \"A route guard rejected the navigation.\";\n case \"LOAD\":\n return \"A route loader or lazy component failed.\";\n case \"RENDER\":\n return \"A route component failed to render.\";\n }\n};\n\n/**\n * The single error type surfaced to `[ERROR]` components. `type`\n * discriminates the failure source; when the router wraps an\n * application-level error (thrown by a guard or loader), the original\n * is preserved on the standard `cause` property.\n *\n * Guards and loaders may also throw `RouterError` directly — e.g.\n * `throw new RouterError(\"NOT_FOUND\")` from a loader when an entity\n * doesn't exist — and it passes through unwrapped.\n */\nexport class RouterError extends Error {\n readonly type: RouterErrorType;\n readonly path?: string;\n\n /** @internal matched-prefix state captured when the matcher throws NOT_FOUND */\n state?: MatchState;\n /** @internal level index of the failing guard, for depth-aware bubbling */\n depth?: number;\n\n constructor(type: RouterErrorType, options?: RouterErrorOptions) {\n super(options?.message ?? defaultMessage(type, options?.path), { cause: options?.cause });\n this.name = \"RouterError\";\n this.type = type;\n this.path = options?.path;\n }\n}\n","import React from \"react\";\nimport { RouterError } from \"../errors\";\nimport type { Route } from \"../route\";\nimport type { Component, ErrorComponentProps } from \"../types\";\n\n/**\n * Rendered when an error occurs and no `[ERROR]` component is defined\n * on the matched prefix. Deliberately minimal and dependency-free —\n * define a root-level `[ERROR]` to replace it.\n */\nexport const DefaultErrorPage: Component = ({ error }: ErrorComponentProps) => (\n <div role=\"alert\">\n <h1>{error.type === \"NOT_FOUND\" ? \"Page Not Found\" : \"Something Went Wrong\"}</h1>\n <p>{error.message}</p>\n </div>\n);\n\nexport interface RouteErrorBoundaryProps {\n route: Route;\n fallback: Component;\n children?: React.ReactNode;\n}\n\ninterface RouteErrorBoundaryState {\n error?: RouterError;\n route?: Route;\n}\n\n/**\n * Catches render-time crashes in page and `[WRAPPER]` components and\n * renders the nearest `[ERROR]` component with `type: \"RENDER\"`. Mounted\n * inside the `[LAYOUT]` so the layout survives page crashes; crashes in\n * the layout itself (or in the fallback) propagate out of `<Router>` by\n * design — those are developer bugs that should stay loud.\n *\n * Deliberately NOT keyed by location: the boundary must be transparent\n * to reconciliation (a key would remount the entire subtree and re-fire\n * every effect on each navigation). Instead, a captured error is cleared\n * when a new Route object arrives.\n */\nexport class RouteErrorBoundary extends React.Component<\n RouteErrorBoundaryProps,\n RouteErrorBoundaryState\n> {\n override state: RouteErrorBoundaryState = {};\n\n static getDerivedStateFromError(cause: unknown): RouteErrorBoundaryState {\n return { error: cause instanceof RouterError ? cause : new RouterError(\"RENDER\", { cause }) };\n }\n\n static getDerivedStateFromProps(\n props: RouteErrorBoundaryProps,\n state: RouteErrorBoundaryState,\n ): Partial<RouteErrorBoundaryState> | null {\n if (state.route === props.route) return null;\n // a new Route object means a navigation occurred — clear any\n // captured error so the boundary doesn't keep a stale fallback\n return { route: props.route, error: undefined };\n }\n\n override render(): React.ReactNode {\n if (!this.state.error) return this.props.children;\n\n const Fallback = this.props.fallback;\n return <Fallback route={this.props.route} error={this.state.error} />;\n }\n}\n","export const CONTEXT: unique symbol = Symbol.for(\"MOBX_ROUTER_CONTEXT\");\nexport const LAYOUT: unique symbol = Symbol.for(\"MOBX_ROUTER_LAYOUT\");\nexport const WRAPPER: unique symbol = Symbol.for(\"MOBX_ROUTER_WRAPPER\");\nexport const LOAD: unique symbol = Symbol.for(\"MOBX_ROUTER_LOAD\");\nexport const GUARD: unique symbol = Symbol.for(\"MOBX_ROUTER_GUARD\");\nexport const PAGE: unique symbol = Symbol.for(\"MOBX_ROUTER_PAGE\");\nexport const ERROR: unique symbol = Symbol.for(\"MOBX_ROUTER_ERROR\");\nexport const REDIRECT: unique symbol = Symbol.for(\"MOBX_ROUTER_REDIRECT\");\n","import { PAGE, REDIRECT } from \"./symbols\";\nimport type { Component, LazyComponent, Leaf, Obj, Page, Redirector } from \"./types\";\n\nexport const resolvePath = (to: string, params?: Obj): string => {\n return to.replaceAll(/:[^/]*/g, (segment) => {\n const value = params?.[segment.slice(1)];\n if (!value)\n throw new Error(`Unable to resolve route '${to}'. Parameter '${segment}' not specified.`);\n return value;\n });\n};\n\nexport const isComponent = (data: any): data is Component => {\n if (!data) return false;\n return (\n typeof data === \"function\" ||\n (typeof data === \"object\" && data[\"$$typeof\"] === Symbol.for(\"react.memo\"))\n );\n};\n\nexport const isPage = (data: any): data is Page => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(PAGE);\n};\n\nexport const isRedirect = (data: any): data is Redirector => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(REDIRECT);\n};\n\nexport const isLeaf = (data: any): data is Leaf => {\n return isComponent(data) || isPage(data) || isRedirect(data);\n};\n\nexport const isLazyComponent = (data: any): data is LazyComponent => {\n return typeof data === \"function\" && data.toString().startsWith(\"() => import(\");\n};\n","import { observer } from \"mobx-react-lite\";\nimport { createContext, useContext } from \"react\";\nimport type { Route } from \"../route\";\nimport type { RouterStore } from \"../router.store\";\nimport type { Component } from \"../types\";\nimport { DefaultErrorPage, RouteErrorBoundary } from \"./error\";\n\nexport const PassThrough: Component = ({ children }) => children;\n\n// Plain (non-observer) renderer. State observation lives one level up\n// in `Router`, so the page component renders as a child of a plain\n// FunctionComponent — no memo wrapper in the parent chain to interact\n// with React Refresh's family-update propagation.\nexport const RouterOutlet: React.FC<{ route: Route; components: (Component | undefined)[] }> = ({\n route,\n components,\n}) => {\n const [C, ...remaining] = components;\n\n if (!C) return null;\n\n return (\n <C route={route}>\n {remaining.length > 0 && <RouterOutlet route={route} components={remaining} />}\n </C>\n );\n};\n\nexport const routerContext = createContext<RouterStore>(null as any);\nexport const useRouter = () => useContext(routerContext);\n\nexport interface RouterProps {\n store: RouterStore;\n}\n\nexport const Router = observer(({ store }: RouterProps) => {\n const route = store.activeRoute;\n if (!route) {\n return null;\n }\n\n const Layout = route.layout ?? PassThrough;\n const components = route.outlets.map((o) => o.Component);\n const outlet = <RouterOutlet route={route} components={components} />;\n\n // Render crashes in pages/wrappers funnel to the nearest [ERROR]\n // component; the layout survives. On synthetic error routes the\n // boundary is omitted so a crashing [ERROR] component propagates\n // out of <Router> — a developer bug that should stay loud. Layout\n // crashes propagate for the same reason. The boundary is unkeyed on\n // purpose — it resets itself when the route changes — so navigation\n // reconciles by component type instead of remounting the subtree.\n const fallback = route.levels.at(-1)?.errorComponent ?? DefaultErrorPage;\n\n return (\n <routerContext.Provider value={store}>\n <Layout route={route}>\n {route.error ? (\n outlet\n ) : (\n <RouteErrorBoundary route={route} fallback={fallback}>\n {outlet}\n </RouteErrorBoundary>\n )}\n </Layout>\n </routerContext.Provider>\n );\n});\n","import { observer } from \"mobx-react-lite\";\nimport React, { useCallback } from \"react\";\nimport type {\n DynamicRoutePath,\n ExtractParams,\n NavigateOptions,\n RoutePath,\n StaticRoutePath,\n} from \"../types\";\nimport { resolvePath } from \"../util\";\nimport { useRouter } from \"./router\";\n\ntype LinkComponentProps<C extends React.ElementType> = Omit<\n React.ComponentProps<C>,\n \"ref\" | \"exact\" | \"to\" | \"params\" | \"onClick\" | \"asChild\"\n>;\n\nexport type LinkPropsBase<\n C extends React.ElementType,\n I extends React.ElementType = C,\n> = LinkComponentProps<C> & {\n exact?: boolean;\n preserveSearch?: boolean;\n ref?: React.Ref<React.ComponentRef<I>>;\n};\n\n// function overloading is much faster than leveraging conditional types\n// but once the typescript go compiler is released and performance is no\n// longer an issue, it might make sense to simplify this a bit so it can\n// be more easily consumed by users\nexport interface LinkComponent<C extends React.ElementType, I extends React.ElementType = C> {\n <P extends StaticRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params?: undefined },\n ): React.ReactNode;\n <P extends DynamicRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params: ExtractParams<P> },\n ): React.ReactNode;\n}\n\n// final thing to do is make sure refs still work in React 19\n\n// this smooths over some of the awkwardness when extending this component\nexport const makeLinkComponent = <C extends React.ElementType, I extends React.ElementType = C>(\n C: C,\n baseProps?: Partial<LinkComponentProps<C>> & { as?: I },\n) => {\n return observer(({ to, params, exact, preserveSearch, children, ...props }: any) => {\n const router = useRouter();\n const mergedProps = { ...baseProps, ...props };\n\n if (props.role !== \"link\") {\n mergedProps.href = resolvePath(to, params);\n }\n\n if (router.doesPathMatch(to, exact)) {\n mergedProps[\"aria-current\"] = \"page\";\n }\n\n mergedProps.onClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.preventDefault();\n if (props.disabled) return;\n router.navigate({ to, preserveSearch, params } as NavigateOptions<RoutePath>);\n },\n [router, params, to, props.disabled],\n );\n\n return React.createElement(C, mergedProps, children);\n }) as LinkComponent<C, I>;\n};\n\n//export const Link = makeLinkComponent('a');\n","import { useLayoutEffect } from \"react\";\nimport type { NavigateOptions, RoutePath } from \"../types\";\nimport { useRouter } from \"./router\";\n\nexport const Navigate = <P extends RoutePath>(props: NavigateOptions<P>) => {\n const router = useRouter();\n\n useLayoutEffect(() => {\n router.navigate(props);\n }, [router, props]);\n\n return null;\n};\n","import type { NavigateOptions, RoutePath } from \"./types\";\n\nexport class Redirect<P extends RoutePath> {\n constructor(readonly options: NavigateOptions<P>) {}\n}\n\nexport const redirect = <P extends RoutePath>(options: NavigateOptions<P>): Redirect<P> =>\n new Redirect(options);\n","import { makeAutoObservable, observable } from \"mobx\";\nimport { DefaultErrorPage } from \"./components/error\";\nimport { RouterError } from \"./errors\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, LazyComponent, Loader, Obj } from \"./types\";\nimport { isLazyComponent } from \"./util\";\n\nexport interface OutletConfig {\n component?: Component | LazyComponent;\n loader?: Loader;\n errorComponent?: Component;\n}\n\nexport type RouteSegmentState = \"preloading\" | \"loading\" | \"error\" | \"ready\";\n\nexport const DefaultOutlet: Component = ({ children }) => children;\n\nconst LoadingPlaceholder: Component = () => <p>Loading...</p>;\n\nexport class Outlet {\n state: RouteSegmentState = \"preloading\";\n promise: Promise<unknown> | undefined;\n data: unknown;\n error: RouterError | undefined;\n\n // Plain (non-observable) reference. The page component must reach\n // React unmediated by MobX — once MobX deep-observes the holder,\n // React Refresh can no longer swap the page identity via family\n // lookup on the original function. This mirrors how Route holds\n // `layout` as a plain field under makeObservable.\n component: Component | undefined;\n\n get Component(): Component | undefined {\n switch (this.state) {\n case \"loading\":\n return LoadingPlaceholder;\n case \"ready\":\n return this.component ?? DefaultOutlet;\n case \"error\": {\n // render the nearest [ERROR] component in this outlet's slot,\n // leaving the rest of the page intact\n const ErrorComponent = this.config.errorComponent ?? DefaultErrorPage;\n const error = this.error ?? new RouterError(\"LOAD\");\n return (props: Obj) => <ErrorComponent {...props} error={error} />;\n }\n default:\n return undefined;\n }\n }\n\n constructor(readonly config: OutletConfig) {\n if (!isLazyComponent(config.component)) {\n this.component = config.component;\n }\n\n makeAutoObservable<Outlet, \"component\" | \"config\">(this, {\n promise: observable.ref,\n data: observable.ref,\n error: observable.ref,\n component: false,\n config: false,\n });\n }\n\n async load(route: Route): Promise<void> {\n const promises: Promise<void>[] = [];\n\n if (isLazyComponent(this.config.component) && !this.component) {\n promises.push(this.loadComponent());\n }\n\n if (this.config.loader) {\n promises.push(this.loadData(route));\n }\n\n if (!promises.length) {\n this.setState(\"ready\");\n return;\n }\n\n // wait to transition to loading to avoid\n // screen flashes when the loader function\n // executes quickly\n const preloadingTimer = setTimeout(() => {\n if (this.state === \"preloading\") {\n this.setState(\"loading\");\n }\n }, 300);\n\n this.promise = Promise.all(promises)\n .then(() => {\n clearTimeout(preloadingTimer);\n if (this.state === \"loading\") {\n // if we had to transition to regular loading because\n // the loader was taking too long, force an additional\n // timeout to prevent a loading flash\n setTimeout(() => {\n this.setState(\"ready\");\n }, 300);\n } else {\n this.setState(\"ready\");\n }\n })\n .catch((e) => {\n clearTimeout(preloadingTimer);\n this.setState(\"error\");\n // a Redirect thrown by a loader propagates so the router\n // navigates; everything else renders in-slot error UI\n if (e instanceof Redirect) throw e;\n this.setError(e instanceof RouterError ? e : new RouterError(\"LOAD\", { cause: e }));\n });\n\n await this.promise;\n }\n\n setData(data: unknown) {\n this.data = data;\n }\n\n setError(error: RouterError) {\n this.error = error;\n }\n\n setState(state: RouteSegmentState) {\n this.state = state;\n }\n\n private async loadData(route: Route): Promise<void> {\n await this.config.loader?.(route).then((data) => this.setData(data));\n }\n\n private async loadComponent(): Promise<void> {\n if (!isLazyComponent(this.config.component)) return;\n const module = await this.config.component();\n for (const exportName in module) {\n if (exportName === \"default\" || exportName.endsWith(\"Page\")) {\n this.component = module[exportName];\n return;\n }\n }\n throw new Error(\n \"Lazy route component module did not export `default` or a `*Page` named export\",\n );\n }\n}\n","import { computed, makeObservable } from \"mobx\";\nimport { RouterError } from \"./errors\";\nimport type { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport type { Component, Guard, GuardEntry, MatchLevel, Obj } from \"./types\";\n\nexport interface RouteConfig {\n path: string;\n outlets: Outlet[];\n guards: GuardEntry[];\n levels: MatchLevel[];\n context?: Obj;\n layout?: Component;\n params: Obj;\n error?: RouterError;\n}\n\nexport class Route {\n readonly path: string;\n readonly outlets: Outlet[];\n readonly guards: Guard[];\n readonly context: Obj;\n readonly params: Obj;\n readonly layout?: Component;\n /** set on synthetic error routes; the error being rendered */\n readonly error?: RouterError;\n /** @internal */\n readonly guardEntries: GuardEntry[];\n /** @internal */\n readonly levels: MatchLevel[];\n\n get data(): Obj {\n return Object.assign({}, ...this.outlets.map((o) => o.data));\n }\n\n constructor(def: RouteConfig) {\n this.path = def.path;\n this.guardEntries = def.guards;\n this.guards = def.guards.map((entry) => entry.guard);\n this.levels = def.levels;\n this.context = def.context ?? {};\n this.outlets = def.outlets;\n this.params = def.params;\n this.layout = def.layout;\n this.error = def.error;\n\n makeObservable(this, {\n data: computed,\n });\n }\n\n async guard(): Promise<void> {\n for (const { guard, depth } of this.guardEntries) {\n try {\n await guard(this);\n } catch (e) {\n if (e instanceof Redirect) throw e;\n const error = e instanceof RouterError ? e : new RouterError(\"GUARD\", { cause: e });\n error.depth ??= depth;\n throw error;\n }\n }\n }\n\n async load(): Promise<void> {\n await Promise.all(this.outlets.map((outlet) => outlet.load(this)));\n }\n}\n","import { DefaultErrorPage } from \"./components/error\";\nimport { RouterError } from \"./errors\";\nimport { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport { Route } from \"./route\";\nimport { CONTEXT, ERROR, GUARD, LAYOUT, LOAD, PAGE, REDIRECT, WRAPPER } from \"./symbols\";\nimport type { Component, GuardEntry, MatchLevel, Obj, Routes } from \"./types\";\nimport { isComponent, isLazyComponent, isLeaf, isPage, isRedirect } from \"./util\";\n\nconst pathToSegments = (path: string): string[] => {\n return path.replace(/^\\/+|\\/+$/g, \"\").split(\"/\");\n};\n\nexport interface MatchState {\n segments: string[];\n context: Obj;\n params: Obj;\n outlets: (Outlet | undefined)[];\n guards: GuardEntry[];\n levels: MatchLevel[];\n layout?: Component;\n errorComponent?: Component;\n}\n\nexport const makeRoute = (matchState: MatchState): Route => {\n const outlets = matchState.outlets.filter((o) => o !== undefined);\n\n return new Route({ ...matchState, outlets, path: matchState.segments.join(\"/\") });\n};\n\n/**\n * Builds the synthetic route rendered when navigation fails. Bubbles\n * from the failing level (`error.depth`, defaulting to the deepest\n * matched level) to the nearest `[ERROR]` component, preserving the\n * `[LAYOUT]` and `[WRAPPER]`s accumulated up to that level. Ancestor\n * `[LOAD]` loaders are intentionally not run — error routes never\n * fetch data.\n */\nexport const makeErrorRoute = (\n error: RouterError,\n pathname: string,\n source?: { levels: MatchLevel[]; params: Obj; context: Obj },\n): Route => {\n const levels = error.state?.levels ?? source?.levels ?? [];\n const depth = Math.min(error.depth ?? levels.length - 1, levels.length - 1);\n const level = depth >= 0 ? levels[depth] : undefined;\n\n const ErrorComponent = level?.errorComponent ?? DefaultErrorPage;\n const outlets = levels\n .slice(0, depth + 1)\n .flatMap((l) => (l.wrapper ? [new Outlet({ component: l.wrapper })] : []));\n outlets.push(\n new Outlet({ component: (props: Obj) => <ErrorComponent {...props} error={error} /> }),\n );\n\n return new Route({\n path: pathname.replace(/^\\/+/, \"\"),\n outlets,\n guards: [],\n levels: [],\n params: error.state?.params ?? source?.params ?? {},\n context: error.state?.context ?? source?.context ?? {},\n layout: level?.layout,\n error,\n });\n};\n\nconst notFound = (state: MatchState, attemptedSegments: string[]): RouterError => {\n const error = new RouterError(\"NOT_FOUND\", {\n path: `/${attemptedSegments.filter((s) => s !== \"\").join(\"/\")}`,\n });\n error.state = state;\n return error;\n};\n\nexport const matchRoute = (path: string, routeDef: Routes, matchState?: MatchState): Route => {\n const depth = matchState?.levels.length ?? 0;\n const layout = routeDef[LAYOUT] ?? matchState?.layout;\n const errorComponent = routeDef[ERROR] ?? matchState?.errorComponent;\n\n const state: MatchState = {\n segments: [],\n params: {},\n ...matchState,\n layout,\n errorComponent,\n context: { ...matchState?.context, ...routeDef[CONTEXT] },\n guards: [\n ...(matchState?.guards ?? []),\n ...(routeDef[GUARD] ? [{ guard: routeDef[GUARD], depth }] : []),\n ],\n outlets: [\n ...(matchState?.outlets ?? []),\n routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER], errorComponent }) : undefined,\n routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD], errorComponent }) : undefined,\n ],\n levels: [...(matchState?.levels ?? []), { wrapper: routeDef[WRAPPER], layout, errorComponent }],\n };\n\n const [segment, ...remainingSegments] = pathToSegments(path);\n const remainingPath = remainingSegments.join(\"/\");\n\n let defAtSegment = routeDef[segment || \"index\"];\n\n if (!defAtSegment) {\n const matchedSegment = Object.keys(routeDef).find(\n (segment) => segment.startsWith(\"$\") || segment.startsWith(\":\"),\n );\n if (matchedSegment) {\n defAtSegment = routeDef[matchedSegment];\n state.params[matchedSegment.slice(1)] = segment;\n }\n }\n\n if (!defAtSegment) {\n throw notFound(state, [...state.segments, segment ?? \"\", ...remainingSegments]);\n }\n\n state.segments.push(segment ?? \"index\");\n\n if (isLeaf(defAtSegment)) {\n if (remainingPath) {\n throw notFound(state, [...state.segments, ...remainingSegments]);\n }\n\n if (isRedirect(defAtSegment)) {\n const redirect =\n typeof defAtSegment[REDIRECT] === \"string\"\n ? { to: defAtSegment[REDIRECT] }\n : defAtSegment[REDIRECT];\n throw new Redirect(redirect as any);\n }\n\n if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {\n state.outlets.push(new Outlet({ component: defAtSegment, errorComponent }));\n return makeRoute(state);\n }\n }\n\n // at this point we have a nested route or a [Page] definition\n\n if (isPage(defAtSegment)) {\n state.layout = defAtSegment[LAYOUT] ?? state.layout;\n state.errorComponent = defAtSegment[ERROR] ?? state.errorComponent;\n Object.assign(state.context, defAtSegment[CONTEXT]);\n if (defAtSegment[GUARD]) {\n state.guards.push({ guard: defAtSegment[GUARD], depth });\n }\n state.outlets.push(\n new Outlet({\n component: defAtSegment[PAGE],\n loader: defAtSegment[LOAD],\n errorComponent: state.errorComponent,\n }),\n );\n state.levels[state.levels.length - 1] = {\n ...state.levels[state.levels.length - 1],\n layout: state.layout,\n errorComponent: state.errorComponent,\n };\n\n return makeRoute(state);\n }\n\n // now we know we have a nested route\n return matchRoute(remainingPath, defAtSegment, state);\n};\n\n// TODO: ideally this could resolve to something less than R,\n// but specific enough to infer all paths as a literal union.\n// As it stands, there are certain things we can't access reliably\n// without the compiler complaining about circular references\n// try \"as const satisfies\" approach which would allow us to\n// exchange a less specific version of MobxRoutesRoot for this\nexport const makeRoutes =\n () =>\n <R extends Routes>(routes: R): R => {\n // todo: perform some validation here\n // - no forward slashes in keys\n // - at most one variable segment per level\n // - only lowercase letters (except variables)\n // - paths/variables cannot contain $ or : that aren't at the beginning\n // - path variables must be unique across a path\n return routes;\n };\n","import { createBrowserHistory, type History, type Location } from \"history\";\nimport { action, computed, makeObservable, observable, runInAction } from \"mobx\";\nimport { RouterError } from \"./errors\";\nimport { makeErrorRoute, matchRoute } from \"./make-routes\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, MobxRouterConfig, NavigateOptions, Obj, RoutePath, Routes } from \"./types\";\nimport { resolvePath } from \"./util\";\n\nexport interface MobxRenderSegment {\n segment: string;\n component: Component;\n props?: Obj;\n}\n\nexport class RouterStore {\n readonly history: History;\n\n routesDef?: Routes;\n\n location!: Location;\n activeRoute: Route | undefined;\n\n get search(): URLSearchParams {\n return new URLSearchParams(this.location?.search);\n }\n\n get query(): Record<string, string> {\n return Object.fromEntries(this.search);\n }\n\n get pathParams(): Record<string, string> {\n return { ...this.activeRoute?.params };\n }\n\n get activeSegments(): string[] {\n return this.activeRoute?.path.split(\"/\") ?? [];\n }\n\n constructor(config?: MobxRouterConfig) {\n makeObservable(this, {\n location: observable.ref,\n activeRoute: observable.ref,\n\n search: computed,\n pathParams: computed,\n activeSegments: computed,\n\n setLocation: action,\n });\n\n this.history = config?.history ?? createBrowserHistory();\n }\n\n initialize(routesDef: Routes): void {\n this.routesDef = routesDef;\n this.history.listen((data) => {\n void this.setLocation(data.location);\n });\n\n void this.setLocation(this.history.location);\n }\n\n doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean {\n const segments = path.slice(1).split(\"/\");\n const segmentsMatch = segments.every(\n (segment, i) => segment === this.activeSegments[i] || segment.startsWith(\":\"),\n );\n\n return (\n segmentsMatch &&\n this.activeSegments.length >= segments.length &&\n (!exact || segments.length === this.activeSegments.length)\n );\n }\n\n navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n // navigating to the current URL attaches no new information — skip\n // the navigation (and its view transition) entirely so redundant\n // navigations (e.g. clicking an already-active link) cause no churn\n if (!options.state && this.isCurrentLocation(options)) {\n return;\n }\n\n if (!document.startViewTransition) {\n this._navigate(options);\n } else {\n const transition = document.startViewTransition(() => this._navigate(options));\n transition.ready.catch((e) => console.log(e, typeof e));\n }\n }\n\n _navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n const location = this.resolveLocation(options);\n\n if (options.replace) {\n this.history.replace(location, options.state);\n } else {\n this.history.push(location, options.state);\n }\n }\n\n private resolveLocation<P extends RoutePath>(\n options: NavigateOptions<P>,\n ): { pathname: string; search: string | undefined } {\n const { to, search = {}, preserveSearch, params } = options;\n\n const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);\n\n if (preserveSearch) {\n for (const [name, value] of this.search) {\n if (!searchParams.has(name)) {\n searchParams.set(name, value);\n }\n }\n }\n\n return {\n pathname: resolvePath(to, params),\n search: searchParams.size ? `?${searchParams.toString()}` : undefined,\n };\n }\n\n private isCurrentLocation<P extends RoutePath>(options: NavigateOptions<P>): boolean {\n if (!this.location) return false;\n\n const target = this.resolveLocation(options);\n return (\n target.pathname === this.location.pathname && (target.search ?? \"\") === this.location.search\n );\n }\n\n setQueryParam(param: string, value: string): void {\n const params = new URLSearchParams(this.location.search);\n params.set(param, value);\n this.history.replace({ search: `?${params.toString()}` });\n }\n\n removeQueryParam(param: string): string | undefined {\n const params = new URLSearchParams(this.location.search);\n const value = params.get(param) ?? undefined;\n if (value !== undefined) {\n params.delete(param);\n this.history.replace({ search: params.size ? `?${params.toString()}` : \"\" });\n }\n return value;\n }\n\n async setLocation(location: Location): Promise<void> {\n if (!this.routesDef) return;\n\n // TODO: this should not be the responsibility of mobx-router\n // and should really be handled server-side\n if (location.pathname !== \"/\" && location.pathname.endsWith(\"/\")) {\n this.history.replace({ ...location, pathname: location.pathname.slice(0, -1) });\n return;\n }\n\n // a same-pathname change (query params, history state) can't affect\n // which route matches, its guards, or its loaders (none of which can\n // observe search params) — update the observable location without\n // rebuilding the route, so query-param changes don't refetch loaders\n // or replace activeRoute\n if (this.activeRoute && this.location?.pathname === location.pathname) {\n this.location = location;\n return;\n }\n\n this.location = location;\n\n let matchedRoute: Route | undefined;\n try {\n matchedRoute = matchRoute(location.pathname, this.routesDef);\n\n await matchedRoute.guard();\n\n // navigating within a guard function\n // is essentially a redirect\n if (this.location !== location) {\n return;\n }\n\n runInAction(() => {\n this.activeRoute = matchedRoute;\n });\n\n await this.activeRoute?.load();\n } catch (e) {\n if (e instanceof Redirect) {\n this.navigate(e.options);\n return;\n }\n\n // navigating within a guard before it threw — treat as a redirect\n if (this.location !== location) {\n return;\n }\n\n const error =\n e instanceof RouterError\n ? e\n : new RouterError(\"RENDER\", { cause: e, path: location.pathname });\n console.error(error);\n\n const errorRoute = makeErrorRoute(error, location.pathname, matchedRoute);\n runInAction(() => {\n this.activeRoute = errorRoute;\n });\n await errorRoute.load();\n }\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jayalfredprufrock/mobx-toolbox",
3
- "version": "0.6.5",
3
+ "version": "0.7.1",
4
4
  "description": "Misc mobx/react modules/utilities.",
5
5
  "homepage": "https://github.com/jayalfredprufrock/mobx-toolbox#readme",
6
6
  "bugs": {
@@ -33,10 +33,13 @@
33
33
  "@tsconfig/node24": "^24.0.4",
34
34
  "@types/node": "^24.12.0",
35
35
  "@types/react": "^19.2.2",
36
+ "@types/react-dom": "catalog:",
36
37
  "@typescript/native-preview": "7.0.0-dev.20260328.1",
38
+ "happy-dom": "catalog:",
37
39
  "history": "^5.3.0",
38
40
  "mobx-react-lite": "^4.1.1",
39
- "react": "^19.2.4",
41
+ "react": "catalog:",
42
+ "react-dom": "catalog:",
40
43
  "semantic-release": "^25.0.3",
41
44
  "typebox": "^1.1.17",
42
45
  "typescript": "^6.0.2",