router

Turn files in app/routes into pages, with links, loaders and guards. Web, desktop and mobile apps get it automatically.

Pages & routingClientBuilt onTanStack Router

Every export of kitr/router, read from the published type definitions. The guide shows them in use.

kitr/router

Re-exports @tanstack/history, @tanstack/react-router, @tanstack/router-core unchanged, plus the following.

can

function can(permission: string, options?: {
  subject?: unknown;
  to?: string;
}): ({ context }: {
  context: {
    session?: GuardSession | null;
  };
}) => void;

beforeLoad permission guard. Throws a FORBIDDEN KitrError that the route's errorComponent renders, or redirects when to is given.

createKitrRouter

function createKitrRouter<TRouteTree extends AnyRoute>(options: CreateKitrRouterOptions<TRouteTree>): Router<TRouteTree, 'never', true>;

createRouter with kitr's defaults: queryClient and app in context, intent preload, scroll restoration, default pending/error/not-found components, and the app's providers wrapped around the whole tree.

With @kitr/query installed, loaders can context.queryClient.ensureQueryData(...).

DefaultError

function DefaultError({ error, reset }: ErrorComponentProps): import("react").JSX.Element;

DefaultNotFound

function DefaultNotFound(): import("react").JSX.Element;

DefaultPending

function DefaultPending(): import("react").JSX.Element;

Default route-level components. Generated routes reference these so every page has a loading, error and not-found state without anyone deciding each time. Override globally in createKitrRouter({ defaultPendingComponent }) or per route.

guards

function guards<Ctx>(...fns: Array<(ctx: Ctx) => unknown | Promise<unknown>>): (ctx: Ctx) => Promise<Record<string, unknown>>;

Compose several beforeLoad guards; each may return context to merge.

requireAuth

function requireAuth(options?: RequireAuthOptions): ({ context, location }: {
  context: {
    session?: GuardSession | null;
  };
  location: {
    href: string;
  };
}) => {
  session: GuardSession;
};

beforeLoad guard. Reads context.session (set by @kitr/auth or your own provider) and redirects anonymous users, remembering where they were going.

export const Route = createFileRoute('/_app')({ beforeLoad: requireAuth() })

CreateKitrRouterOptions

interface CreateKitrRouterOptions<TRouteTree extends AnyRoute> extends Omit<RouterOptions<TRouteTree, 'never', false, any, any>, 'context'> {
  app: KitrApp;
  /** Defaults to the container's `queryClient` (from @kitr/query). */
  queryClient?: QueryClient;
  /** Extra context merged into every route (e.g. `session`). */
  context?: Record<string, unknown>;
}

GuardSession

interface GuardSession {
  user?: unknown | null;
  can?: (permission: string, subject?: unknown) => boolean;
}

KitrRouterContext

interface KitrRouterContext {
  queryClient: QueryClient;
  app: KitrApp;
}

The router context every kitr route sees. Packages extend it by augmentation:

declare module '@kitr/router' { interface KitrRouterContext { session: Session | null } }

RequireAuthOptions

interface RequireAuthOptions {
  /** Where to send anonymous users. Default `/sign-in`. */
  to?: string;
  /** Name of the search param carrying the original URL. Default `redirect`. */
  redirectParam?: string | false;
}

RouterContextWith

type RouterContextWith<T> = KitrRouterContext & T;