@lyku/lockstep-core
v1.8.3
Published
Schema-driven code generation: PostgreSQL models → TypeScript types, Kysely types, API handlers, and typed clients
Maintainers
Readme
@lyku/lockstep-core
Schema-driven code generation for TypeScript. Define your database tables and API endpoints once, generate everything else: TypeScript types, Kysely types, runtime validators, and more.
The lockstep ecosystem
This package (lockstep-core) provides the schema type system, the first three generators, runtime validators, and BON serialization. Handler and client generation live in separate packages.
Installation
npm install @lyku/lockstep-coreDefining schemas
Database tables
import type { PostgresRecordModel } from '@lyku/lockstep-core';
export const users = {
properties: {
id: { type: 'bigserial' },
username: { type: 'varchar', maxLength: 32 },
created: { type: 'timestamptz', default: { sql: 'CURRENT_TIMESTAMP' } },
email: { type: 'text' },
banned: { type: 'boolean' },
},
required: ['id', 'username', 'created', 'email'],
} as const satisfies PostgresRecordModel;Supported column types: bigint, bigserial, serial, integer, smallint, real, double precision, numeric, money, boolean, text, varchar, char, date, timestamp, timestamptz, time, jsonb, bytea, point, enum, array.
API endpoints
import type { TsonHandlerModel } from '@lyku/lockstep-core';
export const getUser = {
request: { type: 'bigint' },
response: {
type: 'object',
properties: {
id: { type: 'bigint' },
username: { type: 'string' },
},
required: ['id', 'username'],
},
authenticated: true,
throws: [400, 401, 404],
} as const satisfies TsonHandlerModel;Two handler types:
TsonHttpHandlerModel— standard request/response HTTP endpointsTsonStreamHandlerModel— WebSocket endpoints withstream: trueand optionaltweakRequest/tweakResponseschemas
Schema types
The type system used by API models:
| Schema | TypeScript | Notes |
| ------------------------------------------------------ | ------------------- | ------------------------------------------------------- |
| { type: 'string' } | string | Optional: maxLength, minLength, pattern, format |
| { type: 'number' } | number | Optional: min, max |
| { type: 'integer' } | number | Validated as integer |
| { type: 'bigint' } | bigint | |
| { type: 'boolean' } | boolean | |
| { type: 'date' } | Date | ISO 8601 strings |
| { type: 'enum', values: [...] } | 'a' \| 'b' | Union of literals |
| { type: 'array', items: ... } | T[] | Optional: minItems, maxItems |
| { type: 'object', properties: ..., required: [...] } | { ... } | Properties not in required are optional |
| { oneOf: [...] } | A \| B | Union type |
| { allOf: [...] } | A & B | Intersection type |
| { type: 'map', values: ... } | Record<string, T> | Dynamic keys |
String formats: email, uuid, uri, ipv4, ipv6, hostname, date-time.
Generators
generateJsonModels
Converts PostgreSQL column schemas to JSON schemas and TypeScript types.
lockstep generate json-models --models ./my-tables --output ./generated/json-modelsProduces two type variants per table:
- Full type (all fields, optionals included)
- Insertable type (only required fields, auto-generated columns excluded)
generateDbTypes
Generates a Kysely Database interface from PostgreSQL table definitions.
lockstep generate db-types --models ./my-tables --output ./generated/db-types --file kysely.d.tsOutput:
export type Users = {
id: Generated<bigint>;
username: string;
created: Date;
};
export interface Database {
users: Users;
// ...
}generateApiTypes
Generates TypeScript request/response types from API models.
lockstep generate api-types --models ./my-endpoints --output ./generated/api-typesOutput:
export type GetUserRequest = bigint;
export type GetUserResponse = { id: bigint; username: string };
export type ApiTypes = {
getUser: {
request: GetUserRequest;
response: GetUserResponse;
};
// ...
};Handler contexts
Handlers receive a typed context object based on auth requirements:
// @lyku/lockstep-core/contexts
// HTTP handlers
SecureHttpContext<Model>; // authenticated: true
MaybeSecureHttpContext<Model>; // authenticated: false
// WebSocket handlers
SecureSocketContext<Model>; // authenticated: true, streaming
MaybeSecureSocketContext<Model>; // authenticated: false, streamingContext fields:
| Field | Available in | Description |
| ----------------- | ------------ | --------------------------------- |
| requester | Secure only | User ID (bigint) |
| session | Secure only | Session token |
| request | HTTP | Raw Request object |
| responseHeaders | HTTP | Mutable Headers for response |
| emit | Socket | Send data to client |
| onClose | Socket | Register disconnect handler |
| onTweak | Socket | Handle mid-stream request changes |
| strings | All | Localized strings |
| model | All | The endpoint's schema definition |
| now | All | Request timestamp |
Runtime validation
Build validators from any schema:
import { buildValidator } from '@lyku/lockstep-core';
const validator = buildValidator('input', { type: 'string', minLength: 1 });
validator.validate(input); // returns string[] of errors
validator.validateOrThrow(input); // throws on invalid
validator.isValid(input); // returns true or first error stringValidators check types, required fields, string lengths/patterns/formats, numeric ranges, enum membership, and array constraints.
BON serialization
BON (Binary Object Notation) is a JSON-compatible format with BigInt support, used internally for embedding schemas in generated code.
import { stringifyBON, parseBON } from '@lyku/lockstep-core';
stringifyBON({ id: 123n, name: 'test' });
// → '{"id":123n,"name":"test"}'
parseBON('{"id":123n}');
// → { id: 123n }Security limits: max nesting depth 10,000; max string 100MB; blocks __proto__/constructor/prototype keys.
Documentation fields
API models support rich documentation metadata:
{
title: 'Get User',
description: 'Fetch a user by ID.',
category: 'Users',
tags: ['users'],
since: '1.0.0',
examples: [{ title: 'Basic', request: 456n, response: { id: 456n, username: 'alice' } }],
notes: ['Returns 404 if user does not exist'],
errors: [{ code: 404, title: 'Not Found', description: '...' }],
relatedEndpoints: ['updateUser', 'deleteUser'],
rateLimit: { requests: 100, period: '1 minute', scope: 'user' },
deprecated: { since: '2.0.0', useInstead: 'getUserV2', reason: '...' },
requiredPermissions: ['users:read'],
}Exports
@lyku/lockstep-core # Schema types, BON, type converters, validators
@lyku/lockstep-core/contexts # Handler context types
@lyku/lockstep-core/generators # Code generators (json-models, db-types, api-types)Related packages
| Package | Purpose |
| --------------------------- | ------------------------------------------------ |
| @lyku/lockstep-handles-ts | Generate typed handler factories from API models |
| @lyku/lockstep-client-ts | Generate typed HTTP clients from API models |
| @lyku/lockstep-pg | PostgreSQL drift detection and migrations |
License
GPL-3.0
