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

@itsl-solutions/npm-registry-shield

v0.2.0

Published

Registry proxy that quarantines recently published npm package versions

Readme

npm-registry-shield

Registry proxy that quarantines recently published npm package versions. Protects against supply chain attacks by ensuring you only install versions that have been on the registry for a configurable number of days.

How it works

npm-registry-shield sits between your package manager and the npm registry. When you run npm install, it intercepts the package metadata and strips out versions published within the quarantine window (default: 3 days). Your package manager never sees the risky versions - it resolves to the newest safe version automatically.

npm install express
    |
    v
localhost:4873 (npm-registry-shield)
    |
    |- fetch metadata from registry.npmjs.org
    |- strip versions published < 3 days ago
    |- return filtered metadata
    |
    v
npm resolves to newest safe version

All transitive dependencies are also protected - every package at every depth resolves through the proxy.

What gets filtered, what passes through

| Request type | Behavior | |--------------|----------| | GET /<pkg> (full packument) | Versions inside the quarantine window are stripped. dist-tags are rewritten to point at the newest surviving version. If every version is quarantined, returns 404. | | GET /<pkg>/<version> (single version metadata) | Passed through unchanged. If the version is quarantined, a warning is logged and counted in stats but the response is not blocked. | | Tarball downloads (/<pkg>/-/<file>.tgz) | Forwarded upstream as-is. | | Search, login, publish, anything else | Forwarded upstream as-is. |

Packuments are cached in memory for 10 minutes (configurable via cacheTtlMinutes). The cache is cleared automatically when you run allow or remove.

Requirements

bun is the only runtime. The proxy itself runs under bun, and the published package ships TypeScript sources executed directly by bun.

Install

bun add -g @itsl-solutions/npm-registry-shield

Quick start

npm-registry-shield start

That's it. On macOS this installs a launchd service and starts it. On Linux it installs a systemd user service. The proxy runs in the background, survives reboots, and rewrites your ~/.npmrc (and ~/.yarnrc.yml if present) to point at it.

Your npm, pnpm, yarn, and bun install commands are now protected.

To stop:

npm-registry-shield stop

This unloads the service and restores your original ~/.npmrc.

To run in the foreground (for debugging or one-off use):

npm-registry-shield start --foreground

Logs are written to ~/.npm-shield/daemon.log. Configuration is at ~/.npm-shield/config.json.

Manual daemon install

If you want to write the service file yourself (custom flags, custom path, etc.):

# macOS
npm-registry-shield daemon-template launchd > ~/Library/LaunchAgents/com.npm-registry-shield.plist
launchctl load ~/Library/LaunchAgents/com.npm-registry-shield.plist

# Linux
mkdir -p ~/.config/systemd/user
npm-registry-shield daemon-template systemd > ~/.config/systemd/user/npm-registry-shield.service
systemctl --user daemon-reload && systemctl --user enable --now npm-registry-shield

Commands

npm-registry-shield start [options]      Install + start the background daemon (survives reboots)
npm-registry-shield stop                 Stop the daemon and restore package manager configs
npm-registry-shield status               Show running state and config
npm-registry-shield allow <pkg>          Skip quarantine for a package
npm-registry-shield allow <pkg>@<ver>    Allow specific version (with warning)
npm-registry-shield remove <pattern>     Remove from passthrough list
npm-registry-shield list                 Show passthrough entries
npm-registry-shield config get <key>     Show config value
npm-registry-shield config set <k> <v>   Update config value
npm-registry-shield stats                Show statistics summary
npm-registry-shield daemon-template <launchd|systemd>
                                         Print a service unit you can install for persistence

Start options

-f, --foreground          Run in this terminal instead of installing the daemon
-q, --quarantine=<days>   Override quarantine period (default: 3)
-p, --port=<port>         Override proxy port (default: 4873)
-u, --upstream=<url>      Override upstream registry URL
-d, --dashboard           Enable the web dashboard (default)
    --no-dashboard        Disable the web dashboard

Value flags accept long or short, with or without =: --port=4873, --port 4873, -p 4873, -p4873. A value flag with no value (or one immediately followed by another flag) is rejected with an error rather than parsed silently. Short flags cannot be bundled (-fd); pass them separately.

Package manager support

| Manager | Supported | How | |---------|-----------|-----| | npm | Yes | .npmrc registry setting | | pnpm | Yes | .npmrc registry setting | | yarn v1 | Yes | .npmrc registry setting | | yarn v2+ | Yes | .yarnrc.yml npmRegistryServer | | bun | Yes | .npmrc registry setting | | deno | Manual | export DENO_NPM_REGISTRY=http://localhost:4873 |

Dashboard

When the proxy is running, open http://localhost:4873/ for a live stats dashboard showing total requests, hidden (quarantined) versions, blocked installs, and a per-package breakdown.

Each package row also shows:

  • Tool that fetched it (npm, pnpm, yarn, bun, deno, browser, ...) detected from the request User-Agent.
  • Origin path of the process that made the request (working directory) plus the launcher app that started the chain (e.g. iTerm2, Claude, Code Helper), so you can tell apart an explicit npm install from a tool that quietly spawned npm in the background.

By default only packages with more than 10 requests are shown; the "Show all" button in the Packages header reveals the long tail.

Origin attribution uses lsof + ps and works on macOS today. On Linux and other platforms the proxy still serves stats - the origin/tool columns are simply empty.

Stats CLI

For a terminal-friendly snapshot:

npm-registry-shield stats

Prints the totals, the top 20 packages by request count with aligned columns, and the legend explaining what each column means. Reads from ~/.npm-shield/stats.json, which the daemon flushes every 30 seconds.

Security & networking

The proxy listens on 127.0.0.1 only, so nothing on your LAN can reach it. Upstream traffic still goes out over HTTPS to whatever registry you configured (https://registry.npmjs.org by default).

Configuration

Config is stored at ~/.npm-shield/config.json:

{
  "port": 4873,
  "upstream": "https://registry.npmjs.org",
  "quarantineDays": 3,
  "cacheTtlMinutes": 10,
  "dashboard": true,
  "passthrough": []
}

Passthrough list

Skip quarantine for trusted packages:

# Entire package
npm-registry-shield allow lodash

# Scoped packages
npm-registry-shield allow "@my-org/*"

# Specific version (allowed with a warning)
npm-registry-shield allow [email protected]

What happens when...

npm install express - Resolves to the newest version that is at least 3 days old.

npm install [email protected] where 5.0.0 is too new - npm fetches the full packument first to resolve, sees 5.0.0 missing, and fails. Run npm-registry-shield allow [email protected] to permit it.

A brand-new package (all versions < 3 days old) - The packument response is a 404 with an explanatory error. Add the package to the passthrough list to allow it.

npm ci with a lockfile pointing at a quarantined version - The packument resolution step strips the version, so npm errors. Catches dependencies your teammates added that haven't aged past the quarantine window yet. Add the offending versions to passthrough or wait them out.

npm view [email protected] - Hits the single-version endpoint, which passes through with a warning logged in ~/.npm-shield/daemon.log and counted under "warnings" in stats. Useful for inspecting fresh versions without committing to install them.

The proxy is down - .npmrc points at a dead server, npm commands fail. Run npm-registry-shield stop to restore your config. If the CLI is unreachable, manually remove the registry= line from ~/.npmrc.

Recovery

If something goes wrong and npm commands fail:

# Restore configs from backup
npm-registry-shield stop

# If the CLI is unavailable, remove this line manually:
#   registry=http://localhost:4873
nano ~/.npmrc

Development

If you just want to use the tool, see Install above (bun add -g @itsl-solutions/npm-registry-shield). This section is for hacking on the source.

Working from a local clone of this package:

cd npm-registry-shield
bun install
bun link
exec $SHELL              # reload shell so the new global bin is on PATH
npm-registry-shield start

bun link symlinks the package into bun's global bin dir pointing at your clone. Edit src/*.ts and the change is live on the next run - no rebuild step.

Note: after bun link, the npm-registry-shield command is not available in the same shell session that ran the link - shells cache PATH lookups. Open a new terminal or run exec $SHELL (or hash -r in bash/zsh) to refresh.

Run tests with bun test.

License

MIT