@kitbag/router 0.25.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/components/routerLink.d.ts +3 -3
  2. package/dist/compositions/useHasSuspenseBoundary.browser.spec.d.ts +1 -0
  3. package/dist/compositions/useHasSuspenseBoundary.d.ts +4 -0
  4. package/dist/compositions/useIsServerRendering.browser.spec.d.ts +1 -0
  5. package/dist/compositions/useIsServerRendering.d.ts +5 -0
  6. package/dist/compositions/useIsServerRendering.spec.d.ts +1 -0
  7. package/dist/errors/contextRedirectError.d.ts +7 -0
  8. package/dist/errors/navigationAbandonedError.d.ts +1 -0
  9. package/dist/errors/payloadValueError.d.ts +9 -0
  10. package/dist/errors/ssrOptionRequiredError.d.ts +7 -0
  11. package/dist/errors/unsupportedSchemaVendorError.d.ts +7 -0
  12. package/dist/errors/updateWithoutRouteError.d.ts +7 -0
  13. package/dist/kitbag-router.d.ts +1 -1
  14. package/dist/kitbag-router.js +6647 -6429
  15. package/dist/kitbag-router.umd.cjs +5 -5
  16. package/dist/main.d.ts +2 -0
  17. package/dist/services/addLoader.d.ts +4 -1
  18. package/dist/services/addView.d.ts +4 -1
  19. package/dist/services/arktype.spec-d.d.ts +1 -0
  20. package/dist/services/arktype.spec.d.ts +1 -0
  21. package/dist/services/createActivityTracker.d.ts +6 -0
  22. package/dist/services/createActivityTracker.spec.d.ts +1 -0
  23. package/dist/services/createCurrentRejection.d.ts +0 -3
  24. package/dist/services/createNavigationIds.d.ts +6 -0
  25. package/dist/services/createNavigationIds.spec.d.ts +1 -0
  26. package/dist/services/createNavigationStores.d.ts +10 -5
  27. package/dist/services/createRejection.d.ts +2 -6
  28. package/dist/services/createRejection.spec-d.d.ts +1 -0
  29. package/dist/services/createRejection.spec.d.ts +1 -0
  30. package/dist/services/createRouteHooks.d.ts +1 -1
  31. package/dist/services/createRouteValueStore.d.ts +44 -12
  32. package/dist/services/createRouteValueStore.spec.d.ts +1 -0
  33. package/dist/services/createRouterCallbackContext.d.ts +1 -1
  34. package/dist/services/createRouterHistory.spec.d.ts +1 -0
  35. package/dist/services/createServerRedirect.d.ts +14 -0
  36. package/dist/services/createServerRedirect.spec.d.ts +1 -0
  37. package/dist/services/getComputations.d.ts +40 -0
  38. package/dist/services/getGlobalRouteHooks.d.ts +2 -2
  39. package/dist/services/getInitialUrl.d.ts +2 -1
  40. package/dist/services/getRouteHooks.d.ts +2 -2
  41. package/dist/services/getRoutesForRouter.d.ts +3 -1
  42. package/dist/services/hooks.d.ts +1 -1
  43. package/dist/services/payload.d.ts +86 -0
  44. package/dist/services/payload.spec.d.ts +1 -0
  45. package/dist/services/standardSchema.d.ts +21 -0
  46. package/dist/services/urlParser.d.ts +5 -0
  47. package/dist/tests/hydration.browser.spec.d.ts +1 -0
  48. package/dist/tests/render.spec.d.ts +1 -0
  49. package/dist/types/addLoader.d.ts +3 -2
  50. package/dist/types/addView.d.ts +7 -2
  51. package/dist/types/callbackContext.d.ts +9 -0
  52. package/dist/types/hooks.d.ts +14 -15
  53. package/dist/types/paramTypes.d.ts +2 -3
  54. package/dist/types/params.d.ts +1 -1
  55. package/dist/types/redirects.d.ts +11 -3
  56. package/dist/types/rejection.d.ts +24 -4
  57. package/dist/types/resolved.d.ts +4 -2
  58. package/dist/types/routeLoaders.d.ts +2 -0
  59. package/dist/types/routeTitle.d.ts +2 -1
  60. package/dist/types/routeViews.d.ts +2 -0
  61. package/dist/types/router.d.ts +95 -3
  62. package/dist/types/routerPlugin.d.ts +7 -3
  63. package/dist/types/routerReject.d.ts +13 -0
  64. package/dist/types/routerRoute.d.ts +1 -1
  65. package/dist/types/serverRenderResponse.spec-d.d.ts +1 -0
  66. package/dist/utilities/components.d.ts +13 -1
  67. package/dist/utilities/setDocumentTitle.d.ts +1 -2
  68. package/package.json +10 -15
  69. package/dist/services/valibot.d.ts +0 -7
  70. package/dist/services/zod.d.ts +0 -11
@@ -1,5 +1,5 @@
1
1
  import { Hooks } from '../models/hooks';
2
- import { ResolvedRoute, RouterResolvedRouteUnion, ResolvedRouteUnion } from './resolved';
2
+ import { RouterResolvedRouteUnion, ResolvedRouteUnion } from './resolved';
3
3
  import { MaybePromise } from './utilities';
4
4
  import { Route, Routes } from './route';
5
5
  import { RouterReject } from './routerReject';
@@ -8,7 +8,7 @@ import { RouterReplace } from './routerReplace';
8
8
  import { Rejection, Rejections } from './rejection';
9
9
  import { RouteContext, RouteContextToRejection, RouteContextToRoute } from './routeContext';
10
10
  import { RouterAbort } from './routerAbort';
11
- import { CallbackContextAbort, CallbackContextPush, CallbackContextReject, CallbackContextSuccess } from './callbackContext';
11
+ import { CallbackContextAbort, CallbackContextPush, CallbackContextRedirect, CallbackContextReject, CallbackContextSuccess } from './callbackContext';
12
12
  import { RouteUpdate } from './routeUpdate';
13
13
  export declare function getHooks(value: Record<string, unknown> | undefined | null): Hooks[];
14
14
  export declare function combineHooks(parent: Route, child: Route): Hooks[];
@@ -107,10 +107,10 @@ export type BeforeUpdateHookContext<TRoutes extends Routes = Routes, TRejections
107
107
  };
108
108
  export type BeforeUpdateHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo>, context: BeforeUpdateHookContext<TRoutes, TRejections, TRouteTo, TRouteFrom>) => MaybePromise<void>;
109
109
  export type AddBeforeUpdateHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (hook: BeforeUpdateHook<TRoutes, TRejections, TRouteTo, TRouteFrom>) => HookRemove;
110
- export type BeforeLeaveHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = BeforeHookContext<TRouteTo, TRoutes, TRejections> & {
110
+ export type BeforeLeaveHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = Omit<BeforeHookContext<TRouteTo, TRoutes, TRejections>, 'update'> & {
111
111
  from: ResolvedRouteUnion<TRouteFrom>;
112
112
  };
113
- export type BeforeLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo>, context: BeforeLeaveHookContext<TRoutes, TRejections, TRouteTo, TRouteFrom>) => MaybePromise<void>;
113
+ export type BeforeLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo> | null, context: BeforeLeaveHookContext<TRoutes, TRejections, TRouteTo, TRouteFrom>) => MaybePromise<void>;
114
114
  export type AddBeforeLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (hook: BeforeLeaveHook<TRoutes, TRejections, TRouteTo, TRouteFrom>) => HookRemove;
115
115
  export type AfterEnterHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = AfterHookContext<TRouteTo, TRoutes, TRejections> & {
116
116
  from: ResolvedRouteUnion<TRouteFrom> | null;
@@ -122,19 +122,19 @@ export type AfterUpdateHookContext<TRoutes extends Routes = Routes, TRejections
122
122
  };
123
123
  export type AfterUpdateHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo>, context: AfterUpdateHookContext<TRoutes, TRejections, TRouteTo, TRouteFrom>) => MaybePromise<void>;
124
124
  export type AddAfterUpdateHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (hook: AfterUpdateHook<TRoutes, TRejections, TRouteTo, TRouteFrom>) => HookRemove;
125
- export type AfterLeaveHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = AfterHookContext<TRouteTo, TRoutes, TRejections> & {
125
+ export type AfterLeaveHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = Omit<AfterHookContext<TRouteTo, TRoutes, TRejections>, 'update'> & {
126
126
  from: ResolvedRouteUnion<TRouteFrom>;
127
127
  };
128
- export type AfterLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo>, context: AfterLeaveHookContext<TRoutes, TRejections, TRouteTo, TRouteFrom>) => MaybePromise<void>;
128
+ export type AfterLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo> | null, context: AfterLeaveHookContext<TRoutes, TRejections, TRouteTo, TRouteFrom>) => MaybePromise<void>;
129
129
  export type AddAfterLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = (hook: AfterLeaveHook<TRoutes, TRejections, TRouteTo, TRouteFrom>) => HookRemove;
130
- export type BeforeHookResponse = CallbackContextSuccess | CallbackContextPush | CallbackContextReject | CallbackContextAbort;
130
+ export type BeforeHookResponse = CallbackContextSuccess | CallbackContextPush | CallbackContextRedirect | CallbackContextReject | CallbackContextAbort;
131
131
  export type AfterHookResponse = CallbackContextSuccess | CallbackContextPush | CallbackContextReject;
132
132
  export type BeforeHookRunner = <TRoutes extends Routes>(context: {
133
- to: RouterResolvedRouteUnion<TRoutes>;
133
+ to: RouterResolvedRouteUnion<TRoutes> | null;
134
134
  from: RouterResolvedRouteUnion<TRoutes> | null;
135
135
  }) => Promise<BeforeHookResponse>;
136
136
  export type AfterHookRunner = <TRoutes extends Routes>(context: {
137
- to: RouterResolvedRouteUnion<TRoutes>;
137
+ to: RouterResolvedRouteUnion<TRoutes> | null;
138
138
  from: RouterResolvedRouteUnion<TRoutes> | null;
139
139
  }) => Promise<AfterHookResponse>;
140
140
  export type RejectionHookContext<TRoutes extends Routes = Routes, TRouteTo extends Route = TRoutes[number], TRouteFrom extends Route = TRoutes[number]> = {
@@ -147,19 +147,18 @@ export type RejectionHookRunner<TRejection extends Rejection = Rejection, TRoute
147
147
  to: RouterResolvedRouteUnion<TRoutes> | null;
148
148
  from: RouterResolvedRouteUnion<TRoutes> | null;
149
149
  }) => void;
150
- export type ErrorHookContext<TRoute extends Route = Route, TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = {
151
- to: RouterResolvedRouteUnion<TRoutes>;
150
+ export type ErrorHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = {
151
+ to: RouterResolvedRouteUnion<TRoutes> | null;
152
152
  from: RouterResolvedRouteUnion<TRoutes> | null;
153
153
  source: 'props' | 'loader' | 'hook' | 'component';
154
154
  reject: RouterReject<TRejections>;
155
155
  push: RouterPush<TRoutes>;
156
156
  replace: RouterReplace<TRoutes>;
157
- update: RouteUpdate<ResolvedRoute<TRoute>>;
158
157
  };
159
- export type ErrorHook<TRoute extends Route = Route, TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (error: unknown, context: ErrorHookContext<TRoute, TRoutes, TRejections>) => void;
160
- export type AddErrorHook<TRoute extends Route = Route, TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (hook: ErrorHook<TRoute, TRoutes, TRejections>) => HookRemove;
158
+ export type ErrorHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (error: unknown, context: ErrorHookContext<TRoutes, TRejections>) => void;
159
+ export type AddErrorHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (hook: ErrorHook<TRoutes, TRejections>) => HookRemove;
161
160
  export type ErrorHookRunnerContext<TRoutes extends Routes = Routes> = {
162
- to: RouterResolvedRouteUnion<TRoutes>;
161
+ to: RouterResolvedRouteUnion<TRoutes> | null;
163
162
  from: RouterResolvedRouteUnion<TRoutes> | null;
164
163
  source: 'props' | 'loader' | 'hook';
165
164
  };
@@ -1,5 +1,4 @@
1
- import { ValibotSchemaLike } from '../services/valibot';
2
- import { ZodSchemaLike } from '../services/zod';
1
+ import { ArkTypeSchemaLike, ValibotSchemaLike, ZodSchemaLike } from '../services/standardSchema';
3
2
  export type ParamExtras = {
4
3
  invalid: (message?: string) => never;
5
4
  };
@@ -11,4 +10,4 @@ export type ParamGetSet<T = any> = {
11
10
  defaultValue?: T;
12
11
  };
13
12
  export type LiteralParam = string | number | boolean;
14
- export type Param = ParamGetter | ParamGetSet | RegExp | BooleanConstructor | NumberConstructor | StringConstructor | DateConstructor | JSON | ZodSchemaLike | ValibotSchemaLike | LiteralParam;
13
+ export type Param = ParamGetter | ParamGetSet | RegExp | BooleanConstructor | NumberConstructor | StringConstructor | DateConstructor | JSON | ZodSchemaLike | ValibotSchemaLike | ArkTypeSchemaLike | LiteralParam;
@@ -33,7 +33,7 @@ export type ExtractParamName<TParam extends PropertyKey> = TParam extends string
33
33
  * @template TParam - The parameter type.
34
34
  * @returns The extracted type, or 'string' as a fallback.
35
35
  */
36
- export type ExtractParamType<TParam extends Param> = Param extends TParam ? unknown : TParam extends ParamGetSet<infer Type> ? Type : TParam extends DateConstructor ? Date : TParam extends JSON ? unknown : TParam extends ParamGetter ? ReturnType<TParam> : TParam extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TParam> : TParam extends LiteralParam ? TParam : string;
36
+ export type ExtractParamType<TParam extends Param> = Param extends TParam ? unknown : TParam extends ParamGetSet<infer Type> ? Type : TParam extends DateConstructor ? Date : TParam extends JSON ? unknown : TParam extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TParam> : TParam extends ParamGetter ? ReturnType<TParam> : TParam extends LiteralParam ? TParam : string;
37
37
  export type ParamIsOptional<TParam extends string> = TParam extends `?${string}` ? true : false;
38
38
  export type ParamIsGreedy<TParam extends string> = TParam extends `${string}*` ? true : false;
39
39
  export type ParamIsOptionalOrHasDefault<TParamName extends string, TParam extends Param | undefined> = ParamIsOptional<TParamName> extends true ? true : TParam extends Required<ParamGetSet> ? true : false;
@@ -1,5 +1,6 @@
1
1
  import { ResolvedRouteUnion } from './resolved';
2
2
  import { Route, Routes } from './route';
3
+ import { RedirectStatus } from './router';
3
4
  import { RouterReplace } from './routerReplace';
4
5
  import { UrlParamsReading, UrlParamsWriting } from './url';
5
6
  import { AllPropertiesAreOptional, MaybePromise } from './utilities';
@@ -18,12 +19,19 @@ type RedirectHookContext<TRoutes extends Routes> = {
18
19
  };
19
20
  export type RedirectHook<TRoutes extends Routes = Routes, TRouteTo extends Route = TRoutes[number]> = (to: ResolvedRouteUnion<TRouteTo>, context: RedirectHookContext<TRoutes>) => MaybePromise<void>;
20
21
  export type RouteRedirectCallback<TRouteTo extends Route = Route, TRouteFrom extends Route = Route> = (params: UrlParamsReading<TRouteFrom>) => UrlParamsWriting<TRouteTo>;
22
+ export type RouteRedirectOptions = {
23
+ /**
24
+ * The http status a server responds with for this redirect when server rendering. Defaults to the
25
+ * router's `redirectStatus`.
26
+ */
27
+ status?: RedirectStatus;
28
+ };
21
29
  /**
22
30
  * This type is purposely wide to prevent type errors in RouteRedirectFrom where the TRouteTo generic cannot be inferred.
23
31
  */
24
- export type RouteRedirect = (to: Route, callback?: (params: any) => any) => void;
25
- export type RedirectToArgs<TRouteTo extends Route = Route, TRouteFrom extends Route = Route> = AllPropertiesAreOptional<UrlParamsWriting<TRouteTo>> extends true ? [to: TRouteTo, params?: RouteRedirectCallback<TRouteTo, TRouteFrom>] : [to: TRouteTo, params: RouteRedirectCallback<TRouteTo, TRouteFrom>];
32
+ export type RouteRedirect = (to: Route, callback?: (params: any) => any, options?: RouteRedirectOptions) => void;
33
+ export type RedirectToArgs<TRouteTo extends Route = Route, TRouteFrom extends Route = Route> = AllPropertiesAreOptional<UrlParamsWriting<TRouteTo>> extends true ? [to: TRouteTo, params?: RouteRedirectCallback<TRouteTo, TRouteFrom>, options?: RouteRedirectOptions] : [to: TRouteTo, params: RouteRedirectCallback<TRouteTo, TRouteFrom>, options?: RouteRedirectOptions];
26
34
  export type RouteRedirectTo<TRouteFrom extends Route = Route> = <TRouteTo extends Route>(...args: RedirectToArgs<TRouteTo, TRouteFrom>) => void;
27
- export type RedirectFromArgs<TRouteTo extends Route = Route, TRouteFrom extends Route = Route> = AllPropertiesAreOptional<UrlParamsWriting<TRouteTo>> extends true ? [from: TRouteFrom, params?: RouteRedirectCallback<TRouteTo, TRouteFrom>] : [from: TRouteFrom, params: RouteRedirectCallback<TRouteTo, TRouteFrom>];
35
+ export type RedirectFromArgs<TRouteTo extends Route = Route, TRouteFrom extends Route = Route> = AllPropertiesAreOptional<UrlParamsWriting<TRouteTo>> extends true ? [from: TRouteFrom, params?: RouteRedirectCallback<TRouteTo, TRouteFrom>, options?: RouteRedirectOptions] : [from: TRouteFrom, params: RouteRedirectCallback<TRouteTo, TRouteFrom>, options?: RouteRedirectOptions];
28
36
  export type RouteRedirectFrom<TRouteTo extends Route = Route> = <TRouteFrom extends Route>(...args: RedirectFromArgs<TRouteTo, TRouteFrom>) => void;
29
37
  export {};
@@ -1,10 +1,14 @@
1
- import { Ref } from 'vue';
1
+ import { Component, Ref } from 'vue';
2
2
  import { Route } from './route';
3
3
  import { Router } from './router';
4
4
  import { RouterReject } from './routerReject';
5
5
  import { Hooks } from '../models/hooks';
6
- export declare const BUILT_IN_REJECTION_TYPES: readonly ["NotFound"];
7
- export type BuiltInRejectionType = (typeof BUILT_IN_REJECTION_TYPES)[number];
6
+ import { GetTitleCallback } from './routeTitle';
7
+ export declare const BUILT_IN_REJECTIONS: {
8
+ readonly NotFound: 404;
9
+ };
10
+ export type BuiltInRejectionType = keyof typeof BUILT_IN_REJECTIONS;
11
+ export declare const NOT_FOUND_REJECTION_TYPE = "NotFound";
8
12
  export type RouterRejection<T extends Rejection = Rejection> = Ref<T | null>;
9
13
  export type RouterRejections<TRouter extends Router> = TRouter['reject'] extends RouterReject<infer TRejections extends Rejection[]> ? TRejections[number] : never;
10
14
  export declare const IS_REJECTION_SYMBOL: unique symbol;
@@ -18,11 +22,27 @@ export type RejectionInternal = {
18
22
  * Represents an immutable array of Rejection instances.
19
23
  */
20
24
  export type Rejections = readonly Rejection[];
21
- export type Rejection<TType extends string = string> = {
25
+ export type RejectionOptions<TType extends string = string> = {
22
26
  /**
23
27
  * The type of rejection.
24
28
  */
25
29
  type: TType;
30
+ /**
31
+ * The component rendered while this rejection is in effect.
32
+ */
33
+ component?: Component;
34
+ /**
35
+ * The http status a server should respond with while this rejection is in effect. 404 for something
36
+ * missing, 401 or 403 for something gated, 503 for something temporary. Defaults to the router's
37
+ * `rejectStatus`.
38
+ */
39
+ status?: number;
40
+ };
41
+ export type Rejection<TType extends string = string> = Pick<RejectionOptions<TType>, 'type' | 'status'> & {
42
+ /**
43
+ * Returns the title of the rejection from its `setTitle` callback.
44
+ */
45
+ getTitle: GetTitleCallback;
26
46
  };
27
47
  export type RejectionType<TRejections extends Rejections | undefined> = unknown extends TRejections ? never : Rejections extends TRejections ? string : undefined extends TRejections ? string : TRejections extends Rejections ? TRejections[number]['type'] : never;
28
48
  export type ExtractRejections<T> = T extends {
@@ -3,6 +3,7 @@ import { LastInArray } from './utilities';
3
3
  import { ExtractRouteStateParamsAsOptional } from './state';
4
4
  import { UrlString } from './urlString';
5
5
  import { UrlParamsReading } from './url';
6
+ import { GetTitleCallback } from './routeTitle';
6
7
  /**
7
8
  * The match a route resolved to, which is the last of its matches. Falls back to the wide match type when
8
9
  * the matches are not a concrete tuple, so an unregistered router stays assignable.
@@ -51,9 +52,10 @@ export type ResolvedRoute<TRoute extends Route = Route> = Readonly<{
51
52
  */
52
53
  hash: string;
53
54
  /**
54
- * Title of the route.
55
+ * Returns the title of the route from its `setTitle` callback, or from the closest parent route that
56
+ * defines one.
55
57
  */
56
- title: Promise<string | undefined>;
58
+ getTitle: GetTitleCallback;
57
59
  }>;
58
60
  /**
59
61
  * A resolved route whose loaders' data is available. Only the route being navigated to has data: a route
@@ -1,3 +1,4 @@
1
+ import { AnyPayloadTransformer } from '../services/payload';
1
2
  import { PrefetchConfig } from './prefetch';
2
3
  import { AnyFunction } from './utilities';
3
4
  /**
@@ -9,6 +10,7 @@ import { AnyFunction } from './utilities';
9
10
  export type RouteLoader<TData = unknown> = {
10
11
  load: AnyFunction<TData>;
11
12
  prefetch?: PrefetchConfig;
13
+ transformer?: AnyPayloadTransformer;
12
14
  };
13
15
  /**
14
16
  * The loaders for a single route, keyed by loader name (the unnamed loader under 'default').
@@ -1,9 +1,10 @@
1
1
  import { ResolvedRoute, ResolvedRouteUnion } from './resolved';
2
2
  import { Route } from './route';
3
3
  import { MaybePromise } from './utilities';
4
+ export type GetTitleCallback = () => Promise<string | undefined>;
4
5
  export type SetRouteTitleContext = {
5
6
  from: ResolvedRoute;
6
- getParentTitle: () => Promise<string | undefined>;
7
+ getParentTitle: GetTitleCallback;
7
8
  };
8
9
  export type SetRouteTitleCallback<TRoute extends Route = Route> = (to: ResolvedRouteUnion<TRoute>, context: SetRouteTitleContext) => MaybePromise<string>;
9
10
  export type GetRouteTitle<TRoute extends Route = Route> = (to: ResolvedRouteUnion<TRoute>) => Promise<string | undefined>;
@@ -1,3 +1,4 @@
1
+ import { AnyPayloadTransformer } from '../services/payload';
1
2
  import { Component } from 'vue';
2
3
  import { PrefetchConfig } from './prefetch';
3
4
  import { AnyFunction } from './utilities';
@@ -11,6 +12,7 @@ export type RouteView<TProps = undefined> = {
11
12
  component?: Component;
12
13
  props?: AnyFunction<TProps>;
13
14
  prefetch?: PrefetchConfig;
15
+ transformer?: AnyPayloadTransformer;
14
16
  };
15
17
  /**
16
18
  * The views for a single route, keyed by view name (the unnamed view under 'default'). Indexed by depth in
@@ -1,5 +1,6 @@
1
1
  import { App, InjectionKey, Ref } from 'vue';
2
2
  import { RouterHistoryMode } from '../services/createRouterHistory';
3
+ import { TransformerOptions } from '../services/payload';
3
4
  import { RouterRoute } from './routerRoute';
4
5
  import { AddBeforeEnterHook, AddBeforeUpdateHook, AddBeforeLeaveHook, AddAfterEnterHook, AddAfterUpdateHook, AddAfterLeaveHook, AddErrorHook, AddRejectionHook } from './hooks';
5
6
  import { PrefetchConfig } from './prefetch';
@@ -12,16 +13,22 @@ import { RouterReject } from './routerReject';
12
13
  import { RouterPlugin } from './routerPlugin';
13
14
  import { RoutesName } from './routesMap';
14
15
  import { ExtractRejections, ExtractRejectionTypes, Rejections, BuiltInRejectionType } from './rejection';
16
+ import { PayloadValueError } from '../errors/payloadValueError';
15
17
  /**
16
18
  * Options to initialize a {@link Router} instance.
17
19
  */
18
- export type RouterOptions = {
20
+ export type RouterOptions = TransformerOptions & {
19
21
  /**
20
22
  * Initial URL for the router to use. Required if using Node environment. Defaults to window.location when using browser.
21
23
  *
22
24
  * @default window.location.toString()
23
25
  */
24
26
  initialUrl?: string;
27
+ /**
28
+ * Marks the router as rendering on a server, so every navigation is part of the server render from
29
+ * the moment the router is created. Required to call `render`.
30
+ */
31
+ ssr?: boolean;
25
32
  /**
26
33
  * Specifies the history mode for the router, such as "browser", "memory", or "hash".
27
34
  *
@@ -47,6 +54,19 @@ export type RouterOptions = {
47
54
  * @default true
48
55
  */
49
56
  removeTrailingSlashes?: boolean;
57
+ /**
58
+ * The status `render` responds with for a normalized url or a route redirect that does not declare
59
+ * its own.
60
+ *
61
+ * @default 302
62
+ */
63
+ redirectStatus?: RedirectStatus;
64
+ /**
65
+ * The status `render` responds with for a rejection that does not declare its own.
66
+ *
67
+ * @default 200
68
+ */
69
+ rejectStatus?: number;
50
70
  /**
51
71
  * When false, createRouterAssets must be used for component and hooks. Assets exported by the library
52
72
  * will not work with the created router instance.
@@ -55,6 +75,67 @@ export type RouterOptions = {
55
75
  */
56
76
  isGlobalRouter?: boolean;
57
77
  };
78
+ /**
79
+ * What a server should respond with for what the router rendered. `location` exists only on a redirect,
80
+ * so narrowing on it is what proves a `Location` header is available.
81
+ */
82
+ export type ServerRenderResponse = RenderSuccess | RenderReject | RenderRedirect;
83
+ export type RenderSuccess = {
84
+ kind: 'success';
85
+ /**
86
+ * Suggested http status.
87
+ */
88
+ status: number;
89
+ /**
90
+ * A script tag to embed in the document sent to the client, so it adopts what this render settled on
91
+ * rather than working it out again.
92
+ */
93
+ payload: string;
94
+ /**
95
+ * The title of the route that rendered, for the document sent to the client.
96
+ */
97
+ title: string | undefined;
98
+ /**
99
+ * Values that could not be encoded into the payload. Each was left out, so the client computes it
100
+ * again, which can cause a hydration mismatch. Returned so a server can log or inspect them.
101
+ */
102
+ failures: PayloadValueError[];
103
+ };
104
+ export type RenderReject = {
105
+ kind: 'reject';
106
+ /**
107
+ * Suggested http status.
108
+ */
109
+ status: number;
110
+ /**
111
+ * The type of rejection in effect.
112
+ */
113
+ rejection: string;
114
+ /**
115
+ * A script tag to embed in the document sent to the client, so it adopts this rejection rather than
116
+ * working it out again.
117
+ */
118
+ payload: string;
119
+ /**
120
+ * The title of the rejection that rendered, for the document sent to the client.
121
+ */
122
+ title: string | undefined;
123
+ };
124
+ export type RenderRedirect = {
125
+ kind: 'redirect';
126
+ /**
127
+ * Suggested http status.
128
+ */
129
+ status: RedirectStatus;
130
+ /**
131
+ * Value for the `Location` header.
132
+ */
133
+ location: string;
134
+ };
135
+ /**
136
+ * The statuses the router reports for a redirect.
137
+ */
138
+ export type RedirectStatus = 301 | 302;
58
139
  export type Router<TRoutes extends Routes = any, TOptions extends RouterOptions = any, TPlugin extends RouterPlugin = any> = {
59
140
  /**
60
141
  * Installs the router into a Vue application instance.
@@ -129,7 +210,7 @@ export type Router<TRoutes extends Routes = any, TOptions extends RouterOptions
129
210
  * Registers a hook to be called when an error occurs.
130
211
  * If the hook returns true, the error is considered handled and the other hooks are not run. If all hooks return false the error is rethrown
131
212
  */
132
- onError: AddErrorHook<TRoutes[number] | TPlugin['routes'][number], TRoutes | TPlugin['routes'], ExtractRejections<TOptions> | ExtractRejections<TPlugin>>;
213
+ onError: AddErrorHook<TRoutes | TPlugin['routes'], ExtractRejections<TOptions> | ExtractRejections<TPlugin>>;
133
214
  /**
134
215
  * Registers a hook to be called when a rejection occurs.
135
216
  */
@@ -151,7 +232,18 @@ export type Router<TRoutes extends Routes = any, TOptions extends RouterOptions
151
232
  */
152
233
  started: Ref<boolean>;
153
234
  /**
154
- * Stops the router and teardown any listeners.
235
+ * Resolves once the router has nothing left to render: every prop and loader has settled, following
236
+ * any navigation one of them caused, so this waits for the next *full* render rather than for one
237
+ * navigation. Resolves with what a server should respond with.
238
+ *
239
+ * Awaiting `push` only waits for the route to commit; this also waits for its data.
240
+ *
241
+ * Requires the router to be created with the `ssr` option, and throws `SsrOptionRequiredError`
242
+ * without it.
243
+ */
244
+ render: () => Promise<ServerRenderResponse>;
245
+ /**
246
+ * Stops the router. Tears down the history listener and ignores any navigation still in flight or started afterwards.
155
247
  */
156
248
  stop: () => void;
157
249
  /**
@@ -43,11 +43,15 @@ type PluginAfterRouteHookContext<TRoutes extends Routes, TRejections extends Rej
43
43
  replace: RouterReplace<TRoutes>;
44
44
  };
45
45
  export type PluginBeforeRouteHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (to: ResolvedRoute, context: PluginBeforeRouteHookContext<TRoutes, TRejections>) => MaybePromise<void>;
46
+ export type PluginBeforeRouteLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (to: ResolvedRoute | null, context: PluginBeforeRouteHookContext<TRoutes, TRejections>) => MaybePromise<void>;
47
+ type AddPluginBeforeRouteLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (hook: PluginBeforeRouteLeaveHook<TRoutes, TRejections>) => HookRemove;
48
+ export type PluginAfterRouteLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (to: ResolvedRoute | null, context: PluginAfterRouteHookContext<TRoutes, TRejections>) => MaybePromise<void>;
49
+ type AddPluginAfterRouteLeaveHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (hook: PluginAfterRouteLeaveHook<TRoutes, TRejections>) => HookRemove;
46
50
  export type PluginAfterRouteHook<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = (to: ResolvedRoute, context: PluginAfterRouteHookContext<TRoutes, TRejections>) => MaybePromise<void>;
47
51
  type AddPluginBeforeRouteHook<TRoutes extends Routes, TRejections extends Rejections> = (hook: PluginBeforeRouteHook<TRoutes, TRejections>) => HookRemove;
48
52
  type AddPluginAfterRouteHook<TRoutes extends Routes, TRejections extends Rejections> = (hook: PluginAfterRouteHook<TRoutes, TRejections>) => HookRemove;
49
53
  export type PluginErrorHookContext<TRoutes extends Routes = Routes, TRejections extends Rejections = Rejections> = {
50
- to: ResolvedRoute;
54
+ to: ResolvedRoute | null;
51
55
  from: ResolvedRoute | null;
52
56
  source: 'props' | 'loader' | 'hook' | 'component';
53
57
  reject: RouterReject<TRejections>;
@@ -64,7 +68,7 @@ export type PluginRouteHooks<TRoutes extends Routes = Routes, TRejections extend
64
68
  /**
65
69
  * Registers a global hook to be called before a route is left.
66
70
  */
67
- onBeforeRouteLeave: AddPluginBeforeRouteHook<TRoutes, TRejections>;
71
+ onBeforeRouteLeave: AddPluginBeforeRouteLeaveHook<TRoutes, TRejections>;
68
72
  /**
69
73
  * Registers a global hook to be called before a route is updated.
70
74
  */
@@ -76,7 +80,7 @@ export type PluginRouteHooks<TRoutes extends Routes = Routes, TRejections extend
76
80
  /**
77
81
  * Registers a global hook to be called after a route is left.
78
82
  */
79
- onAfterRouteLeave: AddPluginAfterRouteHook<TRoutes, TRejections>;
83
+ onAfterRouteLeave: AddPluginAfterRouteLeaveHook<TRoutes, TRejections>;
80
84
  /**
81
85
  * Registers a global hook to be called after a route is updated.
82
86
  */
@@ -1,2 +1,15 @@
1
1
  import { BuiltInRejectionType, Rejections, RejectionType } from './rejection';
2
+ import { ResolvedRoute } from './resolved';
2
3
  export type RouterReject<TRejections extends Rejections | undefined> = <TSource extends (RejectionType<TRejections> | BuiltInRejectionType)>(type: TSource) => void;
4
+ /**
5
+ * The routes a rejection happened between, which rejection hooks are given.
6
+ */
7
+ export type RejectContext = {
8
+ to?: ResolvedRoute | null;
9
+ from?: ResolvedRoute | null;
10
+ };
11
+ /**
12
+ * Reject as the router itself calls it, which may name any rejection type and supply the routes the
13
+ * rejection happened between. The router exposes {@link RouterReject} instead.
14
+ */
15
+ export type RouterRejectInternal<TRejections extends Rejections | undefined> = RouterReject<TRejections> & ((type: string, context?: RejectContext) => void);
@@ -35,7 +35,7 @@ export type RouterRoute<TRoute extends ResolvedRoute = ResolvedRoute> = {
35
35
  /**
36
36
  * Title of the route.
37
37
  */
38
- readonly title: TRoute['title'];
38
+ readonly getTitle: TRoute['getTitle'];
39
39
  /**
40
40
  * What the route's loaders resolve to, keyed by loader name. A route whose only loader is unnamed
41
41
  * exposes that loader's data here directly.
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,18 @@
1
1
  import { Component } from 'vue';
2
+ import { ResolvedRoute } from '../types/resolved';
3
+ import { CreatedRouteOptions } from '../types/route';
4
+ import { RouteView } from '../types/routeViews';
2
5
  type ComponentWithAsyncLoader = Component & {
3
- __asyncLoader: () => void;
6
+ __asyncLoader: () => Promise<unknown>;
4
7
  };
5
8
  export declare function isAsyncComponent(component: Component): component is ComponentWithAsyncLoader;
9
+ /**
10
+ * Decides which of a route's views to load.
11
+ */
12
+ export type AsyncComponentFilter = (match: CreatedRouteOptions, view: RouteView<unknown>) => boolean;
13
+ /**
14
+ * Loads the async components a route renders, or only those the filter keeps, so they are ready to render
15
+ * synchronously.
16
+ */
17
+ export declare function loadAsyncComponents(route: ResolvedRoute, filter?: AsyncComponentFilter): Promise<unknown>;
6
18
  export {};
@@ -1,2 +1 @@
1
- import { ResolvedRoute } from '../types/resolved';
2
- export declare function setDocumentTitle(to: ResolvedRoute | null): void;
1
+ export declare function setDocumentTitle(title: string | undefined): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kitbag/router",
3
3
  "private": false,
4
- "version": "0.25.0",
4
+ "version": "0.26.1",
5
5
  "license": "MIT",
6
6
  "bugs": {
7
7
  "url": "https://github.com/kitbagjs/router/issues"
@@ -45,31 +45,26 @@
45
45
  "devDependencies": {
46
46
  "@kitbag/eslint-config": "1.0.6",
47
47
  "@vitejs/plugin-vue": "^6.0.8",
48
- "@vue/language-core": "^3.3.9",
49
- "@vue/test-utils": "^2.4.11",
48
+ "@vue/language-core": "^3.3.11",
49
+ "@vue/test-utils": "^2.5.0",
50
+ "arktype": "^2.2.3",
50
51
  "eslint": "^9.39.5",
51
- "globals": "^17.9.0",
52
- "happy-dom": "^20.11.2",
52
+ "globals": "^17.12.0",
53
+ "happy-dom": "^20.14.3",
53
54
  "typedoc": "^0.28.20",
54
- "typedoc-plugin-markdown": "^4.12.0",
55
- "typedoc-vitepress-theme": "^1.1.3",
55
+ "typedoc-plugin-markdown": "^4.13.0",
56
+ "typedoc-vitepress-theme": "^1.1.4",
56
57
  "typescript": "^6.0.3",
57
58
  "valibot": "^1.0.0",
58
59
  "vite": "^8.2.0",
59
60
  "vite-plugin-dts": "^5.0.3",
60
61
  "vitepress": "^1.6.4",
61
- "vitest": "^4.1.10",
62
+ "vitest": "^5.0.0",
62
63
  "vue-tsc": "^3.3.8",
63
64
  "zod": "4.0.0"
64
65
  },
65
66
  "peerDependencies": {
66
- "vue": "^3.5.0",
67
- "zod": "4.0.0"
68
- },
69
- "peerDependenciesMeta": {
70
- "zod": {
71
- "optional": true
72
- }
67
+ "vue": "^3.5.0"
73
68
  },
74
69
  "dependencies": {
75
70
  "@standard-schema/spec": "^1.0.0",
@@ -1,7 +0,0 @@
1
- import { Param, ParamGetSet } from '../types/paramTypes';
2
- import { StandardSchemaV1 } from '@standard-schema/spec';
3
- export interface ValibotSchemaLike extends StandardSchemaV1<any> {
4
- type: string;
5
- }
6
- export declare function isValibotParam(value: Param): value is ValibotSchemaLike;
7
- export declare function createValibotParam<T>(schema: ValibotSchemaLike): ParamGetSet<T>;
@@ -1,11 +0,0 @@
1
- import { ParamGetSet } from '../types/paramTypes';
2
- import { Routes } from '../types/route';
3
- import { StandardSchemaV1 } from '@standard-schema/spec';
4
- import { ZodType } from 'zod';
5
- export interface ZodSchemaLike extends StandardSchemaV1<any> {
6
- parse: (input: any) => any;
7
- }
8
- export declare function zodParamsDetected(routes: Routes): boolean;
9
- export declare function initZod(): Promise<void>;
10
- export declare function isZodParam(value: unknown): value is ZodType;
11
- export declare function createZodParam<T>(schema: ZodType<T>): ParamGetSet<T>;