A Deno Deploy dashboard that tracks npm downloads by package version. It exists because package-total trend tools do not show how downloads move between releases.
The dashboard is seeded with modern-web-guidance.
A top-level Deno.cron() runs every day at 04:17 UTC. For each tracked package it fetches:
api.npmjs.org/versions/{package}/last-week— rolling seven-day counts by version;api.npmjs.org/downloads/point/last-week/{package}— exact inclusive window and package total;api.npmjs.org/downloads/point/last-day/{package}— exact latest daily package total;registry.npmjs.org/{package}/latestand, when needed, the packument — current release and publication dates.
The collector performs three-way reconciliation: per-version sum vs point total, daily range sum vs point
total, and exact window alignment across sources. It records healthy, delayed, or mismatch rather than
silently accepting inconsistent data. One package failure is retained without dropping successful package
results.
Snapshots are keyed by npm's reported window end date, so a retry is idempotent. Version maps are split into bounded Deno KV chunks, checksummed, then made visible by an immutable manifest. A distributed KV lock prevents overlapping cron/manual runs.
On first collection, exact daily package totals are backfilled from the package's publication date in bounded 365-day range requests. npm-wide daily totals are backfilled to 2015-01-10 and retained as a global anomaly/normalization baseline. Subsequent runs only fetch missing days. Unscoped packages use bulk point/range requests in groups of at most 128, with automatic individual fallback; scoped packages remain isolated because npm does not support them in bulk.
npm exposes per-version counts only for a rolling seven-day period. last-day, last-month, last-year, and
custom date ranges are not supported by the per-version endpoint.
There is no historical per-version backfill. Daily snapshots provide an honest rolling version-share series, but they do not uniquely identify exact daily counts for versions that predate tracking:
W[t,v] - W[t-1,v] = D[t,v] - D[t-7,v]
Package-total history can be backfilled through npm's range API, but that cannot reconstruct historical version shares. Any future per-version daily estimates must be labelled inferred and retain the raw observations.
Requires Deno 2.8+.
deno task collect
deno task devOpen http://localhost:8000/.
Checks:
deno fmt --check
deno lint
deno task check
npm testThe dependency-free Node scripts and JSON snapshot remain as a static/prototype compatibility path; Deno
Deploy uses server.ts, Deno KV, and Deno.cron().
- Create a Deno Deploy app from this GitHub repository.
- Use
server.tsas the production entrypoint. - Attach a Deno KV database/timeline if the project setup does not provision one automatically.
- Deploy. Deno discovers the top-level daily cron registration.
- Optionally set
ADMIN_TOKENas an encrypted environment variable. This enables an authenticated manual collection:
curl -X POST \
-H "Authorization: Bearer $ADMIN_TOKEN" \
https://YOUR_APP/api/admin/collectWithout ADMIN_TOKEN, the manual endpoint returns 404. The cron does not need a secret.
Health and data endpoints:
GET /healthzGET /api/dashboard— version snapshots, exact daily package history, and npm-wide baseline
Edit config/packages.json:
{
"packages": [
{
"name": "modern-web-guidance",
"label": "Modern Web Guidance",
"group": "Chrome DevRel",
"important": true
},
{
"name": "@scope/package",
"label": "A scoped package",
"group": "Team name"
}
]
}Scoped names are encoded as a single URL segment when querying npm. A future authenticated UI can add per-user package-follow records without duplicating package observations.
Charts are visual summaries. Every chart has a semantic table containing the same data. The page uses native controls, landmarks, visible focus, responsive intrinsic layout, reduced-motion handling, and bounded horizontal overflow for wide tables/charts.
- static responses use a restrictive Content Security Policy and browser security headers;
- the manual collection endpoint is absent unless
ADMIN_TOKENis configured; - package names originate from trusted config/KV records and are encoded before upstream requests;
- there is no anonymous mutation endpoint;
- collection has timeout, bounded retries, a lock, immutable manifests, checksums, and per-package failure isolation.
Apache-2.0