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

better-swagger-types

v0.3.0

Published

Prisma-like TypeScript type generation for Swagger/OpenAPI schemas

Readme

better-swagger-types

Prisma-style TypeScript type generation for Swagger / OpenAPI JSON schemas.

better-swagger-types generates stable, ergonomic TypeScript output into lib/generated without forcing an HTTP client. The generated code is types-first by default and works well with fetch, axios, swr, and React Query.

Features

  • Prisma-like init and generate workflow
  • Multiple schemas with friendly names and namespaces
  • Local file, directory, glob, and remote URL schema sources
  • OpenAPI v3 and Swagger v2 support
  • Deterministic output with stable operation naming
  • Optional simple path aliases such as HereTooSomethingHereV1API
  • Generated paths, schemas, simple, operations, endpoints, and meta files
  • Optional watch mode and clean command
  • No runtime dependency required in generated files

Installation

bun add -d better-swagger-types

npm also works:

npm install --save-dev better-swagger-types

Quick Start

Initialize the config file:

bunx better-swagger-types --init

Generate types:

bunx better-swagger-types generate

Default command behavior is generate, so this is equivalent:

bunx better-swagger-types

Commands

better-swagger-types --init
better-swagger-types init [--config <path>] [--force]
better-swagger-types generate [--config <path>] [--no-cache] [--verbose]
better-swagger-types dev [--config <path>] [--no-cache] [--verbose]
better-swagger-types clean [--config <path>] [--verbose]

Config

better-swagger-types creates api.swagger-types.ts in your project root.

import { defineConfig } from 'better-swagger-types/config';

export default defineConfig({
  output: 'lib/generated',
  prismaStyleNodeModulesOutput: false,
  schemas: [
    {
      name: 'core',
      source: './schemas/core.json',
      headers: {
        Authorization: `Bearer ${process.env.API_TOKEN ?? ''}`
      },
      format: 'auto',
      namespace: 'Core'
    }
  ],
  generator: {
    emitOperations: true,
    emitSchemas: true,
    emitSimpleAliases: false,
    resolveRefs: true,
    naming: 'stable'
  }
});

Config Options

  • output: relative or absolute output directory for generated files
  • prismaStyleNodeModulesOutput: writes a marker manifest to node_modules/.better-swagger-types
  • schemas: one or more schema source definitions
  • schemas[].name: friendly schema name
  • schemas[].source: file path, directory, glob, or http(s) URL
  • schemas[].headers: headers for remote fetches
  • schemas[].format: auto, openapi3, or swagger2
  • schemas[].namespace: optional TS namespace override
  • generator.emitOperations: emit operations.ts and endpoints.ts
  • generator.emitSchemas: emit schemas.ts
  • generator.emitSimpleAliases: emit path-derived aliases in simple.ts
  • generator.resolveRefs: validate and bundle refs when possible
  • generator.naming: currently supports stable

Generated Output

lib/generated/
  index.ts
  core/
    index.ts
    paths.ts
    schemas.ts
    simple.ts      # when emitSimpleAliases is true
    operations.ts
    endpoints.ts
    meta.ts

Generated files include:

  • paths.ts: OpenAPI-style paths mapping plus canonical component types
  • schemas.ts: schema component aliases such as User and CreateUserInput
  • simple.ts: optional path-derived aliases such as UsersByIdAPI and HereTooSomethingHereV1API
  • operations.ts: operation-level ergonomic mapping keyed by stable names
  • endpoints.ts: endpoint mapping keyed by "METHOD /path"
  • meta.ts: deterministic metadata including schema hash

Simple Path Aliases

Enable generator.emitSimpleAliases to emit a simple.ts file with path item aliases derived from route paths.

import type { Simple } from './lib/generated';

type UsersByIdAPI = Simple.UsersByIdAPI;
type HereTooSomethingHereV1API = Simple.HereTooSomethingHereV1API;

Usage Examples

fetch

import type { Core } from './lib/generated';

type GetUserEndpoint = Core.Endpoints['GET /users/{id}'];
type GetUserParams = Core.ParamsFor<GetUserEndpoint>;
type GetUserResponse = Core.EndpointSuccessResponseFor<GetUserEndpoint>;

async function getUser(params: GetUserParams): Promise<GetUserResponse> {
  const response = await fetch(`/users/${params.path.id}`);
  return response.json() as Promise<GetUserResponse>;
}

axios

import axios from 'axios';
import type { Core } from './lib/generated';

type CreateUser = Core.Endpoints['POST /users'];

async function createUser(body: Core.RequestBodyFor<CreateUser>) {
  return axios.post<Core.EndpointSuccessResponseFor<CreateUser>>('/users', body);
}

SWR

import useSWR from 'swr';
import type { Core } from './lib/generated';

type GetUser = Core.Endpoints['GET /users/{id}'];
type GetUserResponse = Core.EndpointSuccessResponseFor<GetUser>;

const fetcher = async (url: string): Promise<GetUserResponse> => {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error('Request failed');
  }
  return response.json() as Promise<GetUserResponse>;
};

export function useUser(id: string) {
  return useSWR(`/users/${id}`, fetcher);
}

React Query

import { useQuery } from '@tanstack/react-query';
import type { Core } from './lib/generated';

type GetUser = Core.Endpoints['GET /users/{id}'];

export function useUser(id: string) {
  return useQuery<Core.EndpointSuccessResponseFor<GetUser>>({
    queryKey: ['user', id],
    queryFn: async () => {
      const response = await fetch(`/users/${id}`);
      return response.json() as Promise<Core.EndpointSuccessResponseFor<GetUser>>;
    }
  });
}

Schema Sources

Single file

schemas: [{ name: 'core', source: './schemas/core.json' }]

Directory

A directory expands non-recursively to all *.json files. If multiple files are found, each one becomes its own generated schema namespace.

schemas: [{ name: 'services', source: './schemas', namespace: 'Services' }]

Glob

schemas: [{ name: 'apis', source: './schemas/**/*.json' }]

Remote URL

schemas: [
  {
    name: 'remote',
    source: 'https://example.com/openapi.json',
    headers: {
      Authorization: `Bearer ${process.env.API_TOKEN ?? ''}`
    }
  }
]

Remote schemas are cached in .better-swagger-types/cache/. If the server returns ETag or Last-Modified, subsequent runs use conditional requests automatically. Use --no-cache to bypass the cache.

Troubleshooting

Config missing

Run:

bunx better-swagger-types --init

Remote URL fails

  • confirm the URL returns JSON
  • verify any auth headers in schemas[].headers
  • rerun with --verbose to see cache and resolution details

Invalid schema

better-swagger-types validates the document and surfaces parser errors with path context. Fix the schema and rerun generation.

Output path contains old files

Run:

bunx better-swagger-types clean

Missing operationId

This is fine. better-swagger-types falls back to a stable Method + Path name such as GetUsersById.

Development

bun run build
bun run typecheck
bun run test

Example schemas live in examples/.

Release Automation

Automated npm publishing is configured through deploy.yml.

The workflow is designed for npm trusted publishing via GitHub Actions OIDC:

  • publishes only from v* git tags
  • requires the GitHub Actions job to obtain an OIDC token
  • uses the GitHub Environment named release
  • runs bun run release:check before publishing
  • performs a packaged-artifact smoke test before npm publish

One-time setup

  1. In GitHub, create an environment named release.
  2. In that environment, require at least one reviewer and disable self-review if you want a manual approval gate before publish.
  3. In npm package settings for better-swagger-types, configure a trusted publisher for:
    • owner: Sma-Das
    • repository: better-swagger-types
    • workflow filename: deploy.yml
  4. In npm package settings, prefer tokenless publishing by disallowing classic automation tokens once trusted publishing is working.

Release flow

npm version patch
git push origin main --follow-tags

That pushes a tag such as v0.1.4, triggers the deploy workflow, validates the packaged artifact, and publishes to npm if the release environment and npm trusted publisher both allow it.