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

@docspack/openapi

v0.2.0

Published

What docspack does with an OpenAPI document: a dense per-operation digest for an agent, code samples and a request builder for a page, and a try-it console.

Readme

@docspack/openapi

What docspack does with an OpenAPI document.

Reading the document and rendering it as LAPIS is @docspack/lapis, which is publishable on its own because that conversion is useful to people who will never touch docspack. This package is everything built on top of it — and it re-exports the model, so you need one import rather than two:

  • for an agent — a dense per-operation digest: the base URL, the credential, the inputs with their types, the body shape, the response, the failures and a runnable curl call, in LAPIS notation;
  • for a person — a request builder and code samples in cURL, JavaScript, Python and Go, plus the behaviour for a try-it console.

Both come from the same parse and the same request builder, so a sample on a page, the request the console sends and the example an agent is answered with cannot disagree.

Its only dependency is @docspack/lapis, whose main entry has none of its own, so this runs in the CLI and in a browser alike.

import { parseOpenApi, operationDigest, codeSamples, toGroups } from "@docspack/openapi";

// `parseOpenApi` and `toGroups` come from @docspack/lapis, re-exported here.
const document = parseOpenApi(JSON.parse(await readFile("openapi.json", "utf8")));
const [operation] = document.operations;

operationDigest(document, operation); // the dense text an agent gets
codeSamples(document, operation); // cURL, JavaScript, Python, Go
toGroups(document); // operations grouped by tag, for a sidebar

Why a digest rather than the document

An agent handed an OpenAPI document is handed every operation in the API to answer a question about one. Measured against Stripe's published spec — 594 operations, 1,454 schemas, 8.0 MB of JSON:

| | estimated tokens | | --- | --- | | The whole document, as published | 2,007,014 | | The whole document, as LAPIS | 193,593 | | One operation's digest (median) | 830 |

Against the smallest correct slice of OpenAPI JSON for a single operation — the operation, the schemas it references, its security scheme and its server — a digest is about 72% smaller (tests/digest.test.ts holds that number to a floor).

Three limits make that possible, and each of them exists because its absence was measured:

  • Named types are carried by name. The full transitive closure from one Stripe operation reaches most of the API, because every object has an expandable field pointing at another: digests came out at 66,500 tokens each. The walk is breadth-first from the operation's own schemas and stops at a token budget, naming what did not fit.
  • Inline objects expand two levels and list twelve fields. A document that names nothing pays for it here.
  • Enumerations list eight members. Stripe's merchant-category enum has 297 and appears four times in one operation — 25,637 characters on one line.

Anything elided is counted (+32 more, # not expanded here: …), because "there is more to this shape" and "this is the whole shape" are different claims.

LAPIS, and where the digest differs from it

LAPIS (v0.1.0, CC BY 4.0) is an open format for describing an API to a language model. It is adopted rather than replaced by a notation of our own: a format a model has already seen is one it parses without being taught, and the saving is structural either way. The renderer, and its one documented extension, are in @docspack/lapis.

Two further deviations belong to the digest specifically, because it describes one operation rather than a whole API:

  1. Errors are listed per digest, as <status> <Type> # <description>, rather than in a document-wide [errors] section with @ops: bindings. toLapis — the whole-document rendering — does emit the centralized form, which is where LAPIS's largest single saving comes from.
  2. The success status rides along as a # comment on the < line. LAPIS's output marker carries a type and nothing else, and 201 versus 204 changes what a caller does next.

The try-it console

@docspack/openapi/console is a DOM module, not a component:

import { mountApiConsoles } from "@docspack/openapi/console";

mountApiConsoles(); // claims every [data-api-console] on the page

The markup renders statically — a labelled, filled-in form showing exactly what the endpoint takes — and this makes the Send button work. The credential is never stored: it is read from the field at send time and kept in nothing that outlives the request. No localStorage, no sessionStorage, no cookie.

@docspack/sheaf-react renders markup this module understands.

Licence

MIT. The LAPIS specification is CC BY 4.0 and belongs to its authors; this package implements a renderer for it.