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

specshot

v3.0.6

Published

Fire an OpenAPI spec, get strictly-typed TypeScript code and a robust API mock server — zero-dependency, Zod-validated, and highly customizable.

Readme

SpecShot

One command. Zero dependencies. 100% type-safe API client.

Drop an OpenAPI spec in, get production-ready TypeScript out. No SDKs to install. No generated bloat to maintain. You own every line — like shadcn/ui, but for your API layer.


Why SpecShot?

| Instead of... | You get... | | ---------------------- | --------------------------------------------------- | | Vendor lock-in SDKs | Code you own, edit, and extend | | Black-box generators | 100% customizable Handlebars templates | | Hardcoded architecture | Bring your own patterns (Classes, Hooks, Functions) | | Untyped fetch() | Strictly typed endpoints and models |

What you get

  • Template-Driven Engine — SpecShot doesn't dictate your architecture. It ships with robust built-in presets (class, functional), but you can easily eject and modify the Handlebars templates to match your exact team standards.
  • Custom Code Preservation — Write your own custom methods directly inside the generated files using magic comments (// --- CUSTOM CODE START ---). Your code survives the next generation.
  • 100% Code Ownership — Generate it once, own it forever. No proprietary libraries or hidden runtime dependencies injected into your project unless your chosen template requires them.
  • Built-in Mock Server — Instantly spin up a local Mock API dashboard that serves realistic data generated from your OpenAPI spec.

30 Seconds

# 1. Scaffold the core
npx specshot init

# 2. Point at your spec
npx specshot generate --url http://localhost:8080/openapi.json

# 3. Use it
import { clientApi, defaultClient } from "./lib/api/default";

// Override the base URL if needed
defaultClient.options.baseUrl = "https://api.myprod.com";

// Everything is typed — no generics, no casting
const { data, error, ok } = await clientApi.pets.listPets();
const { data: pet } = await clientApi.pets.getPet("abc123");
const result = await clientApi.pets.createPet({
  name: "Buddy",
  species: "dog",
});

That's it. No config files. No code generation pipelines. Just typed API calls.


Commands

1. init (One-time setup)

Creates a specshot.config.mjs configuration file with your preferences. No files are installed — generate handles all installation.

Interactive mode:

npx specshot init

Non-interactive mode (CI/CD friendly):

npx specshot init \
  --preset class \
  --url http://localhost:8080/openapi.json

| Flag | Description | | ----------------------- | ------------------------------------------------------- | | --preset <name> | Preset: class, functional, or community/custom | | --templates, -t <dir> | Custom Handlebars templates directory | | --url, -u <url> | OpenAPI JSON URL to save in config for later generation |

2. generate (Run repeatedly on API updates)

Installs the API core infrastructure (if missing), then reads your OpenAPI spec to generate strictly-typed API services, Zod schemas, and models.

Presets

Choose a built-in code style with --preset:

| Preset | Style | Dependencies | Result pattern | | ------------------------------------------------------ | ---------------------------------------------- | ------------ | ------------------------------ | | class (default) | BaseService + ApiClient + Zod | zod | Promise<{ data, error, ok }> | | functional | Standalone async function + native fetch() | none | Promise<T> (throws on error) |

npx specshot generate --preset functional

Or set it in config:

export default {
  preset: "functional",
  apis: { ... }
};

If you already provided a --url during init (which saves it to specshot.config.mjs), you can simply run:

npx specshot generate

(No flags or prompts required! Perfect for an npm run api:sync script.)

Or, if you want to override the source:

npx specshot generate --url http://localhost:8080/openapi.json

Auto-install: When using built-in templates, generate automatically installs the API Core (ApiClient, BaseService, types) and Provider skeleton (client.ts, plugins, hooks) if they don't already exist. When using custom templates, infrastructure installation is skipped.

generate options

| Flag | Description | | ----------------------- | ---------------------------------------------------------- | | --url, -u <url> | Remote OpenAPI spec URL | | --file, -f <path> | Local OpenAPI JSON file | | --output, -o <dir> | Output directory | | --alias, -a <alias> | Import alias (e.g. @/lib/api) | | --config, -c <path> | Custom config file path | | --templates, -t <dir> | Custom Handlebars templates (partial override) | | --preset <name> | Built-in preset: class, functional | | -w, --watch | Watch for changes and auto-regenerate | | --dry-run | Preview without writing files | | --msw | Generate MSW mock handlers | | --force-scaffold | Force regenerate scaffold files, overwriting existing ones |

3. templates (Manage Handlebars templates)

Subcommands for template management:

templates eject

Copies a built-in or community preset to your project as a custom preset so you can customize it. Only the templates you edit will override the built-ins — missing files automatically fall back to defaults.

npx specshot templates eject class
npx specshot templates eject functional --output ./my-templates

| Flag | Description | | -------------------- | ---------------------------------------------------------- | | --output, -o <dir> | Output directory (default: .specshot/templates/presets/) | | --generator-only | Eject only generator templates | | --msw-only | Eject only MSW templates |

templates list

Shows all available templates and their current override status (built-in / dir override / per-file override).

npx specshot templates list

templates context <name>

Shows all available variables and naming helpers for a specific template.

npx specshot templates context service
npx specshot templates context models

templates install <package>

Install a community preset from npm or GitHub:

npx specshot templates install github:user/my-preset

templates uninstall <preset>

Remove an installed community preset:

npx specshot templates uninstall my-preset

templates validate

Validate preset structure and _preset.json for community templates:

npx specshot templates validate

Then generate with your custom templates:

npx specshot generate --templates ./my-templates

Template structure

my-templates/
  models.hbs              # Generator: shared Zod schemas + types
  types.hbs               # Generator: per-tag request/response types
  service.hbs             # Generator: per-tag service class
  index.hbs               # Generator: provider index + clientApi export
  plugins-index.hbs       # Generator: plugin auto-wiring
  msw/
    handlers.hbs          # MSW: per-tag http.<method>() handlers
    index.hbs             # MSW: handler barrel export
    browser.hbs           # MSW: setupWorker entry

Partial override

You don't need to copy all templates. Place only the files you want to customize in your override directory. Any missing file will use the built-in default automatically.

For example, to customize only the service template:

my-templates/
  service.hbs    # Your custom version
npx specshot generate --templates ./my-templates
# models.hbs, types.hbs, index.hbs → built-in defaults
# service.hbs → your custom version

Template context

Templates use standard Handlebars syntax. Key variables available:

| Template | Context variables | | -------------- | ------------------------------------------------------------------------------------- | | models.hbs | schemas (shared), version, customCode | | types.hbs | tag, imports, specificSchemas, operations, customCode | | service.hbs | className, tagPrefix, exportsToReExport, operations, corePath, customCode | | index.hbs | services, corePath, pluginsPath, customCode | | handlers.hbs | tag, tagLowerCase, handlers, typeImports, usesFaker, typesImportPath |

Each generated file preserves a // --- CUSTOM CODE START --- / // --- CUSTOM CODE END --- block so your hand-written code survives regeneration.

Handlebars naming helpers

Custom templates can use built-in naming helpers:

| Helper | Example input | Output | | ------------- | ------------------------------------- | ------------------- | | capitalize | pets | Pets | | camelCase | pet-store | petStore | | pascalCase | pet-store | PetStore | | kebabCase | PetStore | pet-store | | snakeCase | PetStore | pet_store | | toLowerCase | PetStore | petstore | | toUpperCase | petstore | PETSTORE | | ifEq | {{#ifEq tag "pets"}}...{{/ifEq}} | Conditional block | | ifNeq | {{#ifNeq tag "users"}}...{{/ifNeq}} | Negated conditional |

File naming configuration

Control generated file names via fileNaming in config:

export default {
  apis: {
    petstore: {
      openapiUrl: "./openapi.json",
      fileNaming: {
        models: "schemas", // → schemas.ts
        service: "{{pascalCase tag}}Service", // → PetsService.ts
        types: "{{pascalCase tag}}Types", // → PetsTypes.ts
        index: "index", // → index.ts
      },
    },
  },
};

Custom output paths

Control WHERE generated files go via outputPaths in config:

export default {
  apis: {
    default: {
      openapiUrl: "./openapi.json",
      outputPaths: {
        models: "src/models",
        services: "src/services",
        types: "src/types",
        index: "src/api",
      },
    },
  },
};

Import paths between files are computed automatically. See docs/template-variables.md for full reference.

Editor autocompletion

SpecShot provides autocompletion for both config files and templates:

Config files (specshot.config.mjs):

/**
 * @typedef {Object} TemplateData
 * @property {"react-query" | "swr" | "none"} [hook] - Hooks framework
 * @property {("bearer" | "logger" | "request-id" | "circuit-breaker")[]} [pluginNames] - Plugins to generate
 * @property {"types-only" | "zod-schemas" | "zod-runtime"} [validation] - Validation strictness mode
 */
/** @type {import('specshot').SpecshotConfig<TemplateData>} */
export default {
  // Autocompletion works in VS Code with the TypeScript language server
  preset: "functional",
  apis: {/* ... */},
  templateData: {
    hook: "none",
    pluginNames: [],
    validation: "zod-runtime",
  },
};

For JSON config files (specshot.config.json), add a $schema reference:

{
  "$schema": "https://specshot.dev/config.schema.json",
  "preset": "functional"
}

Template files (.hbs):

mock (Zero-config API Mocking)

SpecShot includes a powerful built-in mock server and Web Dashboard. No MSW or complex setup required.

npx specshot mock --web --proxy http://localhost:3000

| Flag | Description | | ------------------- | -------------------------------------------- | | --web | Launch the interactive Web Dashboard (SPA) | | --proxy, -p <url> | Proxy un-mocked requests to a real backend | | --port <number> | Port for the mock API server (default: 3457) | | --no-open | Prevent opening the browser automatically |

🎛️ Mock Dashboard Features

When you run with --web, SpecShot opens a beautiful dashboard where you can:

  • Toggle Endpoints: Turn mock responses on/off per endpoint.
  • Set Latency & Errors: Simulate slow networks or 500/400 error states instantly.
  • Customize Data (Faker.js): Use the searchable dropdown to map specific JSON fields to Faker.js functions (e.g., internet.email, image.url).
  • Manual Overrides: Write custom JSON payloads directly in the browser.
  • WebSocket Mocking: Configure WebSocket endpoints and push events to connected clients in real-time from the dashboard.

(Mock configurations and overrides are automatically saved to .specshot/mocks.json so your team can share the same mock state!)

specshot.config.mjs

/**
 * @typedef {Object} TemplateData
 * @property {"react-query" | "swr" | "none"} [hook] - Hooks framework
 * @property {("bearer" | "logger" | "request-id" | "circuit-breaker")[]} [pluginNames] - Plugins to generate
 * @property {"types-only" | "zod-schemas" | "zod-runtime"} [validation] - Validation strictness mode
 */
/**
 * @typedef {Object} Overrides
 * @property {string} [dir]
 * @property {string} [browser]
 * @property {string} [core]
 * @property {string} [handlerPerTag]
 * @property {string} [index]
 * @property {string} [plugins]
 * @property {string} [provider]
 * @property {string} [servicePerTag]
 * @property {string} [typesPerTag]
 */
/** @type {import('specshot').SpecshotConfig<TemplateData, Overrides>} */
export default {
  preset: "class", // class or functional
  templates: "src/lib/api/templates", // string (dir) or object (per-file)

  // Custom Faker.js plugins for mock generation
  fakerPlugins: [
    {
      name: "custom-image",
      match: (ctx) => ctx.path.endsWith("imageUrl"),
      generate: (faker) => faker.image.url(),
    },
  ],

  // Template data passed to all templates
  templateData: {
    hook: "swr", // swr, react-query, or none
    pluginNames: ["bearer", "logger"], // plugins to generate
    validation: "zod-runtime", // strict runtime data validation
  },

  // Define your APIs
  apis: {
    petstore: {
      // openapiUrl supports:
      // 1. Backend URL (e.g., "http://localhost:8080/openapi.json")
      // 2. Local File (e.g., "./openapi.json")
      openapiUrl: "http://localhost:8080/openapi.json",
    },
    payment: {
      openapiUrl: "http://api.staging.com/payment/openapi.json",
    },
  },
};

Examples

| Example | What it shows | | ------------------------------------------------------ | ------------------------------------------------------ | | examples/local-file | Generate from a openapi.json on disk | | examples/remote-url | Fetch from a running backend + mock server | | examples/real-or-fake | Full-stack usage with the mock server | | examples/design-patterns | Singleton, Factory, Observer, Builder service patterns |


Development

npm install
npm run build
npm test
npm run lint

Built by the open-source community