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

@taico/openapi-sdkgen

v0.3.3

Published

A TypeScript SDK generator from OpenAPI specs with focus on developer ergonomics and maintainability.

Readme

@taico/openapi-sdkgen

A TypeScript SDK generator from OpenAPI specs with focus on developer ergonomics and maintainability.

Install

npm install @taico/openapi-sdkgen

CLI

openapi-sdkgen ./openapi.json ./generated

Motivation

The existing @taico/client package uses openapi-typescript-codegen with multiple post-processing scripts to work around limitations:

  • fix-esm-imports.js - Adds .js extensions for ESM compatibility
  • make-client-instantiable.js - Transforms static methods to accept per-instance config

This approach is fragile and hard to maintain. This package generates better SDKs from scratch instead.

Design Goals

  1. Instance-based configuration - No global singletons, auth per client instance
  2. Ergonomic API - Resource-based grouping, clean method signatures
  3. Type-safe - Full TypeScript support with strict mode
  4. Streaming support - SSE endpoints return AsyncIterable
  5. Simple generator - Transparent code generation, easy to debug
  6. No post-processing - Generate correct code from the start

Architecture

Three-Step Process

  1. Parse (parser.ts) - Convert OpenAPI JSON to internal IR
  2. Generate (generator.ts) - Produce TypeScript source files
  3. Emit (index.ts) - Write files to disk

Generated Structure

generated/
├── index.ts              # Main exports
├── client.ts             # ApiClient main class
├── base-client.ts        # BaseClient with fetch wrapper
├── types.ts              # Type definitions from schemas
├── users-resource.ts     # UsersResource class
├── tasks-resource.ts     # TasksResource class
└── stream-resource.ts    # StreamResource class

Usage Pattern

const client = new ApiClient({
  baseUrl: 'http://localhost:3000',
  getAccessToken: async () => getToken(),
});

// Resource-based API
await client.users.getUser({ id: '123' });
await client.tasks.create({ body: { title: 'Task' } });

// Streaming
for await (const event of client.stream.events({ count: 10 })) {
  console.log(event);
}

// AbortSignal support
const controller = new AbortController();
await client.users.list({ signal: controller.signal });

Key Features

Instance-Based Auth

const client1 = new ApiClient({ baseUrl: 'http://api1.com', getAccessToken: () => token1 });
const client2 = new ApiClient({ baseUrl: 'http://api2.com', getAccessToken: () => token2 });

No global state, no singleton issues.

Resource Grouping

Operations are grouped by OpenAPI tags into resource classes:

  • client.users.* - All user operations
  • client.tasks.* - All task operations
  • client.stream.* - All streaming operations

Streaming Support

SSE endpoints automatically detected and generated as async generators:

async *streamEvents(params): AsyncIterable<Event> {
  yield* this.streamEvents('/stream/events', { params });
}

Type Safety

  • Request bodies typed from requestBody schema
  • Path/query params typed from parameters
  • Response types from responses[200].content
  • Optional fields handled correctly
  • Enums generated as union types

Testing

The test suite is fully automated and self-contained under test/.

npm test

This runs the full pipeline:

  1. Clean - Remove previously generated client
  2. Generate spec - Start the test API in spec-generation mode, write openapi.json, exit
  3. Generate client - Run the generator against the spec
  4. Run tests - Start the test API server, run the test SDK against it, shut down

Test API (test/api/)

NestJS app with endpoints exercising OpenAPI features:

  • GET with path/query params
  • POST/PUT/PATCH with JSON body
  • DELETE with no content response
  • Nested objects and arrays
  • Optional fields
  • SSE streaming (/stream/events)
  • Auth headers and custom header parameters
  • Query parameters with special characters

The test API generates openapi.json via --generate-spec mode (starts, writes file, exits immediately — no server needed).

Test Client (test/client/)

test-sdk.ts imports the generated SDK and makes real HTTP calls to the test API, validating both types and runtime behavior including streaming and AbortSignal.

Tradeoffs

What We Gain

✅ No post-processing — generate correct code directly ✅ Cleaner code — no regex hacks on generated output ✅ Instance config — no global singleton ✅ Better DX — resource grouping, clear method names ✅ Streaming — first-class AsyncIterable support ✅ Maintainability — simple generator, easy to understand

What We Lose

❌ More code — custom generator vs off-the-shelf tool ❌ Edge cases — may not handle all OpenAPI features yet ❌ Battle-tested — new code vs mature library

Comparison to Current Approach

| Aspect | Current (openapi-typescript-codegen) | New Generator | |--------|---------------------------------------|---------------| | Post-processing | 2 scripts (fix-esm, make-instantiable) | None | | Auth pattern | Global with per-call override | Instance-based | | Resource grouping | Service classes | Resource classes | | Streaming | Not supported | AsyncIterable | | Maintainability | Fragile regex transforms | Transparent generation |

Limitations

Current implementation doesn't handle:

  • Complex schema compositions (allOf, oneOf, anyOf)
  • Custom media types beyond JSON
  • File uploads
  • Cookie parameters
  • Complex security schemes

File Structure

packages/openapi-sdkgen/
├── src/
│   ├── types.ts       # Internal IR types
│   ├── parser.ts      # OpenAPI -> IR
│   ├── generator.ts   # IR -> TypeScript
│   ├── index.ts       # Main API
│   └── cli.ts         # CLI tool
├── test/
│   ├── api/           # NestJS test API (spec source)
│   │   └── src/
│   │       ├── main.ts
│   │       ├── app.module.ts
│   │       ├── users.controller.ts
│   │       ├── tasks.controller.ts
│   │       └── stream.controller.ts
│   ├── client/        # Test SDK + generated output
│   │   ├── generated/ # Generated SDK (gitignored)
│   │   └── test-sdk.ts
│   └── run.mjs        # Test orchestrator
├── package.json
├── tsconfig.json
└── README.md