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

@routegraph/docs

v1.0.0

Published

Self-contained interactive docs UI for RouteGraph, plus static export — no React, no CDN, no build step.

Readme

@routegraph/docs

Self-contained, interactive API documentation for RouteGraph — no React, no CDN, no build step. Renders directly from your routes' Zod schemas.

Installation

pnpm add -D @routegraph/docs

zod is a peer dependency (^4.0.0 — narrower than @routegraph/core's range, since this package imports Zod's exported classes as runtime values for schema rendering; see DECISIONS.md).

createDocsMiddleware(graph, options?)

function createDocsMiddleware(graph: RouteGraph, options?: DocsMiddlewareOptions): DocsMiddleware
// DocsMiddleware = (req: { method?; url? }, res: { statusCode; setHeader; end }, next: () => void) => void

interface DocsMiddlewareOptions {
  basePath?: string   // where the adapter's router is actually mounted, e.g. '/api' — used only
                        // so the UI's Try It Out panel builds correct request URLs
}

createDocsMiddleware returns a plain Connect-style middleware — it works with any framework whose request/response objects structurally match { method?, url? } / { statusCode, setHeader, end }, which Node's raw IncomingMessage/ServerResponse satisfy directly.

Usage with each adapter

Express / Koa / Fastify (via request.raw/reply.raw, which are Node's native req/res):

// Express
app.use('/_routegraph', createDocsMiddleware(graph, { basePath: '/api' }))

// Fastify — hijack the reply so Fastify doesn't also try to send its own response
app.get('/_routegraph/*', async (request, reply) => {
  reply.hijack()
  docsMiddleware(request.raw, reply.raw, () => {})
})

// Koa
app.use(async (ctx, next) => {
  if (!ctx.path.startsWith('/_routegraph')) return next()
  await new Promise<void>((resolve) => docsMiddleware({ method: ctx.req.method, url: ctx.req.url }, ctx.res, resolve))
})

Hono / Elysia (no raw Node req/res — bridge manually):

function createHonoDocsMiddleware(graph: RouteGraph, options?: DocsMiddlewareOptions) {
  const docsMiddleware = createDocsMiddleware(graph, options)
  return async (c: Context, next: Next) => {
    let status = 200, headers = new Headers(), body: string | undefined, skipped = false
    docsMiddleware(
      { method: c.req.method, url: c.req.path },
      {
        get statusCode() { return status }, set statusCode(v) { status = v },
        setHeader: (k, v) => headers.set(k, v),
        end: (chunk) => { body = chunk },
      },
      () => { skipped = true }
    )
    if (skipped) return next()
    c.res = new Response(body ?? null, { status, headers })
  }
}
app.use('/_routegraph/*', createHonoDocsMiddleware(graph, { basePath: '/api' }))

See examples/with-express/index.hono.ts and index.elysia.ts for the complete, working versions of this bridge. routegraph dev mounts docs automatically for Express, Fastify, and Koa; for Hono and Elysia you currently need to wire it yourself, as above.

exportDocs(graph, outDir, options?)

function exportDocs(graph: RouteGraph, outDir: string, options?: DocsMiddlewareOptions): Promise<void>

Writes a single self-contained outDir/index.html — the route payload is inlined as a <script> data block rather than fetched live, so the file works when opened offline or hosted as a static asset with no server behind it. routegraph export-docs (no --format flag, or --format ui) calls this.

renderSchema(schema)

function renderSchema(schema: ZodTypeAny): SchemaNode

Walks a Zod schema (via instanceof checks against Zod's exported classes — ZodString, ZodObject, ZodOptional, etc.) into a plain, serializable tree the UI renders as text:

renderSchema(z.object({ id: z.string().uuid(), role: z.enum(['admin', 'user']).optional() }))
// {
//   type: 'object',
//   fields: {
//     id: { type: 'string', format: 'uuid' },
//     role: { type: 'enum', enum: ['"admin"', '"user"'], optional: true },
//   },
// }

This is a separate, independent implementation from @routegraph/core's zod-to-jsonschema.ts (used for OpenAPI export) — see DECISIONS.md for why both exist.

What the UI shows

  • Sidebar: a search box, method filter chips (ALL/GET/POST/PUT/PATCH/DELETE), and the route list grouped by each route's tags (untagged routes group under "Untagged", sorted last).
  • Detail panel: method + path, description, tags, a deprecation banner for routes with deprecated: true, tabbed request schema (params/query/body/headers — whichever are declared) and tabbed response schema (by status code), each rendered as a type tree.
  • Try It Out: a form (base URL, path params, query params, JSON body for POST/PUT/PATCH, headers) that fires a real fetch() against your running server and displays status, timing, and the response body, with copy/clear actions.

Dark/light mode

A theme toggle in the navbar persists the choice to localStorage (routegraph-theme) and defaults to the OS prefers-color-scheme on first load.

Production warning

The docs UI is a development tool — it exposes your full route list, request/response schemas, and a live Try It Out panel that can fire real requests against your server. Gate createDocsMiddleware() behind an environment check (process.env.NODE_ENV === 'development' or equivalent) rather than mounting it unconditionally in production.