API reference

actions

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

@kitr/actions

Re-exports @tanstack/start-client-core unchanged, plus the following.

defineMutation

function defineMutation<S extends StandardSchemaV1 | undefined = undefined, TOutput = unknown, const M extends ReadonlyArray<unknown> = [
], TContext = MiddlewareContext<M>>(name: string, options: DefineMutationOptions<S, TOutput, TContext, M>): ServerMutation<InputOf<S>, TOutput, TContext>;

Define a mutation whose handler runs on the server, with the cache effects it has on success.

export const updateProject = defineMutation('projects.update', {
  input: z.object({ id: z.string(), name: z.string().min(2) }),
  effects: (project) => ({ set: [{ key: projectKeys.detail(project.id), data: project }], invalidate: [projectKeys.lists()] }),
  handler: ({ input }) => db.projects.update(input),
})

defineQuery

function defineQuery<S extends StandardSchemaV1 | undefined = undefined, TOutput = unknown, const M extends ReadonlyArray<unknown> = [
], TContext = MiddlewareContext<M>>(name: string, options: DefineQueryOptions<S, TOutput, TContext, M>): ServerQuery<InputOf<S>, TOutput, TContext>;

Define a query whose handler runs on the server. The name is the registry key kitr types writes to .kitr/actions.ts, so useQuery('projects.list', input) works with these types.

export const listProjects = defineQuery('projects.list', {
  input: z.object({ status: z.enum(['open', 'closed']).optional() }),
  handler: ({ input }) => db.projects.findMany({ where: input }),
})

requireSession

const requireSession: import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, undefined, undefined, undefined>;

Shortcut: a function middleware that rejects anonymous callers. Expects context.session from an earlier middleware.

CallOptions

interface CallOptions<TContext = unknown> {
  signal?: AbortSignal;
  /** `.run()` only: the middleware context the handler would see. */
  context?: Partial<TContext>;
}

Options for a direct call or .run().

DefineMutationOptions

interface DefineMutationOptions<S extends StandardSchemaV1 | undefined, TOutput, TContext, M extends ReadonlyArray<unknown> = ReadonlyArray<unknown>> extends DefineOperationOptions<S, TOutput, TContext, M> {
  /** Cache effects applied on the client after success. A function gets the result and the input. */
  effects?: CacheEffect | ((result: TOutput, input: InputOf<S>) => CacheEffect);
}

The second argument of defineMutation: the shared options plus cache effects.

DefineOperationOptions

interface DefineOperationOptions<S extends StandardSchemaV1 | undefined, TOutput, TContext, M extends ReadonlyArray<unknown> = ReadonlyArray<unknown>> {
  /** Any Standard Schema. Validated on the server; a failure reaches the caller as a VALIDATION error with field errors. */
  input?: S;
  /**
   * TanStack Start function middleware (`createMiddleware({ type: 'function' })`). What each one
   * passes to `next({ context })` is typed on the handler's `context`. An error thrown here reaches
   * the caller the same way a handler error does, masked in production when it is a server error.
   */
  middleware?: M;
  /** Runs on the server only. Its code, and anything it imports, never reaches the browser bundle. */
  handler: (ctx: HandlerContext<InputOf<S>, TContext>) => TOutput | Promise<TOutput>;
}

Options shared by defineQuery and defineMutation.

DefineQueryOptions

interface DefineQueryOptions<S extends StandardSchemaV1 | undefined, TOutput, TContext, M extends ReadonlyArray<unknown> = ReadonlyArray<unknown>> extends DefineOperationOptions<S, TOutput, TContext, M> {
  /** How long a result counts as fresh, in milliseconds. Carried into the query options. */
  staleTime?: number;
}

The second argument of defineQuery: the shared options plus staleTime.

HandlerContext

interface HandlerContext<TInput, TContext> {
  input: TInput;
  /** Context from Start middleware (request, session...). */
  context: TContext;
  signal: AbortSignal;
}

What a handler receives: the validated input, Start middleware context, and the request's abort signal.

ServerMutation

interface ServerMutation<TInput, TOutput, TContext = unknown> extends MutationDefinition<TInput, TOutput> {
  (input: TInput, options?: {
    signal?: AbortSignal;
  }): Promise<TOutput>;
  readonly name: string;
  /** Validation and the handler in-process, for tests. Skips Start middleware. */
  run(input: TInput, options?: CallOptions<TContext>): Promise<TOutput>;
  readonly serverFn: ServerFn<TOutput>;
}

A server mutation: a MutationDefinition from @kitr/query that is also a function. Call it to mutate, pass it to useMutation for pending state and cache effects, or use it by name.

ServerQuery

interface ServerQuery<TInput, TOutput, TContext = unknown> extends QueryDefinition<TInput, TOutput> {
  (input: TInput, options?: {
    signal?: AbortSignal;
  }): Promise<TOutput>;
  readonly name: string;
  /** Validation and the handler in-process, for tests. Skips Start middleware. */
  run(input: TInput, options?: CallOptions<TContext>): Promise<TOutput>;
  readonly serverFn: ServerFn<TOutput>;
}

A server query: a QueryDefinition from @kitr/query that is also a function. Call it to fetch, pass .options(input) to any TanStack hook or loader, or use it by name once kitr types has registered it.

MiddlewareContext

type MiddlewareContext<M extends ReadonlyArray<unknown>> = [
  M[number]
] extends [
  never
] ? {} : UnionToIntersection<ServerContextOf<M[number]>> & {};

The context a list of Start function middleware gives the handler: every middleware's next({ context }), merged.

ServerFn

type ServerFn<TOutput> = (opts: {
  data: unknown;
  signal?: AbortSignal;
}) => Promise<Envelope<TOutput>>;

The raw TanStack server function behind a definition, for useServerFn or middleware composition.

@kitr/actions/types

renderActions

function renderActions(found: FoundOperation[], ctx: Pick<GenerateContext, 'importPath'>): string;

The generated module for a set of operations. Exported for tests and for kitr doctor.

scanActions

function scanActions(sources: Array<{
  file: string;
  source: string;
}>, options?: ScanOptions): Promise<FoundOperation[]>;

Every exported defineQuery / defineMutation call in the given sources, found with the TypeScript compiler: the callee is resolved to its declaration, so an import alias (import { defineQuery as query }), a namespace import (k.defineQuery) and a re-export (export { listProjects } from '../shared/projects') all count, and a local function that merely shares the name does not. A name that is not a string literal is an error with file:line.

FoundOperation

interface FoundOperation {
  /** Project-relative file. */
  file: string;
  /** The exported identifier. */
  exportName: string;
  /** The dotted name passed to `defineQuery` or `defineMutation`. */
  name: string;
  kind: 'query' | 'mutation';
}

The actions generator for kitr types. It reads every file under app/actions (directories.actions), finds the exported defineQuery and defineMutation calls and writes .kitr/actions.ts: the operations map app/app.ts passes to createApp, the same names as a nested actions tree, and the Operations augmentation that types useQuery('projects.list').

ScanOptions

interface ScanOptions {
  /** The project root: where `tsconfig.json` is read from and module specifiers resolve. Default `/`. */
  root?: string;
  /** In-memory files by project-relative path (modules the actions import), seen before the file system. For tests. */
  files?: Record<string, string>;
}