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

@apisurf/canonui

v0.2.1

Published

canonui — build and preview the documents that canon holds: render one into static HTML, or serve it locally.

Readme

@apisurf/canonui

The canonui command: build and preview the documents that canon holds.

npm i -g @apisurf/canonui
canonui ls                     # what is in the database, and what to build
canonui build retry-guide      # -> ./dist/retry-guide
canonui serve retry-guide      # build it, then open it in a browser
canonui serve                  # every document, behind a list of them
canonui open ./public          # serve a folder that is already built
canonui help

Four commands, none of which writes anything. canon is the agent's half of the pair — it creates and edits content, one record per command — and this is the human's: it opens the same database read-only, says what is in it, and turns a document into a folder of static files.

It is usable on its own. canonui ls prints the slugs the other commands take, and build and serve resolve the only document themselves when there is one — so nothing here sends you to canon to find out what to type.

Everything is documented in the command itself — canonui help, then canonui help <command> — and in the repository README.

What is in here

Two halves of one package, and the seam between them is a JSON file.

| File | What it is | | ---------------- | -------------------------------------------------------------- | | src/bin.ts | Argument parsing and dispatch. One parser per command | | src/list.ts | ls, and the document build picks when given none | | src/db.ts | Opening the file canon owns, read-only and unmigrated | | src/build.ts | Open the database, reduce a document to a snapshot, render it | | src/serve.ts | serve — build a document, or all, then hand it to the server | | src/home.ts | The page listing every document, in front of serve's builds | | src/open.ts | open — work out which built folder was meant | | src/http.ts | The static file server both of them end at | | src/render.ts | Spawning Astro with the theme, parameterised by environment | | src/help.ts | Every help page. One screen each | | src/howto.ts | Worked examples: preview, publish, snapshot | | src/format.ts | The listing ls prints, and its JSON | | src/version.ts | The build's version, and the schema it expects | | theme/ | The Astro theme — the only part that renders anything |

Only src/ links against SQLite, and only theme/ knows what HTML is. That is what lets canonui build --snapshot-only hand the same input to some other renderer, and what lets the theme be worked on without a database in reach.

The theme

One document builds into one page. One layout with three named slots (head, aside, footer) and a default behind each, one component per block type, and one stylesheet of plain CSS with tokens on :root.

The page is two columns: the document — title, description, a copy button, then every block in order — and a rail listing its titled blocks and the headings inside markdown blocks. There is no framework, and the client-side runtime is five small scripts: the wide toggle, the copy button, the one that puts it under each section's heading, the rail's scroll tracking, and mermaid when the document holds a diagram — bundled into the site rather than fetched from a CDN, so it works offline.

| File | What it is | | ------------------------------------ | --------------------------------------------------- | | theme/layouts/Site.astro | The shell, and every slot a theme would replace | | theme/components/Block.astro | One block, drawn according to its type | | theme/components/Toc.astro | The contents rail | | theme/components/Copy.astro | The button that copies the document as markdown | | theme/components/SectionCopy.astro | The same button, twice under each section's heading | | theme/pages/index.astro | The document, at / | | theme/styles/theme.css | The whole of the styling | | theme/lib/snapshot.ts | The snapshot, read once at build time |

The markdown twin

/index.md is written by the command rather than the theme, with bundleDocument — the same function behind canon cat, so what a reader copies out of the site is byte for byte canon cat --toc --no-meta. The theme builds on a machine that has no workspace to resolve that function from; the command already carries it, which is what keeps the site and the CLI one renderer. The copy button fetches it rather than embedding it, so the button wants the site served rather than opened off the disk, where fetch has no origin to work from; everything else on the page works either way.

Each top-level section is written the same way, to /sections/<anchor>.md, with bundleSection. Where the sections fall is theme/lib/sections.ts, which the command imports so that the files it writes and the headings the page puts buttons on are cut by the same parse.

The theme sits under theme/ rather than Astro's default src/, which this package uses for the command itself. astro.config.mjs points srcDir at it.

Build parameters

src/render.ts passes these to Astro as environment variables, so the package stays immutable at build time and two builds cannot race over a config file.

| Variable | What it sets | | ----------------- | ----------------------------------------------- | | CANON_SITE_DATA | Path to the snapshot JSON. Required | | CANON_OUT_DIR | Absolute path to write the site to. Required | | CANON_BASE | Sub-path the site is served under, e.g. /docs | | CANON_SITE_URL | Canonical origin, for absolute URLs | | CANON_HOME | Href of the list of documents, for a link back |