How the Typed API Client Library Is Generated for Kaneo: OpenAPI to TypeScript Pipeline

Kaneo generates its typed API client library automatically from an OpenAPI specification using openapi-typescript, then wraps the generated types in a lightweight Hono client that provides compile-time type safety for all API operations.

The Kaneo project (usekaneo/kaneo) maintains a type-safe API client that React applications and external consumers import as @kaneo/libs. Rather than maintaining handwritten type definitions that drift out of sync with the backend, the typed API client library is generated directly from the OpenAPI specification, ensuring zero-runtime-overhead type safety across the entire stack.

The OpenAPI-to-TypeScript Generation Pipeline

OpenAPI Specification Source

The single source of truth for the API surface resides in apps/docs/openapi.json. This file is produced from Hono route definitions in apps/api/src/openapi.ts that use the @hono/zod-openapi library to attach Zod schemas to each route. Keeping the specification in a JSON file allows the codebase to treat it as a stable contract between the backend implementation and the client types.

TypeScript Declaration Generation

The packages/libs workspace automates type generation through a dedicated npm script. In packages/libs/package.json, the gen:libs script executes:

"scripts": {
  "gen:libs": "openapi-typescript apps/docs/openapi.json --output packages/libs/src/openapi.d.ts"
}

This command processes the canonical spec and outputs packages/libs/src/openapi.d.ts, a declaration file containing fully typed representations of every request payload, query parameter, and response shape. Because this file contains only type declarations, it adds zero bytes to the JavaScript bundle while providing full IntelliSense support in IDEs.

Hono Client Wrapper

The generated types are consumed by a minimal wrapper located in packages/libs/src/hono.ts. This module imports the paths type from the generated declarations and creates a client instance typed against the OpenAPI specification:

import { Hono } from "hono";
import type { paths } from "./openapi";

export const client = new Hono<paths>();
export const windowId = "kaneo-client";

The wrapper integrates with resolveApiBaseUrl from packages/libs/src/api-url.ts to handle runtime URL resolution while maintaining strict compile-time constraints on all request paths and payloads.

Key Files in the Generation Architecture

Using the Generated Typed Client

Consumers import the fully typed client from @kaneo/libs. The TypeScript compiler validates request parameters and response types against the OpenAPI specification at build time, catching mismatches before runtime.

Fetching Workspace Data

import { client } from "@kaneo/libs";

async function listWorkspaces() {
  const resp = await client.get("/workspace");
  const workspaces = await resp.json(); // Typed as Workspace[]
  return workspaces;
}

Creating Resources with Typed Payloads

import { client } from "@kaneo/libs";

async function createTask(projectId: string, title: string) {
  const resp = await client.post("/task/{projectId}", {
    json: { title },
    params: { projectId },
  });

  const task = await resp.json(); // Type: Task (from generated OpenAPI types)
  return task;
}

Configuring Custom API Endpoints

import { resolveApiBaseUrl, client } from "@kaneo/libs";

const apiUrl = resolveApiBaseUrl({ apiUrl: "https://api.my-kaneo.com" });
client.baseURL = apiUrl;

Build Automation and Type Synchronization

The generation process integrates with the workspace build system to prevent type drift. Running pnpm build in the libs workspace triggers npm run gen:libs first, guaranteeing that packages/libs/src/openapi.d.ts always reflects the current API surface defined in apps/docs/openapi.json.

This automation ensures that any modification to the Hono routes in apps/api/src/openapi.ts cascades through to the TypeScript declarations before the library compiles. Developers never need to manually update client types when adding new endpoints or changing request schemas.

Summary

  • Single Source of Truth: The OpenAPI specification in apps/docs/openapi.json drives all client types.
  • Automatic Generation: The openapi-typescript tool produces packages/libs/src/openapi.d.ts via the gen:libs npm script.
  • Type-Safe Wrapper: packages/libs/src/hono.ts wraps generated types in a Hono client instance with runtime URL resolution via resolveApiBaseUrl.
  • Zero Runtime Overhead: Generated files contain only TypeScript declarations; network logic remains in the lightweight Hono wrapper.
  • Build Integration: The pnpm build command regenerates types automatically, ensuring synchronization between API implementation and client library.

Frequently Asked Questions

How does Kaneo keep the API client types synchronized with the backend?

Kaneo uses a build-time generation pipeline. The gen:libs script in packages/libs/package.json runs openapi-typescript against apps/docs/openapi.json before compilation. This ensures the TypeScript declarations in packages/libs/src/openapi.d.ts always match the current Hono route definitions in apps/api/src/openapi.ts, eliminating manual type maintenance.

Can I use the Kaneo typed client in a non-React project?

Yes. The @kaneo/libs package exports framework-agnostic utilities including the typed client instance, resolveApiBaseUrl for URL configuration, and windowId constants. Any TypeScript project can import these to make type-safe API calls using the Hono client pattern without React dependencies.

What tool generates the TypeScript definitions from OpenAPI?

The project uses openapi-typescript, an open-source CLI tool that converts OpenAPI 3.x specifications into TypeScript declaration files. Kaneo invokes this tool via the gen:libs script, outputting to packages/libs/src/openapi.d.ts to provide compile-time type checking for all API operations defined in the spec.

Where is the API base URL configured in the typed client?

URL resolution logic lives in packages/libs/src/api-url.ts. The resolveApiBaseUrl function determines the appropriate API endpoint from environment variables or explicit configuration objects. The Hono client in packages/libs/src/hono.ts consumes this resolver to set client.baseURL while maintaining full type safety for all routes defined in the generated paths interface.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →