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

api-dumper

v0.1.0

Published

Generate TypeScript types and enum constants from any OpenAPI 3.x schema, with an API Platform / JSON-LD preset.

Readme

api-dumper

Dump an OpenAPI 3.x schema into TypeScript: the openapi-typescript types, a cleaned copy of the schema, and one file of constants per enum.

It works with any OpenAPI API. An api-platform preset covers what API Platform and JSON-LD / Hydra APIs need on top: dropping the per-format schemas (Animal.csv…) and mapping enum values to their IRIs.

app/api-schema/
├── openapi.json       # the schema, cleaned
├── api-schema.ts      # openapi-typescript types (`paths`, `components`…)
└── enums/
    ├── Gender.ts
    └── PetStatus.ts

Install

pnpm add -D api-dumper typescript

Node 20 or later. typescript is a peer dependency of openapi-typescript.

Quick start

Create api-dumper.config.ts at the root of your project:

import { defineConfig } from "api-dumper"

export default defineConfig({
  source: "https://api.example.com/openapi.yaml", // URL or file, JSON or YAML
  outDir: "src/api",
})

Then run it:

npx api-dumper              # writes what changed, removes vanished enums
npx api-dumper --check      # writes nothing, exits 1 if the files are out of date
npx api-dumper -c other.config.ts

--check is meant for CI: regenerate from the committed schema and fail when someone forgot to commit the result.

Paths in the config resolve against the config file's directory. The config may be .ts, .mts, .js, .mjs or .json.

Enums

Every named schema carrying the standard enum keyword becomes a file:

components:
  schemas:
    PetStatus:
      type: string
      enum: [available, pending, sold]
// enums/PetStatus.ts
export const PetStatus = ["available","pending","sold"] as const

export const PetStatusEnum = {
  available: "available",
  pending: "pending",
  sold: "sold",
} as const

export type PetStatusValues = keyof typeof PetStatusEnum

null is left out of the values. Enums declared inline on a property are skipped, unless enums.inline is on: they are then named <Schema><Property> (PetSize).

These schema extensions are understood:

| Extension | Effect | |--------------------------------------|----------------------------------------------------------------------------| | x-enum-name | TypeScript name, instead of the one derived from the schema key | | x-enum-varnames / x-enumNames | Key of each value — needed for numeric enums ({ LOW: 1, HIGH: 3 }) | | x-enum-iris | IRI of each value ({ "MALE": "/api/genders/MALE" }), emits XxxApiEnum |

Without x-enum-varnames, a numeric value gets a VALUE_1-style key. Two enums ending up with the same name but different values are an error, never a silent overwrite.

API Platform / JSON-LD

export default defineConfig({
  source: "../api/var/openapi.json", // bin/console api:openapi:export --output=var/openapi.json
  outDir: "app/api-schema",
  preset: "api-platform",
  strip: { contentTypes: ["text/csv"] },
})

On top of the core, the preset:

  • removes the schemas of a stripped format. Stripping text/csv also drops Animal.csv, Animal.csv-read, Animal.csv_noid… (same for XML, YAML, HTML, JSON:API, HAL).

  • emits XxxApiEnum (value → IRI) for enums exposed as resources:

    export const GenderApiEnum = {
      MALE: "/api/genders/MALE",
      FEMALE: "/api/genders/FEMALE",
    } as const

    API Platform does not publish those values in the OpenAPI document: a relation to an enum is a plain iri-reference. Two ways to get them:

    1. From the document (recommended). Decorate API Platform's OpenApiFactory so it adds, for each backed enum, a schema with enum, x-enum-name and x-enum-iris. Generation then works offline, from a file.

    2. From the Hydra collections, fetched at generation time. Each member must carry value and @id; the enum is named after the collection's @context.

      apiPlatform: {
        collections: {
          host: "http://localhost:8080", // defaults to the origin of `source` when it is a URL
          paths: ["/api/genders", "/api/roles"],
          headers: { authorization: "Bearer …" },
        },
      },

Configuration

| Option | Default | Description | |----------------------------|------------------|-------------------------------------------------------------------| | source | — | URL or path of the OpenAPI 3.x document (JSON or YAML) | | outDir | — | Output directory | | preset | "openapi" | "openapi", "api-platform", or a custom Preset object | | strip.contentTypes | [] | Content types removed everywhere (content left empty goes too) | | strip.paths | [] | Paths removed — a string matches exactly, a RegExp is tested | | schemaFile | "openapi.json" | Cleaned schema, relative to outDir; false to skip | | types.fileName | "api-schema.ts"| openapi-typescript output, relative to outDir | | types.options | {} | Passed as-is to openapi-typescript | | types | | false to skip the types | | enums.dir | "enums" | Enum directory, relative to outDir | | enums.inline | false | Also generate enums declared inline on a property | | enums.asConst | true | Add as const to the constants | | enums | | false to skip the enums | | apiPlatform.collections | — | See above |

After cleanup, any local $ref that no longer resolves is an error: a too-broad strip fails loudly instead of producing broken types.

Files are only rewritten when their content changes. In the enum directory, files that were generated (they carry the Generated by api-dumper marker) and no longer are get removed; a hand-written file is never touched.

Custom presets

A preset is an object with two optional hooks:

import { defineConfig, type Preset } from "api-dumper"

const internalOnly: Preset = {
  name: "internal",
  // mutate the document after loading, before anything is generated
  transform(document) {
    delete document.components.schemas.Debug
  },
  // complete or replace the enums found in the document
  enums(document, enums) {
    return enums.filter((e) => !e.name.startsWith("Internal"))
  },
}

export default defineConfig({ source: "openapi.json", outDir: "src/api", preset: internalOnly })

Programmatic use

import { generate, run } from "api-dumper"

const { files } = await generate(config, cwd)         // in memory, nothing written
const { changed, removed } = await run(config, { cwd, check: false })

The building blocks (loadDocument, stripContentTypes, collectEnums, renderEnum, generateTypes…) are exported too.

Development

pnpm install
pnpm test        # vitest, against real files and a real local HTTP server
pnpm typecheck
pnpm build

License

MIT