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

@shiftgraph/generate

v0.2.3

Published

TypeScript types AND test fixtures from what an API was actually observed to return. Optionality earned, not assumed. Zero dependencies.

Readme

Canonical source. This package is developed in shiftgraph/observatory under packages/generate, which is where the record it reads is produced and where its published metadata points. This mirror exists because the package was first released from here; it had drifted to source for a version npm never published, which is the opposite of useful, so it now tracks what ships.

@shiftgraph/generate

Your types describe what the docs promise. This generates types from what the API actually returned.

npx @shiftgraph/generate https://api.github.com/repos/facebook/react

No install, no signup, no config. It requests the URL a few times, profiles each response, and writes a .ts file containing TypeScript types and a Zod schema — an artifact you commit, not output you read once.

What it writes

Two files, from one command:

npx @shiftgraph/generate https://api.github.com/repos/facebook/react
Wrote github-com-repos-facebook-react.ts
Wrote github-com-repos-facebook-react.fixture.ts

The type is consulted when your code compiles. The fixture is consulted on every test run, which is far more often, and it is the one that goes stale because time passes rather than because a provider changed anything.

The fixture is typed against the declaration beside it, so a regenerated type that no longer matches is a compile error rather than a test that quietly keeps passing. Its values are placeholders, because the record holds no values: a fixture built from a captured response embeds whatever happened to be in it, and a test asserting against that is asserting against one response rather than against the contract.

Optional fields are present in the fixture. It is the shape your code must handle, and a fixture missing the optional half lets a test pass against a response the interface is entitled to send.

--no-fixture writes the type alone.

Why the types differ from a spec generator's

A specification describes the union of every response an endpoint can produce. Your code receives exactly one shape, conditioned on your credentials, your plan, and the state of the thing you asked for. So a generator reading a spec marks nearly everything optional, and optional-everything types push the work back to you at every call site.

Measured against GitHub's own maintained OpenAPI on 2026-07-26:

spec promises                    105 fields on /repos/{owner}/{repo}
octocat/Hello-World returns       84
facebook/react returns            86

Optionality here is earned. A field is marked optional only where the interface was actually watched omitting it. A field never seen absent is required, because that is what came back.

Usage

# more samples, better evidence for optionality
npx @shiftgraph/generate <url> --samples 5

# fold several resources: each one can only widen the type honestly
npx @shiftgraph/generate https://api.github.com/repos/facebook/react \
  --also https://api.github.com/repos/octocat/Hello-World

# choose the filename
npx @shiftgraph/generate <url> --out src/types/repo.ts

# print instead of writing a file
npx @shiftgraph/generate <url> --stdout

# anything you already have
cat response.json | npx @shiftgraph/generate --stdin --name Widget

Fold across resources, or your types will be too narrow

facebook/react is owned by an organisation and returns organization and custom_properties. octocat/Hello-World is owned by a user and returns neither. Same endpoint, same moment, same credentials, different contract.

A type generated from react alone marks both fields required, which is wrong for any user-owned repo. Fold with --also and they come back correctly optional:

custom_properties?: Record<string, unknown>;
organization?: { ... };

Every generated file records which resources it saw, so the required/optional split is auditable rather than merely confident.

Where this is worse than what you have

Stated first, because you will find out anyway.

  • Where a vendor ships good official types, use theirs. Stripe's and OpenAI's SDKs carry methods, auth handling and documentation. These carry none of that. This is strongest where no types exist at all: MCP tool responses, internal services, and the long tail.
  • Few observations means under-evidenced optionality. Below three, the generated header says so.
  • Error responses are refused. Types from a 4xx would describe the error, not the contract.

MCP tools

Roughly two thirds of MCP tools declare no outputSchema at all, so an agent calling one has a precise specification for the request and nothing for the response it has to reason over.

What they actually return, across the tools we have invoked:

9 of 12   { content: [ { type, text } ] }
3 of 12   { content: [...], structuredContent: {...} }

Where text holds JSON it holds it as a string, so the payload sits three levels below where a reasonable guess looks. This decodes that and types the payload, not just the envelope. The envelope varies per tool rather than per server, so it cannot be learned once and reused.

The generated header

Every file records the source, the observation count, the date range, the field and optional counts, the limits that apply to that specific file, and the exact regeneration command. This file gets committed to your repository, so it has to explain itself to whoever opens it next.

Programmatic use

import { generateModule, toTypeScript, toZod, describeRegeneration } from "@shiftgraph/generate";
import { profileValue, structuralProfile, carryOptionality } from "@shiftgraph/generate/core/shape.js";

describeRegeneration(before, after) returns a field-level list of what changed between two observations, meant to be readable by someone reviewing the regeneration in a pull request.

Zero dependencies. Node 18+. MIT.