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

typecompass

v1.0.4

Published

Type-safe API contracts with OpenAPI generation for TypeScript

Readme

TypeCompass

Navigate your API with type-safe precision 🧭

TypeCompass is a lightweight TypeScript library that lets you define API contracts once and use them everywhere — with full type safety, automatic OpenAPI generation, and zero runtime overhead.

Features

Type-Safe Contracts - Define routes with Zod schemas, get full TypeScript inference
🔄 Client & Server - Use the same contract for backend validation and frontend calls
📚 Auto OpenAPI - Generate OpenAPI 3.0 specs automatically from your contracts
🎯 Zero Runtime Cost - Contracts are just types on the client side
🔗 Combinable - Merge multiple service contracts into one unified API
🎨 Framework Agnostic - Works with Express, Fastify, Hono, or any Node.js framework

Installation

npm install typecompass zod

Quick Start

1. Define a Contract

// contracts/auth.contract.ts
import { defineRoutes } from 'typecompass'
import { z } from 'zod'

export const AuthContract = defineRoutes({
  login: {
    method: "POST",
    path: "/auth/login",
    summary: "User Login",
    tags: ["Auth"],
    body: z.object({
      email: z.string().email(),
      password: z.string().min(8),
    }),
    responses: {
      200: {
        schema: z.object({
          token: z.string(),
          user: z.object({
            id: z.string(),
            email: z.string(),
          }),
        }),
      },
    },
  },
  
  register: {
    method: "POST",
    path: "/auth/register",
    summary: "User Registration",
    tags: ["Auth"],
    body: z.object({
      email: z.string().email(),
      password: z.string().min(8),
      name: z.string(),
    }),
  },
})

2. Use on the Backend

// server.ts
import express from 'express'
import { AuthContract } from './contracts/auth.contract'

const app = express()

app.post('/auth/login', async (req, res) => {
  // Validate with the contract schema
  const data = AuthContract.login.body.parse(req.body)
  
  // TypeScript knows the shape of data!
  const user = await loginUser(data.email, data.password)
  
  res.json({ token: user.token, user })
})

// Generate OpenAPI documentation
app.get('/openapi.json', (req, res) => {
  const spec = AuthContract.generateOpenApi({
    title: "Auth API",
    version: "1.0.0",
    servers: [{ url: "https://api.example.com", description: "Production" }],
  })
  res.json(spec)
})

3. Use on the Frontend

// api/client.ts
import { AuthContract } from '@company/api-contracts'
import { initClient } from 'typecompass/client'
import axios from 'axios'

const axiosInstance = axios.create({
  baseURL: 'https://api.example.com',
})

const client = initClient(AuthContract, axiosInstance)

// Fully typed API calls!
const response = await client.login({
  body: {
    email: "[email protected]",
    password: "secret123",
  }
})

// TypeScript knows response.data.token exists
console.log(response.data.token)

Combining Multiple Contracts

For larger applications with multiple services:

// contracts/index.ts
import { combineContracts } from 'typecompass'
import { AuthContract } from './auth.contract'
import { UsersContract } from './users.contract'
import { PaymentsContract } from './payments.contract'

export const ApiContract = combineContracts({
  auth: AuthContract,
  users: UsersContract,
  payments: PaymentsContract,
})

// Generate unified OpenAPI spec
export const openApiSpec = ApiContract.generateOpenApi({
  title: "Company API",
  version: "1.0.0",
  servers: [
    { url: "https://api.company.com", description: "Production" },
    { url: "http://localhost:3000", description: "Development" },
  ],
  securitySchemes: {
    BearerAuth: {
      type: "http",
      scheme: "bearer",
    },
  },
  defaultSecurity: ["BearerAuth"],
})

Client with Combined Contracts

// Frontend usage
import { ApiContract } from '@company/api-contracts'
import { initCombinedClient } from 'typecompass/client'

const client = initCombinedClient(ApiContract, axiosInstance)

// Namespaced by service
await client.auth.login({ body: {...} })
await client.users.getProfile({ params: { id: "123" } })
await client.payments.createCharge({ body: {...} })

Advanced Features

Path Parameters

const UsersContract = defineRoutes({
  getUser: {
    method: "GET",
    path: "/users/:id",
    summary: "Get User by ID",
    params: z.object({
      id: z.string(),
    }),
  },
})

// Client usage
await client.getUser({ params: { id: "user-123" } })

Query Parameters

const ProductsContract = defineRoutes({
  searchProducts: {
    method: "GET",
    path: "/products",
    summary: "Search Products",
    query: z.object({
      q: z.string(),
      category: z.string().optional(),
      limit: z.number().default(10),
    }),
  },
})

// Client usage
await client.searchProducts({ 
  query: { q: "laptop", category: "electronics", limit: 20 } 
})

Custom Security

const AdminContract = defineRoutes({
  deleteUser: {
    method: "DELETE",
    path: "/admin/users/:id",
    summary: "Delete User",
    tags: ["Admin"],
    security: ["BearerAuth", "AdminRole"],
    params: z.object({
      id: z.string(),
    }),
  },
})

Schema Examples

Add examples to your schemas for better documentation:

import { z } from 'zod'

const createUserSchema = z.object({
  email: z.string().email().example("[email protected]"),
  name: z.string().example("John Doe"),
  age: z.number().min(18).example(25),
})

Publishing Contracts

For teams with separate frontend/backend repos, publish your contracts as an npm package:

1. Create Contracts Package

packages/api-contracts/package.json


{
  "name": "@company/api-contracts",
  "version": "1.0.0",
  "private": true,
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "dependencies": {
    "typecompass": "^1.0.0"
  },
  "peerDependencies": {
    "zod": "^3.0.0"
  }
}

2. Export Combined Contract

// packages/api-contracts/src/index.ts
export { ApiContract } from './contracts'
export type { ApiContract as ApiContractType } from './contracts'

3. Install in Frontend

npm install @company/api-contracts
import { ApiContract } from '@company/api-contracts'
import { initCombinedClient } from 'typecompass/client'

const api = initCombinedClient(ApiContract, axiosInstance)

API Reference

defineRoutes(routes)

Define a single service contract.

Parameters:

  • routes - Object mapping route names to route configurations

Returns: Contract<T>

combineContracts(contracts)

Combine multiple contracts into one.

Parameters:

  • contracts - Object mapping namespace to contracts

Returns: CombinedContract<T>

generateOpenApi(contract, config)

Generate OpenAPI 3.0 specification.

Parameters:

  • contract - Contract or CombinedContract
  • config - OpenAPI configuration (title, version, servers, etc.)

Returns: OpenAPI JSON object

initClient(contract, api)

Initialize type-safe client for a single contract.

Parameters:

  • contract - Contract to use
  • api - Axios-like API provider

Returns: Typed client object

initCombinedClient(contract, api)

Initialize type-safe client for combined contracts.

Parameters:

  • contract - CombinedContract to use
  • api - Axios-like API provider

Returns: Namespaced typed client object

Route Configuration

interface RouteConfig {
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
  path: string                    // e.g., "/users/:id"
  summary: string                 // Short description
  tags?: string[]                 // For OpenAPI grouping
  security?: string[]             // Security scheme names
  body?: z.ZodType               // Request body schema
  query?: z.ZodType              // Query parameters schema
  params?: z.ZodType             // Path parameters schema
  responses?: Record<number, ResponseConfig>
  description?: string            // Long description
}

License

MIT © Jesulonimii

Contributing

Contributions welcome! Please open an issue or PR.