API Reference

new Kizuna()

The authoring surface for one API, typed by the Config that kizuna generate writes.

new Kizuna<Config>() is what you declare routes with. It takes nothing at runtime: its type parameter is the Config generated from your kizuna.config.ts, and that is what types everything a handler receives and checks every name you write.

Keep the instance as k, usually in src/k.ts, and import it wherever you declare.

pnpm add kizunajs@beta
bun add kizunajs@beta
npm install kizunajs@beta
src/k.ts
import { Kizuna } from 'kizunajs';
import type { Config } from '../kizuna.types';

export const k = new Kizuna<Config>();

What it gives you

MemberSignatureDescription
k.route(definition) => RouteBuilderDeclare one route and the handler that answers it.
k.routes(tag, defs) => RoutesGroup routes under one of the tag set's keys.
k.tags(tags) => TagSetDeclare the OpenAPI tags routes are grouped under.
k.identity.bearer, .apiKey, .basic, .oauth2, .openIdConnect, .customDeclare an identity and the guard that authenticates it.
k.requestContext(config) => RequestContextBuilderDeclare a request-scoped value and the handler that fills it.
k.job(definition) => JobBuilderDeclare one job and the handler that runs it.
k.jobs(identity, definitions) => JobsGroup jobs and name the identity they require.
k.issue(ctx, issue) => voidRaise a typed validation code inside a Zod refinement.

Statics

Some declarations are shared across APIs rather than bound to one, so they stay on the class:

MemberDescription
Kizuna.modelName a schema so every client reuses one type.
Kizuna.permissionsDeclare a permission catalog.
Kizuna.rolesDeclare the roles callers hold.

What Config carries

kizuna.types.ts is written by kizuna generate from your config. Every name you write against k is checked against it, and everything a handler receives comes from it.

kizuna.types.ts
export interface Config {
    adapter: ReturnType<typeof expressAdapter>;
    tags: typeof tags;
    auth: {
        identities: {
            user: typeof user;
            member: typeof member;
        };
    };
    requestContext: {
        analytics: typeof analytics;
    };
    validation: {
        issueCodes: 'invalid_phone_number';
    };
    jobs: typeof jobs;
}

So a route's auth only accepts a declared identity, k.routes('users', ...) only accepts a declared tag, and a handler reads auth.user, requestContext.analytics, jobs.indexUser and your framework's own request without importing any of them.

Example

src/routes/users.ts
import { z } from 'zod';
import { k } from '../k';

export const usersRoutes = k.routes('users', {
    getUser: k
        .route({
            method: 'GET',
            path: '/users/:id',
            auth: 'user',
            responses: {
                200: UserSchema,
            },
        })
        .handler(async ({ params, auth, req }) => ({
            status: 200,
            body: await db.users.find(params.id, auth.user.userId),
        })),
});

Assemble them with defineConfig. See the Config guide for response schemas, deprecation, typed response headers, and nesting.

On this page