Libraries
    Preparing search index...
    • Defines a typed API contract with one level of grouping.

      The returned object is the single source of truth for both server and client. The server imports it and extends each endpoint with .authorize(), .inject(), and OpenAPI metadata. The client passes it to createClient() from @cleverbrush/client to obtain a fully typed HTTP client.

      At runtime the contract (and each group within it) is frozen with Object.freeze to prevent accidental mutation — endpoint builders are immutable by design, so every .body() / .query() / etc. call already returns a new builder.

      Type Parameters

      • T extends ApiContract

        The exact shape of the contract, inferred from the argument.

      Parameters

      • contract: T

        A record of named groups, each containing named endpoints.

      Returns Readonly<T>

      The same object, frozen and typed as Readonly<T>.

      import { defineApi, endpoint, route } from '@cleverbrush/server/contract';
      import { array, number, object, string } from '@cleverbrush/schema';

      const TodoSchema = object({ id: number(), title: string(), completed: boolean() });
      const todosResource = endpoint.resource('/api/todos');
      const ById = route({ id: number().coerce() })`/${t => t.id}`;

      export const api = defineApi({
      todos: {
      list: todosResource.get()
      .query(object({ page: number().optional(), limit: number().optional() }))
      .responses({ 200: array(TodoSchema) }),
      get: todosResource.get(ById)
      .responses({ 200: TodoSchema }),
      create: todosResource.post()
      .body(object({ title: string() }))
      .responses({ 201: TodoSchema }),
      },
      auth: {
      login: endpoint.post('/api/auth/login')
      .body(object({ email: string(), password: string() }))
      .responses({ 200: object({ token: string() }) }),
      },
      });