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

@suluk/docs

v0.1.4

Published

Generate an intuitive static documentation site for a Bun/TS monorepo, straight from source (package.json + doc-comments + exports + README/ARCHITECTURE). Deployable to GitHub Pages. CANDIDATE tooling.

Readme


CANDIDATE tooling — not official OpenAPI. Suluk is a single-contributor candidate for OpenAPI Specification v4.0 ("Moonwalk"), unaffiliated with the OpenAPI Initiative and unable to ratify anything on the SIG's behalf.

Install

bun add @suluk/docs

What it does

It harvests a Bun/TS workspace into a documentation model and renders it to a flat, self-hosting site — the same "one source, many projections" discipline as the rest of Suluk, applied to the monorepo itself.

  • Harvests from source. For each package directory it reads package.json (name / description / version / deps), the leading doc-comment of src/index.ts as the overview, the public exports of that barrel, and each module's leading doc-comment. No extra annotations — it uses the comments the code already carries.
  • Renders a complete site. A landing page, one page per package (install + overview + public API + deps + modules), an Architecture page with a generated package-dependency diagram, plus curated Get-started / Contributing / Community pages.
  • Zero-build output. Plain HTML + one stylesheet + a .nojekyll, with relative links — drop the files on GitHub Pages (even a project-pages subpath) and it serves verbatim. Suluk documents itself this way.
  • Composable primitives. A small dependency-free Markdown→HTML renderer (mdToHtml) and a D2 package-graph + kroki URL helper are exported on their own.

When to reach for it

Reach for it to document the monorepo / toolkit itself — the packages, how they depend on each other, what each one exports. It reads structure from package.json + barrel doc-comments, so it stays in sync as you add packages.

It does not document your API. For an OpenAPI v4 reference site use @suluk/reference / @suluk/scalar / @suluk/swagger (those project the v4 document; this projects the codebase).

Usage

The common case is two calls — harvest a packages directory into a FrameworkDoc, then generateSite it into files you write to disk.

import { harvest, generateSite } from "@suluk/docs";
import { writeFileSync, mkdirSync } from "node:fs";
import { join, dirname } from "node:path";

const fw = harvest({
  packagesDir: join(import.meta.dir, "packages"),
  title: "Suluk",
  tagline: "One typed contract — projected into your entire stack.",
  description: "**Suluk** derives the whole stack from one source.",
  repoUrl: "https://github.com/MahmoodKhalil57/suluk",
  architecturePath: join(import.meta.dir, "ARCHITECTURE.md"), // optional — prepends to the Architecture page
  // excludePrivate: true,   // drop demo/private packages from the public docs (default: include, flagged)
});

const out = join(import.meta.dir, "site");
for (const f of generateSite(fw)) {
  const p = join(out, f.path);
  mkdirSync(dirname(p), { recursive: true });
  writeFileSync(p, f.content);
}
// → site/index.html, site/<pkg>.html, site/architecture.html, site/style.css, site/.nojekyll, …

generateSite returns SiteFile[] ({ path, content }) — no I/O of its own, so you own where the bytes land. Override the curated pages by passing Markdown:

generateSite(fw, {
  gettingStarted: "# Get started\n\nYour own intro…",
  contributing: "# Contributing\n\n…",
  community: "# Community\n\n…",
});

Harvest one package, or render one page

The harvest and render steps are exposed individually:

import { harvestPackage, renderIndex, renderPackage } from "@suluk/docs";

const pkg = harvestPackage("./packages/core");  // → PackageDoc | null (null if no package.json)
const indexHtml = renderIndex(fw);              // the landing page
const pageHtml = renderPackage(fw, fw.packages[0]); // one package page

The standalone primitives

import {
  mdToHtml, parseExports, firstBlockComment,
  packageGraphD2, krokiD2Url, STYLE,
} from "@suluk/docs";

mdToHtml("# Hi\n\n`code`, **bold**, and a [link](https://suluk.dev)"); // → HTML string
parseExports(`export { a, b as c } from "./x";`);                     // → ["a", "c"]
firstBlockComment("/**\n * one\n * two\n */");                        // → "one\ntwo"

const d2 = packageGraphD2(fw.packages); // D2 of the @suluk dependency graph (private pkgs omitted)
krokiD2Url(d2);                         // → https://kroki.io/d2/svg/… (deflate+base64url, renders the diagram)
STYLE;                                  // the site's single stylesheet, if you assemble pages yourself

API

| Export | What it does | | --- | --- | | harvest(opts) | Read a packages dir → FrameworkDoc (every package's name, overview, exports, deps, modules). | | harvestPackage(dir) | Harvest a single package dir → PackageDoc \| null. | | generateSite(fw, opts?) | Assemble the whole site → SiteFile[] ({ path, content }); no I/O. | | renderIndex(fw) | Render just the landing page → HTML. | | renderPackage(fw, p) | Render one package page → HTML. | | renderMarkdownPage(fw, file, title, md) | Render a curated Markdown page into the site chrome → HTML. | | mdToHtml(md) / inline(text) / escapeHtml(s) | Dependency-free Markdown / inline-span / HTML-escape helpers. | | parseExports(src) | Collect the public symbol names a barrel re-exports. | | firstBlockComment(src) | Extract + clean the first JSDoc block comment. | | packageGraphD2(packages) | D2 source for the @suluk package-dependency graph. | | krokiD2Url(d2) | A kroki.io render URL for D2 source. | | STYLE | The site's single stylesheet (string). |

Types: FrameworkDoc, PackageDoc, ModuleDoc, HarvestOptions, SiteOptions, SiteFile.

Boundary

This package renders, never hosts (the L3 line). generateSite returns the files; you write them and serve them (GitHub Pages, any static host). It reads from a directory of packages and emits HTML strings — no network in the harvest/render path, and the only outbound URL it constructs is the kroki render link for the architecture diagram. What it documents is the codebase (package structure + doc-comments), not your runtime API — that projection belongs to @suluk/reference / @suluk/scalar / @suluk/swagger.

License

Apache-2.0