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

sitedrift

v0.3.11

Published

Visual review for local and hosted previews: compare DEV and LIVE with Split, Diff, SEO, response deltas, notes, and MCP.

Readme

sitedrift

Catch the drift between dev and live. A zero-build, zero-dependency dev tool that frames your local site and production side-by-side on the same route, locked to the same scroll — then overlays them in difference mode so the only things that light up are the pixels that actually changed.


Quick start

No install — run it with npx (needs Node ≥ 18):

npx sitedrift /pricing \
  --dev http://localhost:4321 \
  --live https://example.com \
  --open

That boots the viewer on http://127.0.0.1:4178, opens it at /pricing, and puts your dev build on the left and production on the right. Type any route in the toolbar and both panes follow.

Install it globally if you reach for it often:

npm i -g sitedrift
sitedrift /pricing -d http://localhost:4321 -l https://example.com -o

Bind securely to loopback while using an existing local DNS name and certificate:

sitedrift / --host 127.0.0.1 --hostname compare.homelab \
  --cert /path/to/fullchain.pem --key /path/to/compare.homelab.key

For a project you use repeatedly, add sitedrift.config.json:

{
  "dev": "http://localhost:4321",
  "live": "https://example.com",
  "author": "joe",
  "open": true
}

Configuration precedence is flag > environment > project file > default. The file is discovered from the current directory upward; --config <file> selects one explicitly.

HTTPS

The default (http://127.0.0.1) just works — loopback is a browser "secure context", so you usually need nothing. When you do want HTTPS:

sitedrift --setup-https   # one-time: generate + trust a local cert
sitedrift --https         # serve over HTTPS from then on

--setup-https uses mkcert if it's installed — that gives a locally-trusted cert with zero browser warnings. If mkcert isn't found it falls back to an openssl self-signed cert and prints the one command to trust it on your OS. Already have a cert? Skip all of this and pass --cert <file> --key <file>.

Cloudflare preview deployments

Turn every non-production Cloudflare Pages deployment into a compact sitedrift review URL. The deployment opens its own preview in DEV Solo mode and can switch to Split, Overlay, or Diff against the configured production site.

Install sitedrift and run the wrapper after your static build:

npm install --save-dev sitedrift@latest
{
  "scripts": {
    "build": "astro build && sitedrift cloudflare --dir dist --live https://example.com"
  }
}

Add one scoped Pages Function:

// functions/__sitedrift/[[path]].ts
export { onRequest } from 'sitedrift/cloudflare';

That is the entire integration. On Cloudflare Pages, the wrapper activates only when CF_PAGES=1 and CF_PAGES_BRANCH is not main. Production builds are left unchanged. Use --production-branch <name> when production is another branch.

Hosted proxies are read-only (GET/HEAD) and fixed to the configured live origin. Frames run the compared site's scripts so interactive previews behave like the deployment; only enable the addon for preview code you trust. Review notes stay in that browser's localStorage; they are not sent to an API, shared with agents, or written to disk. Existing application Functions keep their original routes.

That is two project changes and requires no Cloudflare dashboard settings or bindings. See the complete Cloudflare Pages guide for framework examples, the production guard, security details, and a CI check.

A real Pages deployment

This is the same integration running on jseverino.com. A GitHub branch push created an ordinary Cloudflare Pages preview tied to one repository, branch, commit, and immutable deployment URL:

Cloudflare Pages deployment details for a sitedrift preview

The existing Cloudflare build generated 83 static pages, then the installed sitedrift dependency wrapped those pages before Cloudflare uploaded the assets and scoped Function. There was no separate deployment service or dashboard configuration:

Cloudflare build log showing sitedrift wrapping 83 HTML files

Opening that immutable deployment produces the review UI. DEV is a temporary red-brand branch generated with branding-engine; LIVE is the unchanged navy production site:

Cloudflare preview comparing red DEV with navy LIVE

The source branch was later restored to navy, while the immutable deployment remains a reproducible artifact of the exact reviewed commit.


See the whole review loop

The included example compares a fictional Northstar release candidate against production. It uses realistic release drift: primary CTA, metric values, and a release badge change while the underlying layout stays aligned.

Rebuild these screenshots from the deterministic local showcase:

npm run docs:screenshots

What it does

  • One view switch — Split (divider) · Solo (one pane, Swap flips) · Overlay (stacked). In Overlay an opacity slider blends the panes and Diff (mix-blend-mode: difference) lights up only the changed pixels. Overlay force-locks scrolling so the panes can't drift. Keys: O overlay, D diff.
  • Locked scrolling with one controller (exact pixel or proportional) — no duplicate scrollbars, no bounce. An internal link click mirrors to both panes.
  • Metadata diff + response details — title / description / canonical compared across sides (≠ meta). Each 200/3xx/4xx/5xx/ERR badge shows the response time on hover; click it for DEV/LIVE response, DOM-ready, load, transfer, headers, and deltas.
  • SEO panel — Google-style snippet preview + a ~13-point checklist per pane (title/description length, single H1, canonical, viewport, lang, Open Graph, noindex, image alt…), with a flag showing how many checks fail.
  • Review notes as a shared channel — author/route/side-tagged notes in a JSON file the viewer polls every 4s, so a teammate or an AI coding session can leave notes that appear live. Click a note to jump to its route, copy a per-note deep link, dock or float the drawer, and Send to vault or export Markdown.
  • No runtime dependencies. Node standard library only.
  • Deploy-preview mode for Cloudflare Pages. Preview branches can carry the compact comparison toolbar without changing production output or application API routes.

Keyboard

| Key | Action | |---|---| | O | Toggle Overlay | | D | Toggle the Overlay difference blend | | S | Swap sides | | R | Reload both panes | | 0 | Reset divider to 50/50 | | / | Focus the route field | | Space / ⇧Space | Page down / up (when scrolling is linked) | | | Line scroll both panes | | Esc | Close the notes drawer / open popovers |

Shortcuts work whether focus is in the viewer chrome or inside either pane.


Options

Every option is a CLI flag, and also reads a SITEDRIFT_<NAME> env var.

| Flag | Env | Default | Purpose | |---|---|---|---| | -d, --dev <url> | SITEDRIFT_DEV | http://127.0.0.1:4321 | Left-pane (dev) origin. | | -l, --live <url> | SITEDRIFT_LIVE | required | Right-pane (live) origin. | | -p, --port <n> | SITEDRIFT_PORT | 4178 | Listen port. | | --host <addr> | SITEDRIFT_HOST | 127.0.0.1 | Bind address. | | --hostname <name> | SITEDRIFT_HOSTNAME | bind address | Browser-facing local DNS name; the socket remains bound to --host. | | -o, --open | — | off | Open the viewer in your browser. | | --https | — | off | Serve HTTPS with an auto cert (mkcert if present, else openssl). | | --setup-https | — | — | One-time: generate + trust a local cert, then exit. | | --http | — | — | Force plain HTTP (the default; overrides --https). | | --cert <file> / --key <file> | SITEDRIFT_CERT / _KEY | — | Bring your own cert; if both set, serve over HTTPS. | | --notes <file> | SITEDRIFT_NOTES | $TMPDIR/sitedrift-notes.json | Shared review-notes file. | | --brand <text> | SITEDRIFT_BRAND | — | Strip \| <text> from titles in pane headers. | | --author <name> | SITEDRIFT_AUTHOR | you | Byline for notes added in the viewer. | | --vault <dir> | SITEDRIFT_VAULT | — | Enable Send to vault (writes the review markdown here). | | --config <file> | — | discovered | Read project configuration from JSON. |

A positional [path] (e.g. sitedrift /pricing) sets the initial route. -h, --help and -v, --version do what you'd expect.

AI and automation

The running process writes a private mode-0600 descriptor under ~/.sitedrift/sessions/. The npm package includes a zero-dependency stdio MCP server and an AGENTS.md operating guide.

Configure an MCP host with:

{
  "command": "sitedrift-mcp",
  "args": []
}

Codex and Claude Code can register it directly:

codex mcp add sitedrift -- sitedrift-mcp
claude mcp add sitedrift -- sitedrift-mcp

Without a global install:

{
  "command": "npx",
  "args": ["-y", "sitedrift", "mcp"]
}

Agents call sitedrift_context first, then use the note tools to share findings with the user. The server also exposes sitedrift://guide, a review_route prompt, and sitedrift_setup for install/config/HTTPS guidance.

For hosts without MCP, use the JSON CLI instead of scraping the viewer or constructing authenticated requests:

sitedrift context
sitedrift notes list
sitedrift notes add "CTA differs" --route /pricing --side live --author codex
sitedrift notes resolve <id>
sitedrift notes reopen <id>
sitedrift notes remove <id>
sitedrift notes clear

Commands print JSON and return non-zero on failure. They work over HTTP or local HTTPS without an agent-specific SDK.

HTTP endpoints

| Route | Purpose | |---|---| | GET / | The viewer. | | GET /health | { dev, live, version }. | | GET /api/v1/session | Authenticated session context and capabilities. | | GET /api/v1/notes · POST /api/v1/notes | Authenticated note list / operations. | | GET /notes.md | Notes as a Markdown checklist. | | POST /api/v1/notes/save | Write notes markdown into --vault. | | GET /icon.svg | The app mark / favicon. | | frame ports: GET /__dev/* · GET /__live/* | Isolated proxied origins. |

The control API requires the per-session bearer token. The CLI commands above are the supported machine interface.

Most viewer state (route, layout, scroll mode, focus) is mirrored into the URL query string, so a link reproduces the exact view.


Security — local development only

The proxy strips Content-Security-Policy, X-Frame-Options, and the Cross-Origin-{Embedder,Opener,Resource}-Policy headers so production can be framed next to dev.

  • Only loopback hosts are accepted, and Host headers are validated.
  • The viewer/control API uses --port; DEV and LIVE frames use --port + 1 and --port + 2, so neither page can inspect the other.
  • Framed pages communicate through a narrow postMessage bridge and cannot access the viewer DOM, bearer token, notes API, or vault endpoint.
  • Treat the notes file as plaintext shared scratch space.

Development

npm test
npm run test:e2e:visual
npm run test:e2e:visual:update   # intentionally accept visual changes

The visual suite uses deterministic origins and checked-in Chromium baselines for desktop split, narrow Solo, difference overlay, and the notes drawer.

Limitations

  • URL rewriting is regex-based, tuned for static sites (e.g. Astro builds). It rewrites root-relative href/src/srcset/url(...) and Vite/_astro paths, but won't catch URLs built in JS (fetch, dynamic import, import maps). SPAs with client-side absolute fetches may need extra rules.
  • Designed for two origins of the same site, not arbitrary cross-site diffing.

Docs

Credits

Created by Joe Severino.

License

MIT © 2026 Joe Severino