@carlos-tzin/tzin

中文文档
1.0.8发布于 2026/10/01MITTypeScriptES Module近 30 天下载 2323

Contract-first TypeScript framework. Types that scale, realtime channels with presence, and an MCP server for every API.

原始使用文档
文档目录24 节
  1. Documentation
  2. Why another framework?
  3. Features
  4. Core
  5. Runtime
  6. Realtime
  7. AI-Native
  8. Database
  9. Auth
  10. Jobs
  11. Logging
  12. Testing
  13. Quick Start
  14. 1. Scaffold
  15. 2. Define a contract
  16. 3. Create the app
  17. 4. Run
  18. CLI
  19. Benchmarks
  20. Runtime throughput
  21. Examples
  22. Design principles
  23. Development
  24. License

tzin

Contract-first TypeScript framework. Types that scale. Realtime built in. AI-native from day one.

tzin — from Nahuatl -tzin, an honorific suffix for what is valued and beloved. A pact between client and server, declared once.

CI npm Donate Buy Me A Coffee

Status: stable (1.0.x). The core works end-to-end (see Benchmarks); 1.0.0 shipped the stable API, and 1.0.2 adds test coverage gates, a wider CI matrix and a public type-clean surface.

npm install @carlos-tzin/tzin

Or scaffold a new project:

npx create-tzin my-app

Documentation

Hosted site: tzin.tzinny.com

Why another framework?

The TypeScript backend landscape is crowded — and still leaves real gaps:

GapEvidence
Type inference collapses at scaleHono issues #2399, #3869; chained route builders force one giant expression per app
No architecture in lightweight frameworksHono issue #4121
Extractors don't exist in TSOnly Rust's Axum gets handler input right
OpenAPI is a bolt-onEvery TS framework translates its own schema DSL to JSON Schema at runtime or via codegen
AI-native toolchainOne framework ships an MCP server; the window is closing

tzin's answer: declare a contract once, get everything else for free.

import { t } from '@carlos-tzin/tzin'
import { contract, impl, createApp, listen } from '@carlos-tzin/tzin'

const getUser = contract({
  method: 'GET',
  path: '/users/:id',
  params: t.Object({ id: t.String() }),
  responses: {
    200: t.Object({ id: t.String(), name: t.String(), tags: t.Array(t.String()) }),
    404: t.Object({ error: t.String() }),
  },
})

export const getUserRoute = impl(getUser, async ({ params }) => {
  const user = await findUser(params.id)
  if (!user) throw new HttpError(404, 'user not found')
  return { status: 200, body: user }
})

const app = createApp([getUserRoute])
listen(app, 3000)

From that single declaration:

  • Handler input is extracted, not guessed: { params } exists because you declared it; add query, body, headers or cookies to the contract and they appear, fully typed and validated per request.
  • The compiler enforces your responses: returning a shape that doesn't match the declared 200 body is a type error. Thrown HttpErrors map to their status.
  • OpenAPI 3.1 is free: contracts are JSON Schema (TypeBox), so generateOpenApi(routes) needs no translation layer.

Features

Core

FeatureImportDescription
Contracts@carlos-tzin/tzinType-safe API contracts
Routes@carlos-tzin/tzinBind contracts to handlers
Middleware@carlos-tzin/tzinOnion-style middleware
DI@carlos-tzin/tzinTyped dependency injection

Runtime

FeatureImportDescription
Node server@carlos-tzin/tzinlisten(app, port)
Bun server@carlos-tzin/tzinserveBun(app, port)
Workers@carlos-tzin/tzintoWorker(app)
Dev serverCLItzin dev with hot reload

Realtime

FeatureImportDescription
Channels@carlos-tzin/tzinSSE + POST channels
Presence@carlos-tzin/tzinPhoenix-style presence
WebSocket@carlos-tzin/tzin/wsNative WS channels
Browser client@carlos-tzin/tzin/client-browserZero-dep browser client

AI-Native

FeatureImportDescription
MCP Server@carlos-tzin/tzinStreamable HTTP + stdio
OpenAPI@carlos-tzin/tzinAuto-generated from contracts
LLMs.txt@carlos-tzin/tzinAI-readable API index

Database

FeatureImportDescription
Models@carlos-tzin/tzin/dbType-safe ORM
Query builder@carlos-tzin/tzin/dbChainable queries
Store adapters@carlos-tzin/tzin/dbSwappable backends

Auth

FeatureImportDescription
Bearer auth@carlos-tzin/tzin/authJWT validation
Optional auth@carlos-tzin/tzin/authNon-strict JWT
API key@carlos-tzin/tzin/authHeader-based auth
JWT utils@carlos-tzin/tzin/authsign/verify

Jobs

FeatureImportDescription
Define jobs@carlos-tzin/tzin/jobsBackground tasks
Enqueue@carlos-tzin/tzin/jobsJob queue
Retry@carlos-tzin/tzin/jobsAuto-retry on failure

Logging

FeatureImportDescription
Logger@carlos-tzin/tzin/logStructured logging
Child loggers@carlos-tzin/tzin/logScoped context
Pretty/JSON@carlos-tzin/tzin/logConfigurable output

Testing

FeatureImportDescription
Test client@carlos-tzin/tzin/testAPI testing
Schema validation@carlos-tzin/tzin/testType assertions
Mock data@carlos-tzin/tzin/testGenerate mocks

Quick Start

1. Scaffold

npx create-tzin my-api
cd my-api

2. Define a contract

// src/routes/users.ts
import { t, contract, impl } from '@carlos-tzin/tzin'

export const getUser = contract({
  method: 'GET',
  path: '/users/:id',
  params: t.Object({ id: t.String() }),
  responses: {
    200: t.Object({ id: t.String(), name: t.String() }),
    404: t.Object({ error: t.String() }),
  },
})

export const getUserRoute = impl(getUser, async ({ params }) => {
  return { status: 200, body: { id: params.id, name: 'Ada' } }
})

3. Create the app

// src/app.ts
import { createApp } from '@carlos-tzin/tzin'
import { getUserRoute } from './routes/users.js'

export const app = createApp([getUserRoute], {
  openapi: true,
  mcp: true,
  meta: { title: 'My API', version: '1.0.0' },
})

4. Run

npm run dev    # tzin dev  -> dev server at http://localhost:3000
npm run build  # tzin build -> production build

The tzin binary ships with the package, so these scripts work after npm install. Without a local install, run it through npm exec:

npx --package @carlos-tzin/tzin tzin dev

CLI

tzin dev [--port N]                                # dev server with hot reload
tzin build                                         # build for production
tzin deploy --target node|workers [--pack] [--docker <tag> [--push]]  # deploy
tzin generate route <name>                         # scaffold a route
tzin generate middleware <name>                    # scaffold middleware
tzin generate test <name>                          # scaffold a test

Benchmarks

100 endpoints with distinct schemas, checked by tsc --extendedDiagnostics:

N routestzin: typesHono: typestzin: instantiationsHono: instantiations
204,85172,36822,472156,054
10015,779111,95293,128240k
30043,099210,912270k590k

tzin grows strictly linearly (~130 types/endpoint).

Runtime throughput

Frameworkreq/sp99
raw node:http (floor)~42k2–3ms
hono~34–36k3ms
tzin~30–31k6ms
express~15k7ms

Examples

ExampleRuntimeWhat it shows
examples/node-demo.tsNodeMinimal HTTP server with contracts
examples/bun-demo.tsBunBun.serve with validation
examples/todo-api.tsNodeFull CRUD: auth middleware, DI, OpenAPI, MCP
examples/mcp-demo.tsNodeMCP server over stdio
examples/ws-demo.tsBunWebSocket channels with presence
examples/workers-quickstart/WorkersCopy-paste wrangler project: DO + channels + presence
examples/workers-quickstart.mdWorkersSame project, explained file-by-file

Design principles

  • Contract-first, flat registry. A route is data (contract({...})), not a link in a builder chain. Inference cost stays O(1) per endpoint.
  • JSON Schema native. TypeBox schemas double as OpenAPI with zero conversion.
  • Web Standards runtime. Request in, Response out; adapters stay thin.
  • Extractors over magic. Handlers receive exactly what the contract declares.
  • Errors are control flow. Throw typed errors; the response union already knows.
  • Light DI without ceremony. provide(key, value) at app level seeds typed singletons into every request's context — handlers just ctx.require(db).

Development

npm install
npm test          # vitest — runtime + end-to-end client + type assertions
npm run typecheck # strict tsc across src/test/bench fixtures

License

MIT — see LICENSE.

版本与发布记录

@carlos-tzin/tzin 共发布 21 个版本,首次发布于 2026/08/26;过去 12 个月发布了 21 个版本。

版本发布日期距今
1.0.8latest2026/10/011 个月前
1.0.72026/10/011 个月前
1.0.62026/09/221 个月前
1.0.52026/09/221 个月前
1.0.42026/09/151 个月前
1.0.32026/09/151 个月前

关于 @carlos-tzin/tzin 的常见问题

@carlos-tzin/tzin 是什么?

Contract-first TypeScript framework. Types that scale, realtime channels with presence, and an MCP server for every API.

如何安装 @carlos-tzin/tzin?

在项目目录运行 npm install @carlos-tzin/tzin,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 tzin,可以用 npx tzin 直接运行。

@carlos-tzin/tzin 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@carlos-tzin/tzin 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@carlos-tzin/tzin 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@carlos-tzin/tzin 可以商用吗?

@carlos-tzin/tzin 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@carlos-tzin/tzin 的下载量有多少?

根据 npm 官方下载统计,@carlos-tzin/tzin 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,323 次,日均约 77 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@carlos-tzin/tzin 还在维护吗?

最新版本 1.0.8 发布于 2026/10/01(1 个月前);至今共发布 21 个版本,其中过去 12 个月发布了 21 个;首次发布于 2026/08/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。