Ecosystem

Katax Docs Hub

Katax

Katax Ecosystem

Three TypeScript packages to build, validate, and deploy Node.js APIs on VPS infrastructure with PM2.

katax-core 1.5.4 katax-service-manager 0.5.3 katax-cli 1.4.4

Installation

npm install katax-core
npm install katax-service-manager
npm install -g katax-cli

# optional peer deps for katax-service-manager
npm install pg mysql2 mongodb redis socket.io dotenv node-cron pino-pretty

katax-core

katax-core is the validation layer. The entry point is k. Supports 20+ schema types, coercion, preprocess, async validators, composition and error utilities.

Quick Start

import { k, type kataxInfer } from 'katax-core';

const UserSchema = k.object({
  email: k.email(),
  name: k.string().minLength(2).maxLength(100),
  age: k.number().min(18).optional(),
});

type User = kataxInfer<typeof UserSchema>;

const result = UserSchema.safeParse(req.body);
if (!result.success) return res.status(400).json({ errors: result.issues });

Core Types

type SafeParseResult<T> = 
  | { success: true; data: T }
  | { success: false; issues: Issue[] }

interface Issue {
  path: (string | number)[];
  message: string;
}

interface ValidationResult {
  valid: boolean;
  issues: Issue[];
}

Schema API

All schemas implement: parse(input): T · safeParse(input): SafeParseResult<T> · validate(input): ValidationResult · parseAsync(input): Promise<T> · safeParseAsync(input): Promise<AsyncSafeParseResult<T>> · isValidAsync(input): Promise<AsyncValidationResult> · hasAsyncValidation(): boolean · kataxInfer: T

All k factories

k.string()    k.number()    k.boolean()    k.date()     k.twoDates()
k.object()    k.array()     k.tuple()      k.record()
k.union()     k.intersection()            k.lazy()
k.email()     k.file()      k.base64()
k.custom()    k.literal()   k.enum()
k.any()       k.unknown()   k.never()
k.coerce      k.preprocess()

Modifiers (chainable, all schemas)

schema.optional()             // T | undefined
schema.nullable()             // T | null
schema.default(value)         // Returns default if undefined
schema.transform(fn)          // Transform output type
schema.catch(value)           // Return fallback on validation failure

String — k.string()

MethodDescription
minLength(n, msg?)Minimum length
maxLength(n, msg?)Maximum length
length(n, msg?)Exact length
email(msg?)Valid email format
url(msg?)Valid URL
uuid(msg?)Valid UUID (RFC 4122)
ip(msg?)Valid IPv4
regex(pattern, msg?)Regex match
startsWith(prefix, msg?)Must start with string
endsWith(suffix, msg?)Must end with string
includes(substr, msg?)Must include substring
oneOf(arr, msg?)Must be one of the options
notOneOf(arr, msg?)Must not be any of the options
lowercase(msg?)Lowercase only
uppercase(msg?)Uppercase only
alpha(msg?)Letters only [A-Za-z]
alphanumeric(msg?)Letters and numbers
ascii(msg?)ASCII characters only
noWhitespace(msg?)No spaces
nonempty(msg?)Cannot be empty
trim()No leading/trailing spaces (no msg param)

Number — k.number()

MethodDescription
min(value, msg?)Minimum value (>=)
max(value, msg?)Maximum value (<=)
length(exact, msg?)Exact value
positive(msg?)Must be > 0
negative(msg?)Must be < 0
integer(msg?)Must be integer
finite(msg?)Must be finite
multipleOf(factor, msg?)Multiple of
between(min, max, msg?)Inclusive range
greaterThan(n, msg?)Strictly greater than
lessThan(n, msg?)Strictly less than
notEqual(n, msg?)Not equal to value
oneOf(arr, msg?)Must be one option
notOneOf(arr, msg?)Must not be any option
nonempty(msg?)Alias for min(1)

Boolean — k.boolean()

MethodDescription
isTrue(msg?)Must be true
isFalse(msg?)Must be false
equals(val, msg?)Must equal the value

Object — k.object(shape)

By default, extra keys are stripped. Use passthrough() to keep them or strict() to reject them.

MethodDescription
extend(extension)Add or override fields
merge(other)Merge two object schemas
pick([keys])Select specific fields
omit([keys])Exclude specific fields
partial()All fields optional
strict()Reject extra keys
passthrough()Allow extra keys in output
strip()Remove extra keys (default)
getShape()Get raw shape object
caseInsensitive()Case-insensitive key matching
const schema = k.object({
  name: k.string().minLength(2),
  age: k.number().min(18).optional(),
}).strict();

Array — k.array(elementSchema?)

MethodDescription
minLength(n, msg?)Minimum length
maxLength(n, msg?)Maximum length
length(n, msg?)Exact length
notEmpty(msg?)Cannot be empty
unique(msg?)Unique elements (deep equality)
contains(element, msg?)Must contain element

Email — k.email()

RFC 5322 compliant validation.

MethodDescription
domain(domain, msg?)Restrict to specific domain
domains([domains], msg?)Multiple allowed domains
domainPattern(pattern, msg?)Domain regex pattern
notDomains([blacklist], msg?)Domain blacklist
localMinLength(n, msg?)Min local part length
localMaxLength(n, msg?)Max local part length
localPattern(regex, msg?)Local part pattern
corporate(msg?)Block free providers
noPlus(msg?)Forbid '+' addressing
noDots(msg?)Forbid '.' in local part

Date & TwoDates

k.date()

Input: ISO 8601. Output: Date object. Uses date-fns.

MethodDescription
min(dateStr, msg?)On or after the date
max(dateStr, msg?)On or before the date
between(start, end, msg?)Inclusive range
isFuture(msg?)Must be in the future
isPast(msg?)Must be in the past
format(formatStr, msg?)Must match format
isDateOnly(msg?)Date only (YYYY-MM-DD)
hasTime(msg?)Must include time
formatOutput(format)Output as formatted string

k.twoDates(separator?)

Input: Two ISO dates separated by separator (default '|'). Output: [Date, Date].

MethodDescription
maxDifference(days, msg?)Max days apart
minDifference(days, msg?)Min days apart
maxDifferenceHours(hours, msg?)Max hours apart
minDifferenceHours(hours, msg?)Min hours apart
order(ascending?, msg?)Chronological order (default asc)

File — k.file()

Compatible with Browser File API and Node.js Multer objects.

MethodDescription
maxSize(bytes, msg?)Maximum size
minSize(bytes, msg?)Minimum size
type(mimeType, msg?)Exact MIME type
types([mimeTypes], msg?)Multiple MIME types
typePattern(pattern, msg?)MIME pattern (image/*)
extension(ext, msg?)File extension
extensions([exts], msg?)Multiple extensions
namePattern(regex, msg?)Filename regex
image(msg?)Shortcut: image/*
video(msg?)Shortcut: video/*
audio(msg?)Shortcut: audio/*
document(msg?)Shortcut: PDF, Word, Excel, plaintext

Base64 — k.base64()

Validates base64-encoded strings, including data URLs.

MethodDescription
minDecodedSize(bytes, msg?)Min decoded size
maxDecodedSize(bytes, msg?)Max decoded size
mimeType(type, msg?)Exact data URL MIME type
mimeTypePattern(pattern, msg?)MIME pattern
image(msg?)Shortcut: image/*
pdf(msg?)Shortcut: application/pdf
json(msg?)Decoded must be valid JSON
dataUrl(msg?)Must be data URL

Union / Intersection / Lazy

// Union — at least one schema must match (short-circuit)
k.union([k.string(), k.number()])

// Intersection — ALL schemas must match (merge objects)
k.intersection([
  k.object({ id: k.number() }),
  k.object({ name: k.string() })
])

// Lazy — deferred resolution for recursive types
const categorySchema = k.lazy(() =>
  k.object({
    name: k.string(),
    subcategories: k.array(categorySchema)
  })
);

Literal / Enum / Tuple / Record / Any / Unknown / Never

k.literal('active')               // Exact value (===)
k.enum(['active', 'inactive'])    // String union
k.tuple([k.number(), k.string()]) // Fixed-length typed array
k.record(k.number())              // Record<string, number>
k.any()                           // Accepts everything
k.unknown()                       // Accepts everything (forces narrowing)
k.never()                         // Never matches

Custom — k.custom<T>(validator)

const positiveEven = k.custom<number>((value, path) => {
  if (typeof value !== 'number')
    return [{ path, message: 'Must be number' }];
  if (value <= 0 || value % 2 !== 0)
    return [{ path, message: 'Must be positive even' }];
  return value;
});

// Add refinement
positiveEven.refine((v) => v < 1000, 'Must be less than 1000');

Modifiers / Coercion / Preprocess

Coercion — k.coerce

Auto-converts types before validating:

k.coerce.number()   // "42" → 42, true → 1, false → 0
k.coerce.boolean()  // "true"/"1"/"yes" → true, "false"/"0"/"no" → false
k.coerce.string()   // 42 → "42", true → "true", null → ""
k.coerce.date()     // ISO string → Date, timestamp → Date

// Proxy validation methods available:
k.coerce.number().positive().integer()
k.coerce.boolean().isTrue()
k.coerce.string().minLength(3).email()
k.coerce.date().isFuture()

Preprocess — k.preprocess(fn, schema)

k.preprocess(
  (val) => typeof val === 'string' ? val.trim().toLowerCase() : val,
  k.string().email()
)

Error Utilities

import { createIssue, issues, mergeIssues, isIssueArray, KataxError } from 'katax-core';

createIssue(['field'], 'error message');   // Issue object
issues(['field'], 'error message');         // Issue[]
mergeIssues(arr1, arr2);                    // Merge issue arrays
isIssueArray(value);                        // Type guard

// KataxError is thrown by parse()/parseAsync()
throw new KataxError(result.issues);

Async Validation

const usernameSchema = k.string().minLength(3).asyncRefine(async (value, path) => {
  const exists = await usersRepo.existsByUsername(value);
  return exists ? [{ path, message: 'Already taken' }] : [];
});

const result = await usernameSchema.safeParseAsync(input);

// Also available:
await schema.parseAsync(input);      // Throws KataxError
await schema.isValidAsync(input);    // { valid, issues }

katax-service-manager

Singleton container that manages config, logger, databases, WebSocket, cron, cache, registry, health, and graceful shutdown.

Core

  • Katax class — katax singleton
  • new Katax() isolated instances
  • Katax.getInstance() / Katax.reset()

Services

  • ConfigService · LoggerService
  • DatabaseService · WebSocketService
  • CronService · CacheService
  • RegistryService · RedisStreamBridgeService

Errors

  • KataxServiceError (base)
  • KataxConfigError · KataxDatabaseError
  • KataxRedisError · KataxWebSocketError
  • KataxRegistryError · KataxNotInitializedError

Transports

  • RedisTransport · CallbackTransport
  • TelegramTransport

Helpers

  • registerVersionToRedis
  • startHeartbeat · registerProjectInRedis

Initialization, Environment & Lifecycle

Init

import { katax } from 'katax-service-manager';

await katax.init({
  loadEnv: true,
  appName: 'my-api',
  logger: { level: 'info', prettyPrint: true, enableBroadcast: false },
  hooks: {
    beforeInit: () => {},
    afterInit: () => {},
    beforeShutdown: () => {},
    afterShutdown: () => {},
    onError: (context, error) => {},
  },
  registry: { url: 'https://dashboard.example.com/api/services' },
});

Environment Helpers

katax.env('PORT', '3000');        // string with default
katax.env('PORT', 3000);          // number (auto-cast)
katax.env('DEBUG', false);        // boolean (auto-cast)
katax.envRequired('JWT_SECRET');  // throws if missing

katax.isDev    katax.isProd    katax.isTest
katax.nodeEnv  katax.appName   katax.version
katax.isInitialized

Overrides (testing)

import { Katax } from 'katax-service-manager';
beforeEach(() => Katax.reset());

katax.overrideService('db:main', mockDb);
katax.overrideService('logger', mockLogger);
katax.clearOverride('db:main');   // Remove specific
katax.clearOverride();            // Remove all

Shutdown & Hooks

katax.onShutdown(async () => {
  await cleanupCustomResource();
});

await katax.shutdown();
// Closes all services in order: hooks, DB, WS, cron, registry, bridges
// SIGTERM and SIGINT are handled automatically

Database Service

Supports PostgreSQL, MySQL, MongoDB, and Redis with typed connections and configurable pool.

Setup

// PostgreSQL / MySQL
const db = await katax.database({
  name: 'main', type: 'postgresql',
  connection: { host: 'localhost', port: 5432, database: 'myapp', user: 'admin', password: 'secret' },
  pool: { max: 10, min: 2 },
});

// MongoDB
const mongo = await katax.database({
  name: 'analytics', type: 'mongodb',
  connection: { host: 'localhost', port: 27017, database: 'analytics' },
});

// Redis
const redis = await katax.database({
  name: 'cache', type: 'redis',
  connection: { host: '127.0.0.1', port: 6379 },
});

Typed Access

const db = katax.db('main');

db.asSql()    // ISqlDatabase — query<T>(sql, params?), getClient(), close()
db.asMongo()  // IMongoDatabase — getClient(), close()
db.asRedis()  // IRedisDatabase — redis(...args), close()

// SQL query
const users = await db.asSql().query<User[]>('SELECT * FROM users WHERE id = $1', [userId]);

// Redis command
await db.asRedis().redis('SET', 'key', 'value', 'EX', '60');
await db.asRedis().redis('GET', 'key');

Cache Service

High-level Redis wrapper with automatic JSON serialization.

const cache = katax.cache('cache'); // Redis connection name
MethodDescription
get<T>(key)Get value (auto-deserializes JSON)
set(key, value, ttl?)Store with optional TTL (seconds)
del(key)Delete single key
delMany(keys[])Delete multiple keys
exists(key)Check if key exists
ttl(key)Remaining TTL
expire(key, seconds)Set expiration on existing key
incr(key)Increment by 1
incrBy(key, n)Increment by n
decr(key)Decrement by 1
mget<T>(keys[])Get multiple values
mset(entries[])Store multiple [key, value] pairs
clear(pattern?)Delete by pattern
stats()Redis INFO statistics
await cache.set('user:123', userData, 3600);
const user = await cache.get<User>('user:123');
await cache.del('user:123');
await cache.incr('page:views');
await cache.mset([['k1', v1], ['k2', v2]]);

Logger & Transports

Pino-based structured logging with WebSocket broadcast and transport system.

// All log levels
katax.logger.trace('trace message');
katax.logger.debug('debug message');
katax.logger.info({ message: 'Server started', port: 3000 });
katax.logger.warn({ message: 'High memory', percent: 85 });
katax.logger.error({ message: 'Query failed', error: err });
katax.logger.fatal('fatal error');

// Child logger with context
const log = katax.logger.child({ service: 'payments', userId: 123 });
log.info({ message: 'Payment processed' });

// Broadcast to WebSocket
katax.logger.info({ message: 'Trade executed', broadcast: true, room: 'admins' });

Transports

import { RedisTransport, TelegramTransport, CallbackTransport } from 'katax-service-manager';

// Redis transport
const redisTransport = new RedisTransport(katax.db('cache'), {
  streamKey: 'katax:logs', name: 'redis-errors',
});
redisTransport.filter = (log) => log.level === 'error' || log.persist === true;
katax.logger.addTransport(redisTransport);

// Telegram
const telegram = new TelegramTransport({
  botToken: katax.envRequired('TELEGRAM_BOT_TOKEN'),
  chatId: katax.envRequired('TELEGRAM_ALERTS_CHAT_ID'),
  levels: ['error', 'fatal'],
  includePersist: true, parseMode: 'Markdown',
});
katax.logger.addTransport(telegram);

// Management
katax.logger.removeTransport('telegram-errors');
await katax.logger.closeTransports();

WebSocket (Socket.IO)

// Shared with Express (preferred)
const httpServer = createServer(app);
await katax.socket({
  name: 'main', httpServer,
  cors: { origin: '*' },
});

// Standalone with auth
await katax.socket({
  name: 'events', port: 3001,
  enableAuth: true,
  authValidator: async (token) => token === katax.envRequired('WS_SECRET'),
});

const ws = katax.ws('main');
MethodDescription
emit(event, data, room?)Emit event (optionally to room)
emitToRoom(room, event, data)Emit to specific room
on(event, handler)Listen for events
onConnection(handler)Handle new connections
hasRoomListeners(room)Has listeners in room?
getRoomClientsCount(room)Clients in room
hasConnectedClients()Any clients connected?
getConnectedClientsCount()Total connected clients
close()Close WebSocket server
getServer()Underlying Socket.IO Server
ws.onConnection((socket) => {
  socket.on('message', (data) => { ... });
  socket.emit('welcome', { status: 'connected' });
  socket.join('room-123');
  socket.leave('room-123');
});

Cron Service

katax.cron({
  name: 'process-assets',
  schedule: '*/10 6-15 * * 1-5',
  task: processAssets,
  runOnInit: katax.isProd,
  timezone: 'America/Mexico_City',
  enabled: true,
});

// Advanced management
katax.cronService.getJobs();
katax.cronService.startJob('process-assets');
katax.cronService.stopJob('process-assets');
katax.cronService.removeJob('process-assets');
katax.cronService.stopAll();

Registry & Health Check

await katax.init({
  registry: {
    url: 'https://dashboard.example.com/api/services',
    apiKey: katax.env('REGISTRY_KEY'),
    heartbeatInterval: 30000,
    requestTimeoutMs: 5000,
    retryAttempts: 2,
    retryBaseDelayMs: 300,
    metadata: { env: katax.nodeEnv, region: 'us-east' },
  },
});

// Or custom handler
registry: {
  handler: {
    register: async (info) => { ... },
    heartbeat: async (info) => { ... },
    unregister: async (payload) => { ... },
  }
}

katax.isRegistered;         // boolean
katax.getServiceInfo();     // ServiceInfo | null

Health Check

const health = await katax.healthCheck();
// { status: 'healthy' | 'degraded' | 'unhealthy',
//   services: { databases: {}, sockets: {}, cron: boolean },
//   timestamp: number }

Redis Stream Bridge & Heartbeat

Stream Bridge

const bridge = katax.bridge('cache', 'main', {
  appName: 'my-api',
  streamKey: 'katax:logs',
  group: 'katax-bridge-my-api',
  batchSize: 10,
  blockTimeout: 2000,
});
await bridge.start();
bridge.isRunning();
bridge.stop();

Heartbeat

// Managed (auto-cleanup on shutdown)
katax.heartbeat(
  { app: katax.appName, port: 3000, version: katax.version, intervalMs: 10000 },
  'cache', 'main',
);

// Manual helpers
import { registerProjectInRedis, startHeartbeat } from 'katax-service-manager';
await registerProjectInRedis(redisDb, { app: katax.appName, version: katax.version, port: PORT });
const hb = startHeartbeat(redisDb, { app: katax.appName, port: PORT, intervalMs: 10000 }, ws);
hb?.stop();

Bootstrap Template

import dotenv from 'dotenv';
dotenv.config();

import { katax } from 'katax-service-manager';
import { createServer } from 'http';
import app from './app.js';

async function bootstrap(): Promise<void> {
  try {
    await katax.init({
      loadEnv: true,
      logger: { level: katax.env('LOG_LEVEL', 'info') as any, prettyPrint: katax.isDev, enableBroadcast: true },
    });

    await katax.database({
      name: 'main', type: 'postgresql',
      connection: {
        host: katax.envRequired('DB_HOST'),
        port: katax.env('DB_PORT', 5432),
        database: katax.envRequired('DB_NAME'),
        user: katax.envRequired('DB_USER'),
        password: katax.envRequired('DB_PASSWORD'),
      },
      pool: { max: 10, min: 2 },
    });

    await katax.database({
      name: 'cache', type: 'redis',
      connection: { host: katax.env('REDIS_HOST', '127.0.0.1'), port: 6379 },
    });

    const PORT = katax.env('PORT', '3000');
    const httpServer = createServer(app);
    await katax.socket({ name: 'main', httpServer, cors: { origin: '*' } });

    katax.cron({ name: 'cleanup', schedule: '0 3 * * *', task: async () => { /* nightly */ } });

    httpServer.listen(PORT, () => {
      katax.logger.info({ message: 'Server running on http://localhost:' + PORT });
    });
  } catch (err) {
    console.error('Bootstrap failed:', err);
    process.exit(1);
  }
}

void bootstrap();

katax-cli

CLI for scaffolding Express + TypeScript APIs, generating CRUD/endpoints/repositories, OpenAPI docs, and managing VPS deployments with PM2.

Scaffold init

Complete Express + TypeScript project with interactive prompts for DB, auth, validation, Swagger, WebSocket, Redis, and deployment config.

Generate endpoint & CRUD

Generates validators, controllers, handlers, and routes. Nested resources supported. Auto-regenerates OpenAPI docs.

Deploy PM2

Full VPS deployment workflow: init (clone + PM2), update (pull + restart), rollback, logs, and status.

Commands

katax init [project-name]

Scaffolds a complete Express + TypeScript + katax-core project.

FlagDescription
-f, --forceOverwrite existing directory
--pm <npm|pnpm>Package manager (default: pnpm)
--ignore-scriptsDisable lifecycle scripts
--write-npmrcWrite .npmrc for reproducible installs

katax add endpoint <name>

Add a new endpoint with validator, controller, handler, and routes.

FlagDescription
-m, --method <method>HTTP method (GET, POST, PUT, PATCH, DELETE)
-p, --path <path>Custom route path

katax generate crud <resource-name>

Aliases: gen, g. Generates CRUD endpoints: list, get by ID, create, update, delete.

FlagDescription
--no-authSkip authentication middleware

katax generate repository <name>

Data access layer with typed methods: findAll(), findById(), exists(), create(), update(), delete().

katax generate docs

FlagDescription
-f, --forceForce regeneration
-o, --output <path>Output path (default: src/openapi.json)
-p, --port <port>Server port
-u, --url <url>Production server URL

katax info

Aliases: status, ls. Shows project structure, dependencies, and routes.

Deploy

katax deploy init       # Initial PM2 setup (repo, branch, path, cluster, memory, env)
katax deploy update     # Pull, rebuild, restart
  -b, --branch <branch>
  --hard                # Hard reset
  -a, --app-name <name>
katax deploy rollback   # Revert commits
  -c, --commits <n>     # Default: 1
  -a, --app-name <name>
katax deploy logs       # View PM2 logs
  -l, --lines <n>
  -f, --follow
  -a, --app-name <name>
katax deploy status     # Show PM2 apps

Fix

katax fix docs        # Patch build script to copy openapi.json
  --skip-install
katax fix all         # Apply all fixes
katax fix list        # List available patches

Global Options

--no-color     # Disable colored output
--verbose      # Enable verbose logging
-v, --version  # Show version

Examples

katax init my-api --pm pnpm --ignore-scripts --write-npmrc
katax add endpoint admin/audit/logs -m POST
katax generate crud admin/users --no-auth
katax generate repository products
katax generate docs -u https://api.example.com
katax deploy update -b production --hard

Generators & Templates

Validator Generator

k.object() schemas with per-field validation, async validators and kataxInfer inference.

Controller Generator

Business logic with ControllerResult<T>, createSuccessResult(), createErrorResult().

Handler Generator

Express middleware chaining validator + controller with sendResponse().

Route Generator

Express Router with method calls and JSDoc documentation.

Router Updater

AST-based update of main routes.ts. Prevents duplicates.

OpenAPI Generator

Scans validators and routes, generates OpenAPI 3.0 spec.

Shared Utilities

Response Utils

  • sendSuccess<T>()
  • sendError() · sendValidationError()
  • sendResult<T,E>()
  • sendResponse()

Stream Utils (SSE)

  • initSSE() · sendSSEEvent()
  • sendSSEComment() · closeSSE()
  • SSEStream class
  • sendChunked() · streamAsyncIterator() · streamArray()

Auth Utils

  • hashPassword() (bcrypt) · hashPasswordArgon2()
  • generateAccessToken() · generateRefreshToken()
  • authenticateToken middleware
  • requireRole(...roles) middleware

API Utils

  • ControllerResult<T> type
  • validateSchema()
  • sendResponse()

Result Pattern & Errors

// Result<T, E> pattern
import { ok, err, isOk, isErr, map, mapErr, flatMap,
  unwrap, unwrapOr, tryCatch, tryCatchAsync, combine, match } from './core/result.js';

// AppError hierarchy
import { AppError, ValidationError, AuthenticationError,
  AuthorizationError, NotFoundError, ConflictError,
  DatabaseError, ExternalServiceError, isAppError } from './core/errors.js';

AI Skill — katax-ecosystem

The Copilot/AI skill for the Katax ecosystem. Knows versions, exports, patterns, CLI commands and troubleshooting.

What it covers

  • Versions: core 1.5.4, service-manager 0.5.3, cli 1.4.4
  • All schema types and their methods
  • All services and their API
  • All CLI commands with options
  • Complete bootstrap template
  • Troubleshooting and gotchas

When to invoke it

  • Create/extend APIs with Katax
  • Design validations with katax-core
  • Bootstrap with katax-service-manager
  • Generate endpoints/CRUD/repos with CLI
  • Configure DB, cache, cron, WebSocket
  • Deploy on VPS with PM2

Current Published Status

  • katax-core 1.5.4: 20+ schema types, coercion, async validation, file/base64, advanced email, union/intersection/lazy, preprocess, error utilities.
  • katax-service-manager 0.5.3: Singleton/instance, typed DB (PostgreSQL/MySQL/MongoDB/Redis), cache, cron, WebSocket with auth, transports (Redis/Telegram/Callback), registry, health, lifecycle hooks, stream bridge, heartbeat.
  • katax-cli 1.4.4: Init with advanced prompts, CRUD/endpoint/repository generators, OpenAPI docs, PM2 deploy (init/update/rollback/logs/status), fixes, nested resources, typed access.