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

dashctl

v0.1.0-beta.0

Published

Compile dashboard.yaml into a single self-contained static HTML dashboard.

Downloads

20

Readme

dashctl

Compile a dashboard.yaml into a single self-contained static HTML dashboard. Tableau-style grid layout. Observable Plot charts. Live or snapshot data (CSV / Parquet / DuckDB-WASM / HTTP / BigQuery).

dashctl build dashboard.yaml -o dashboard.html

One YAML in, one HTML out. Drop it on S3, attach it to an email, open it from Finder. There is no runtime server, no SaaS, no tracker. The format is small, declarative, and easy to write by hand or by LLM.

Status: v0 in active development. See SPEC.md for the language reference and design decisions.

30-second pitch

# dashboard.yaml
title: Sales
sources:
  orders: { type: csv, url: ./orders.csv }
panels:
  - row:
      - type: kpi
        title: Total revenue
        source: orders
        query: SELECT SUM(amount) AS [value] FROM orders
        format: currency
      - type: line
        title: Revenue over time
        source: orders
        query: SELECT date, SUM(amount) AS revenue FROM orders GROUP BY date
        x: date
        y: revenue
$ dashctl build dashboard.yaml -o dashboard.html
$ open dashboard.html

Quick start

npm install -g dashctl
dashctl init my-dashboard
dashctl build my-dashboard/dashboard.yaml -o dash.html

Demo & landing

  • Polished demo: examples/demo/ — three pages (Overview, Geography, Trends), 5 filter types, cross-filtering, custom indigo/coral theme, ~2500-row synthetic e-commerce dataset. Build it with dashctl build examples/demo/dashboard.yaml -o demo.html.
  • Landing page: landing/index.html — plain static HTML, no build step. Open it in a browser.

Monorepo layout

packages/
  schema/    Zod source-of-truth → JSON Schema + TS types + runtime validator
  cli/       commander-based CLI: init, dev, build, validate, sources pull
  runtime/   Svelte components for each panel type (kpi, line, bar, table, ...)

examples/
  hello/             Minimal CSV-backed example to validate the spec end-to-end
  sales/             Multi-page Phase 2 example with cross-filter on bar/table
  duckdb/            DuckDB-WASM live source
  bigquery/          BigQuery via `dashctl serve` proxy (ADC auth) — primary BQ mode
  bigquery-oauth/    BigQuery via browser OAuth direct — niche internal-team mode
  filters-showcase/  One panel per filter type
  demo/              Polished hero example (custom theme, 3 pages, generated data)

landing/   Hand-written static HTML landing page (not built by dashctl)
docs/      (placeholder — built with dashctl itself, eventually)

Development

npm install
npm run typecheck
npm run build
npm run cli -- build examples/hello/dashboard.yaml -o /tmp/hello.html

DuckDB-WASM (~140 MB) is an optionalDependency — needed only for dashboards declaring a duckdb-wasm source. To skip it, run npm install dashctl then rm -rf node_modules/@duckdb. (Plain --omit=optional also drops vite/rolldown's platform-native bindings and breaks builds.)

BigQuery in 30 seconds

gcloud auth application-default login
dashctl serve dashboard.yaml --port 8080

The bundled HTML's BQ queries route through the local server's /api/bq, which authenticates via your gcloud login (no service-account JSON, no browser OAuth setup, no @google-cloud/bigquery install). A SHA-256 query allow-list is built from the YAML at compile time so the proxy can only run queries the dashboard's author already approved. See examples/bigquery/ for the full setup. For the older browser-OAuth-direct mode (every viewer signs into Google), see examples/bigquery-oauth/.

To expose dashctl serve publicly, gate viewers with Google OAuth:

dashctl serve dashboard.yaml --auth google \
  --google-client-id 1234.apps.googleusercontent.com \
  --google-client-secret $DASHCTL_GOOGLE_CLIENT_SECRET \
  --google-domain example.com \
  --session-secret $DASHCTL_SESSION_SECRET

Sessions are stateless HMAC-signed cookies (no server-side store). At least one of --google-domain or --google-allow [email protected],... is required.

Roadmap

  • Phase 4 — DuckDB-WASM as the default in-browser engine (replaces alasql), removes the bracketed-keyword and quoting workarounds.
  • Phase 5dashctl publish (S3 / Pages / Vercel one-shot) + signed snapshots.
  • Phase 6 — write-mode panels (notes, annotations) and shared filter URLs.

SQL gotchas

Phase 2 still uses alasql (now in the browser). It treats value, key, order, name, etc. as reserved when used as AS aliases. Bracket them: SELECT SUM(amount) AS [value] FROM .... A future phase will swap to DuckDB-WASM and remove this constraint.

Filter values are bound into queries as safe-quoted SQL literals (single quotes doubled, dates as 'YYYY-MM-DD', arrays as ('a','b','c') for IN-lists). See packages/runtime/src/runtime.ts for the full substitution table.

Cross-filtering scope

Phase 2 ships cross-filtering for bar charts (click a bar to set the named filter) and table rows (declare on_click: { filter: <name>, from: <column> }). Line/area cross-filtering will follow in a later phase — Plot's pointer interactions for line marks are noisier and not worth blocking the milestone on.

License

MIT