npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@carlos-tzin/tzin

v1.0.8

Published

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

Readme

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:

| Gap | Evidence | |---|---| | Type inference collapses at scale | Hono issues #2399, #3869; chained route builders force one giant expression per app | | No architecture in lightweight frameworks | Hono issue #4121 | | Extractors don't exist in TS | Only Rust's Axum gets handler input right | | OpenAPI is a bolt-on | Every TS framework translates its own schema DSL to JSON Schema at runtime or via codegen | | AI-native toolchain | One 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

| Feature | Import | Description | |---|---|---| | Contracts | @carlos-tzin/tzin | Type-safe API contracts | | Routes | @carlos-tzin/tzin | Bind contracts to handlers | | Middleware | @carlos-tzin/tzin | Onion-style middleware | | DI | @carlos-tzin/tzin | Typed dependency injection |

Runtime

| Feature | Import | Description | |---|---|---| | Node server | @carlos-tzin/tzin | listen(app, port) | | Bun server | @carlos-tzin/tzin | serveBun(app, port) | | Workers | @carlos-tzin/tzin | toWorker(app) | | Dev server | CLI | tzin dev with hot reload |

Realtime

| Feature | Import | Description | |---|---|---| | Channels | @carlos-tzin/tzin | SSE + POST channels | | Presence | @carlos-tzin/tzin | Phoenix-style presence | | WebSocket | @carlos-tzin/tzin/ws | Native WS channels | | Browser client | @carlos-tzin/tzin/client-browser | Zero-dep browser client |

AI-Native

| Feature | Import | Description | |---|---|---| | MCP Server | @carlos-tzin/tzin | Streamable HTTP + stdio | | OpenAPI | @carlos-tzin/tzin | Auto-generated from contracts | | LLMs.txt | @carlos-tzin/tzin | AI-readable API index |

Database

| Feature | Import | Description | |---|---|---| | Models | @carlos-tzin/tzin/db | Type-safe ORM | | Query builder | @carlos-tzin/tzin/db | Chainable queries | | Store adapters | @carlos-tzin/tzin/db | Swappable backends |

Auth

| Feature | Import | Description | |---|---|---| | Bearer auth | @carlos-tzin/tzin/auth | JWT validation | | Optional auth | @carlos-tzin/tzin/auth | Non-strict JWT | | API key | @carlos-tzin/tzin/auth | Header-based auth | | JWT utils | @carlos-tzin/tzin/auth | sign/verify |

Jobs

| Feature | Import | Description | |---|---|---| | Define jobs | @carlos-tzin/tzin/jobs | Background tasks | | Enqueue | @carlos-tzin/tzin/jobs | Job queue | | Retry | @carlos-tzin/tzin/jobs | Auto-retry on failure |

Logging

| Feature | Import | Description | |---|---|---| | Logger | @carlos-tzin/tzin/log | Structured logging | | Child loggers | @carlos-tzin/tzin/log | Scoped context | | Pretty/JSON | @carlos-tzin/tzin/log | Configurable output |

Testing

| Feature | Import | Description | |---|---|---| | Test client | @carlos-tzin/tzin/test | API testing | | Schema validation | @carlos-tzin/tzin/test | Type assertions | | Mock data | @carlos-tzin/tzin/test | Generate 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 routes | tzin: types | Hono: types | tzin: instantiations | Hono: instantiations | |---|---|---|---|---| | 20 | 4,851 | 72,368 | 22,472 | 156,054 | | 100 | 15,779 | 111,952 | 93,128 | 240k | | 300 | 43,099 | 210,912 | 270k | 590k |

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

Runtime throughput

| Framework | req/s | p99 | |---|---|---| | raw node:http (floor) | ~42k | 2–3ms | | hono | ~34–36k | 3ms | | tzin | ~30–31k | 6ms | | express | ~15k | 7ms |

Examples

| Example | Runtime | What it shows | |---|---|---| | examples/node-demo.ts | Node | Minimal HTTP server with contracts | | examples/bun-demo.ts | Bun | Bun.serve with validation | | examples/todo-api.ts | Node | Full CRUD: auth middleware, DI, OpenAPI, MCP | | examples/mcp-demo.ts | Node | MCP server over stdio | | examples/ws-demo.ts | Bun | WebSocket channels with presence | | examples/workers-quickstart/ | Workers | Copy-paste wrangler project: DO + channels + presence | | examples/workers-quickstart.md | Workers | Same 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.