Skip to Content
API Reference

API Reference

Core

initSegment

Creates the Next.js route handlers of an Optional Catch-all Segment  route.

It takes:

  • segmentName?: string – the segment name, as used in the route. Defaults to an empty string (the root segment).
  • controllers: Record<string, Function> – the controllers, keyed by RPC module name.
  • exposeValidation?: boolean – false leaves the validation schemas out of the emitted schema, so the client code doesn’t see them. The declared content types stay, since the clients encode the body by them. Defaults to true.
  • emitSchema?: boolean – false emits no schema for the segment. Defaults to true.
  • onError?: (err: Error, req: VovkRequest) => void | Promise<void> – called when a controller throws, for example to log the error. The second argument is the request, with its URL, authorization data and other details.
  • onBefore?: (req: VovkRequest) => void | Promise<void> – called with the request after the route’s before and before the custom decorators and the handler run. An error it throws becomes the response.
  • onSuccess?: (result: unknown, req: VovkRequest) => void | Promise<void> – called with the handler’s result and the request once the handler returns. For a stream, that is when the stream starts, not when it ends.

JSONLinesResponder

JSONLinesResponder creates a response in the JSON Lines format. Its methods send JSON objects, one per line, to the response stream.

const responder = new JSONLinesResponder<IterationType>(req, ({ readableStream, headers }) => new Response(readableStream, { headers })); await responder.send({ message: 'Hello' }); await responder.send({ message: 'World' });

It takes:

  • req?: Request – the incoming request.
  • getResponse?: (responder: JSONLinesResponder<T>) => Response – an optional function that creates a custom Response.

Methods and properties:

  • send(item: T): Promise<void> – sends one JSON object as a line of the stream.
  • close(): Promise<void> – closes the stream: nothing more is sent.
  • throw(err: Error): Promise<void> – sends an error to the client and closes the stream.
  • response: Response – the Response that the Next.js route handler returns.
  • headers: Record<string, string> – the content-type header of the response.
  • readableStream: ReadableStream<Uint8Array> – the stream used as the response body.

See the JSON Lines page.

toDownloadResponse

Creates a Response with file or binary content and the matching headers, such as Content-Type and Content-Disposition. Return it from a controller. MCP tool output formatting accepts such a Response too.

Arguments:

  • content: Blob | File | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | string — the file content.
  • opts?:
    • filename?: string — sets Content-Disposition: attachment; filename=....
    • type?: string — overrides the Content-Type of the response, such as audio/mpeg, text/csv or application/pdf.
    • headers?: Record<string, string> — more headers for the response.

Serving an audio file:

import { get, toDownloadResponse } from 'vovk'; export default class MediaController { @get('audio') static getAudio() { return toDownloadResponse(buffer, { filename: 'track.mp3', type: 'audio/mpeg', headers: { 'x-hello': 'world' }, }); } }

Decorators

@get, @post, @put, @patch, @del, @head, @options

These decorators set the HTTP method of a handler. A HEAD request to a path without a @head route gets the response of the GET route: its status and headers, without the body. A request to a path that has routes only for other methods gets 405 and an Allow header that lists those methods. The decorators take two optional arguments:

  • path? = '' – the path of the route.
  • opts?: { cors?: boolean, headers?: Record<string, string>, staticParams?: Record<string, string>[], before?: (req: VovkRequest) => unknown } – route options:
    • cors: true adds CORS headers to the response and answers the OPTIONS preflight. The preflight allows and lists only the methods whose route on that path has cors, so a browser can’t call a route without it from another origin. The preflight skips the decorator’s before and the segment’s onBefore hooks.
    • headers are added to the response.
    • staticParams (@get only) is an array of path parameter values, for example [{ id: '123' }].
    • before runs on an HTTP request before the segment’s onBefore, the custom decorators and the handler, with the controller as this. An error it throws becomes the response.
import { get, type VovkRequest } from 'vovk'; export default class HelloController { @get('world/{id}', { cors: true, headers: { 'x-hello': 'world' }, staticParams: [{ id: '123' }] }) static getHelloWorld(req: VovkRequest, { id }: { id: string }) { return { hello: 'world', id }; } }

Each HTTP method decorator has an .auto() form. It builds the path from the method name in kebab case and adds a {name} segment for each property of the procedure’s params schema, so getHelloWorld below is served at get-hello-world/{id}. It takes the same options as the decorator.

import { get, procedure } from 'vovk'; import { z } from 'zod'; export default class HelloController { @get.auto({ cors: true, headers: { 'x-hello': 'world' }, staticParams: [{ id: '123' }] }) static getHelloWorld = procedure({ params: z.object({ id: z.string() }), }).handle((req, { id }) => { return { hello: 'world', id }; }); }

@prefix

@prefix(p: string) adds a path in front of every endpoint of a controller. It’s optional.

import { prefix, get } from 'vovk'; @prefix('hello') export default class HelloController { @get('world') static getHelloWorld() { return { hello: 'world' }; } }

@operation

@operation(openAPIOperationObject) adds OpenAPI documentation to a procedure. It takes an object with summary, description and any other property of the OpenAPI Operation Object.

@operation.tool() adds AI tool data under the x-tool key of the operation object (see Deriving AI Tools), and @operation.error(status, message) documents an error response.

import { get, operation } from 'vovk'; export default class HelloController { @operation.tool({ title: 'Get Hello World', }) @operation({ summary: 'Get Hello World', description: 'Returns a hello world message', }) @get('world') static getHelloWorld() { return { hello: 'world' }; } }

@cloneControllerMetadata

A controller can be in several segments, and each segment runs its own hooks. If the composed client includes those segments, give the controller a different key in each: the client exports one module per name. To serve the same handlers under another prefix, or together with new handlers, extend the controller and apply @cloneControllerMetadata to the new class. It copies all metadata (routes, operations and so on) from the parent controller. The new class keeps the parent’s prefix unless it sets its own, as @prefix('v2') does below.

import { prefix, cloneControllerMetadata } from 'vovk'; import UserController from './user-controller'; @cloneControllerMetadata() @prefix('v2') export default class UserControllerV2 extends UserController {}

Utils

createDecorator

createDecorator creates procedure decorators. Its first argument is a middleware function with these parameters:

  • req: VovkRequest – the request.
  • next: () => Promise<any> – calls the next middleware or the handler.
  • Other arguments – the values passed to the decorator.

The optional second argument changes the procedure schema based on the decorator arguments.

import { createDecorator, get } from 'vovk'; const myDecorator = createDecorator( (req, next, a: string, b: number) => { // do something with the request return next(); }, (a: string, b: number) => { // change the schema here } ); export default class MyController { @get.auto() @myDecorator('foo', 1) // passes 'foo' as a, and 1 as b static doSomething() { // ... } }

See the decorator docs.

fetcher

The default fetcher: the function the RPC client sends its requests with, unless you customize it. createFetcher creates a new one. Exported from vovk/fetcher.

createFetcher

Creates a custom fetcher for the RPC client. Its type parameter defines extra options for the RPC methods. It returns the fetcher function that the client is built with.

./src/lib/fetcher.ts
import { createFetcher } from 'vovk/fetcher'; export const fetcher = createFetcher<{ successMessage?: string; // "Successfully created a new user" useAuth?: boolean; // if true, sets the Authorization header someOtherCustomFlag?: boolean; // any other flag you pass to the RPC method }>({ prepareRequestInit: async (init, { useAuth, someOtherCustomFlag }) => { // ... return { ...init, headers: { ...init.headers, ...(useAuth ? { Authorization: 'Bearer token' } : {}), }, }; }, transformResponse: async (data, { someOtherCustomFlag }) => { // ... return data; }, onSuccess: async (data, { successMessage }) => { if (successMessage) { alert(successMessage); } }, onError: async (error) => { alert(error.message); }, });

See the fetcher docs.

controllersToStaticParams

Lists the routes as static params, so the API is built at build time instead of on each request. Use it in the Next.js generateStaticParams() of [[...slug]]/route.ts.

Arguments:

  • controllers: Record<string, Function> — the controllers. It lists the path of every handler, whatever its HTTP method: the controller prefix and the handler path. A handler with staticParams gives one path per item, with the {name} placeholders filled in; other paths keep their placeholders.
  • slugName = 'vovk' — (optional) the name of the Optional Catch‑all Segment param, the folder name in [[...<slugName>]]. Set it when the folder isn’t [[...vovk]].

Returns:

  • Array<Record<string, string[]>> — params objects for generateStaticParams(): one per path, such as { vovk: ['hello', 'greeting.json'] }. The list starts with { vovk: ['_schema_'] } for the schema endpoint when NODE_ENV is development, or when there is no other path, as output: 'export' needs one.
src/app/api/[[...vovk]]/route.ts
// ... export type Controllers = typeof controllers; export function generateStaticParams() { return controllersToStaticParams(controllers); } export const { GET } = initSegment({ controllers });

The segment needs no dynamic export: Next.js pre-renders the listed paths with cacheComponents on or off.

For another slug folder, such as src/app/api/[[...custom]]/route.ts, pass its name as the second argument:

export function generateStaticParams() { return controllersToStaticParams(controllers, 'custom'); }

See the segment page.

multitenant

A Next.js proxy  helper that routes subdomains to segments.

Returns:

  • action: 'rewrite' | 'redirect' | null — what the proxy should do.
  • destination: string | null — the URL to rewrite or redirect to.
  • message: string — what it decided and why, for debugging.
  • subdomains: Record<string, string> | null — the wildcard subdomains from the request host.
src/proxy.ts
// ... proxy ... const { action, destination, message, subdomains } = multitenant({ requestUrl: request.url, requestHost: request.headers.get('host') ?? '', targetHost: process.env.VERCEL ? 'multitenant.vovk.dev' : 'localhost:3000', overrides: { // ... }, }); console.log({ action, destination, message, subdomains }); // ...

See the multitenant guide.

deriveTools

Turns RPC modules or controllers into AI tools that follow the standard-tool  convention (the StandardToolV0 interface).

Options:

  • modules: Record<string, object> – module names mapped to objects with methods. Each method needs the schema property that RPC methods and procedures have, and either isRPC: true (RPC modules) or the fn function (controllers).
  • onExecute?: (result: unknown, tool: StandardToolV0, req: Pick<VovkRequest, 'vovk'> | null) => void – called after each successful tool call. For a controller, req is the request of the call, with req.vovk; for an RPC method, it’s null.
  • onError?: (e: Error, tool: StandardToolV0, req: Pick<VovkRequest, 'vovk'> | null) => void – called when a tool call throws, or when a controller returns a Response with an error status. req is as in onExecute, or null for a thrown error.
  • toModelOutput – formats the tool result for the model. A formatter that returns an Error for a failed call makes the tool throw it.
  • meta?: Record<string, any> – data passed to each call of a controller handler or RPC method; see req.vovk.meta().
import { deriveTools } from 'vovk'; import { UserRPC } from '@/client'; import TaskController from '@/modules/task/task-controller'; const tools = deriveTools({ meta: { hello: 'world' }, modules: { UserRPC, TaskController, }, toModelOutput: (result) => `Result: ${JSON.stringify(result, null, 2)}`, onExecute: (result, { name }) => console.log(`${name} executed`, result), onError: (e) => console.error('Error', e), });

See the Deriving AI Tools guide.

ToModelOutput

Built-in toModelOutput formatters for deriveTools. They shape tool results for LLMs.

  • ToModelOutput.DEFAULT — the default, used when toModelOutput isn’t set.
  • ToModelOutput.MCP — formats the output in the MCP tool output shape: text, JSON, image or audio. See tools for details and examples.
  • ToModelOutput.RAW — the result as the procedure gives it; a failed call throws its error, after onError. See Using with uicast.

createValidateOnClient

Creates the validateOnClient function, which runs client-side validation for RPC methods, for all segments or per segment. It takes a validate function, which gets the input data, the validation schema and more options. validate returns the validated data, or throws an error when validation fails.

./src/lib/validate-on-client.ts
import { validateData } from 'validation-library'; import { createValidateOnClient, HttpException, HttpStatus } from 'vovk/create-validate-on-client'; export const validateOnClient = createValidateOnClient({ validate: async (input, schema, meta) => { const isValid = validateData(input, schema); if (!isValid) { throw new HttpException(HttpStatus.NULL, 'Validation failed'); } return input; }, });

For client-side validation, see the customization page.

procedure

Defines a procedure: a controller handler with validation and schema emission. procedure(options) returns .handle(), which takes the handler, (req, params) => ….

import { z } from 'zod'; import { procedure } from 'vovk'; export default class UserController { static createUser = procedure({ body: z.object({ name: z.string(), email: z.string().email(), }), output: z.object({ id: z.string(), name: z.string(), email: z.string().email(), }), }).handle((req) => { // ... }); }

Without .handle(), the procedure throws a Not Implemented error.

procedure options:

  • body, query, params — input validation schemas.
  • output — the output schema, for JSON responses.
  • iteration — the item schema, for JSON Lines responses.
  • contentType — the Content-Type (a string or an array of strings) the request body may have, for non-JSON bodies such as forms, text or files. See contentType.
  • disableServerSideValidation — turns off server-side validation: true for all parts, or an array of parts.
  • skipSchemaEmission — leaves JSON Schemas out of the emitted schema: true for all parts, or an array of parts.
  • validateEachIteration — validates every streamed item, not only the first one.
  • operationObject — OpenAPI operation details, for when you can’t use the @operation decorator.
  • preferTransformed — whether req.vovk.* and the response use the transformed values or the raw ones.
  • target — the JSON Schema version the validation library emits for the procedure’s schemas: 'draft-2020-12' by default, or another version the library supports, such as 'draft-07'.

A procedure also has:

  • .fn(...) — calls the procedure locally, without HTTP, with the same arguments as an RPC call.
  • .schema — the method schema, the same as the RPC method’s.
  • .definition — the options passed to procedure.

See the procedure guide.

progressive

Experimental. Makes one request and gets several responses, each as its own promise.

const { users: usersPromise, tasks: tasksPromise } = progressive(ProgressiveRPC.streamProgressiveResponse);

See Progressive Response.

HttpException

An error class that extends the built-in Error, with an HTTP status code and a message. Throw it from a procedure, and Vovk.ts answers with that status code and message.

import { HttpException, HttpStatus } from 'vovk'; throw new HttpException(HttpStatus.BAD_REQUEST, 'Invalid request', { some: 'cause' });

The optional third argument holds more data for logging or debugging. The client gets it as error.cause.

See responses.

Inference Types

VovkBody, VovkQuery, VovkParams

Infer the input types of RPC methods and procedures.

import type { VovkBody, VovkQuery, VovkParams } from 'vovk'; import { UserRPC } from '@/client'; type Body = VovkBody<typeof UserRPC.updateUser>; type Query = VovkQuery<typeof UserRPC.updateUser>; type Params = VovkParams<typeof UserRPC.updateUser>;

See inference.

VovkInput

Infers the params, query and body of a procedure as one object. Use it to type the arguments of a Next.js server action.

import type { VovkInput } from 'vovk'; import type UserController from './user-controller'; type Input = VovkInput<typeof UserController.createUser>; // { params: VovkParams<...>; query: VovkQuery<...>; body: VovkBody<...> }

See inference.

VovkOutput, VovkIteration

Output types of validated procedures:

  • VovkOutput<T> infers the JSON response type of a procedure({ output }).
  • VovkIteration<T> infers the JSON Lines item type of a procedure({ iteration }).
import type { VovkOutput, VovkIteration } from 'vovk'; import { UserRPC, StreamRPC } from '@/client'; type Output = VovkOutput<typeof UserRPC.updateUser>; type Iteration = VovkIteration<typeof StreamRPC.streamItems>;

See inference.

VovkReturnType, VovkYieldType

Infer the return and yield types of a method from its code, when it has no validation schemas.

import type { VovkReturnType, VovkYieldType } from 'vovk'; import { UserRPC, StreamRPC } from '@/client'; type Return = VovkReturnType<typeof UserRPC.updateUser>; type Yield = VovkYieldType<typeof StreamRPC.streamItems>;

See inference.

Other Types and Enums

VovkRequest

A copy of the Next.js NextRequest type, with stricter types for .json() and .nextUrl.searchParams, and a vovk property with input helpers.

VovkRequest doesn’t extend NextRequest, so the vovk package doesn’t depend on the next package.

See req.vovk.

HttpStatus enum

Status codes for throwing and catching server errors. NULL (0) is for an error without an HTTP response, such as a failed client-side validation.

export enum HttpStatus { NULL = 0, CONTINUE = 100, SWITCHING_PROTOCOLS = 101, PROCESSING = 102, EARLYHINTS = 103, OK = 200, CREATED = 201, ACCEPTED = 202, NON_AUTHORITATIVE_INFORMATION = 203, NO_CONTENT = 204, RESET_CONTENT = 205, PARTIAL_CONTENT = 206, AMBIGUOUS = 300, MOVED_PERMANENTLY = 301, FOUND = 302, SEE_OTHER = 303, NOT_MODIFIED = 304, TEMPORARY_REDIRECT = 307, PERMANENT_REDIRECT = 308, BAD_REQUEST = 400, UNAUTHORIZED = 401, PAYMENT_REQUIRED = 402, FORBIDDEN = 403, NOT_FOUND = 404, METHOD_NOT_ALLOWED = 405, NOT_ACCEPTABLE = 406, PROXY_AUTHENTICATION_REQUIRED = 407, REQUEST_TIMEOUT = 408, CONFLICT = 409, GONE = 410, LENGTH_REQUIRED = 411, PRECONDITION_FAILED = 412, PAYLOAD_TOO_LARGE = 413, URI_TOO_LONG = 414, UNSUPPORTED_MEDIA_TYPE = 415, REQUESTED_RANGE_NOT_SATISFIABLE = 416, EXPECTATION_FAILED = 417, I_AM_A_TEAPOT = 418, MISDIRECTED = 421, UNPROCESSABLE_ENTITY = 422, FAILED_DEPENDENCY = 424, PRECONDITION_REQUIRED = 428, TOO_MANY_REQUESTS = 429, INTERNAL_SERVER_ERROR = 500, NOT_IMPLEMENTED = 501, BAD_GATEWAY = 502, SERVICE_UNAVAILABLE = 503, GATEWAY_TIMEOUT = 504, HTTP_VERSION_NOT_SUPPORTED = 505, }

VovkSchema

The full schema of the composed client, or of one segment in a segmented client. It has segments, the schema of each segment by name, and an optional meta with the emitted config. To type the schema of one segment, use typeof UserRPC.updateUser.segmentSchema.

See the schema docs.

VovkConfig

The type of the config file.

VovkJSONSchemaBase

A JSON Schema object with type, properties and the other standard keywords.

VovkFetcher

The type of a fetcher, the function that sends the API requests. Exported from vovk/fetcher.

See the fetcher docs.

VovkStreamAsyncIterable

The stream a client method returns for a JSON Lines response: an async iterable of the items, with status, asPromise, onIterate, abortController and abortSilently. Generated clients use it in their method types, OpenAPI mixins included.

VovkValidateOnClient

The type of the client-side validation function that createValidateOnClient creates. Exported from vovk/create-validate-on-client.

See the client-side validation docs.

Last updated on