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

@ajna-inc/npmvc

v0.3.4

Published

Verifiable-credential supply chain compliance for npm. Sign attestations, verify dependencies, revoke compromised packages.

Readme

@ajna-inc/npmvc

Supply-chain credential system for npm. Sign attestations when you publish, verify every dependency when you install.

Pure TypeScript. Zero native dependencies. Works everywhere npm runs.

Quick start — consumer

npm install -g @ajna-inc/npmvc
npmvc install-hook              # default preset: "balanced"
# or:
npmvc install-hook --preset strict     # block on unattested too
npmvc install-hook --preset permissive # warn-only, never blocks

This adds a preinstall hook to your package.json and writes npmvc-policy.json. Every subsequent npm install then runs npmvc verify first.

What each preset does

| Preset | Bad signature | Tampered bytes | Revoked credential | Unattested dep | | ------------ | ------------- | -------------- | ------------------ | -------------- | | strict | block | block | block | block | | balanced (default) | block | block | block | warn | | permissive | warn | warn | warn | warn |

Most of npm is still unattested, so balanced warns on unattested deps but blocks the explicitly-bad ones. Flip to strict once your internal packages are all attested.

There is no env-var bypass. To temporarily disable, edit package.json#scripts.preinstall directly.

Quick start — publisher

npm install -g @ajna-inc/npmvc
npmvc init                                        # plaintext key
# or:
npmvc init --encrypt --passphrase "..."           # encrypted at rest

npm pkg set "publisher"="$(jq -r .did ~/.npmvc/wallet/key.json)"
npm pkg set scripts.prepack="npmvc attest --registry https://npmvc.com"
npm pkg set files='["dist", ".npmvc"]' --json

Every subsequent npm publish now runs attest first: signs Provenance + Lifecycle + SBOM credentials, binds them to the content of the tarball, and uploads to the npmvc registry.

To rotate the keys you sign with, see SECURITY.md.

What gets checked

  • Signatures — DSSE envelopes verified against publisher DID (Ed25519)
  • Tarball digest — installed bytes are hashed and compared to the signed claim
  • Revocation — credentials revoked by the publisher are refused
  • Age — versions younger than minAge (default 7d) are flagged
  • Publisher continuity — DID changes across versions block (did:webvh rotations are allowed via SCID-prefix matching)
  • Trust roottrustedIssuers URL fetched, Ed25519-signed by the pinned root DID
  • Lifecycle scriptspostinstall flagged unless whitelisted
  • Transitive deps — full lockfile tree (npm, pnpm, yarn)
  • Audit credentials — third-party scanner verdicts with trustedAuditIssuers + auditMaxAge
  • SBOM — CycloneDX SBOM signed and bundled

Policy

npmvc-policy.json, written by install-hook --preset <name>:

{
  "enforcement": "block",
  "transitive": true,
  "minAge": "7d",
  "unattested": "warn",
  "unattestedMinAge": "30d",
  "trustedIssuers": ["https://npmvc.com/trust-root.json"],
  "trustedAuditIssuers": [],
  "auditMaxAge": "180d",
  "attestationSources": ["local", "registry"],
  "registry": "https://npmvc.com",
  "allowPrivateRegistry": false,
  "publisherContinuity": {
    "required": true,
    "onUnauthorizedChange": "block",
    "pinned": { "express": "did:key:z6Mk..." }
  },
  "revocation": {
    "required": true,
    "registryUrl": "https://npmvc.com",
    "maxCacheAge": "10m"
  },
  "lifecycleScripts": { "postInstall": "whitelisted", "whitelist": [] },
  "waivers": []
}

Set allowPrivateRegistry: true if you point registry at an internal mirror or http:// host. By default the SSRF guards refuse private IPs.

CI/CD

Publish from GitHub Actions:

- name: Attest + Publish
  env:
    NPMVC_KEY: ${{ secrets.NPMVC_KEY }}                  # contents of ~/.npmvc/wallet/key.json
    NPMVC_KEY_PASSPHRASE: ${{ secrets.NPMVC_KEY_PASSPHRASE }}  # only if the key is encrypted
    NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
  run: |
    npm install -g @ajna-inc/npmvc
    mkdir -p ~/.npmvc/wallet && echo "$NPMVC_KEY" > ~/.npmvc/wallet/key.json && chmod 600 ~/.npmvc/wallet/key.json
    npm publish --access public

prepack runs npmvc attest automatically before npm packs the tarball.

See packages/github-action for a packaged action with the same behaviour.

Key management

npmvc wallet encrypt --passphrase "..."   # encrypt the in-use key at rest
npmvc wallet decrypt --passphrase "..."   # undo (back to plaintext)
npmvc wallet export  --passphrase "..." > key.enc      # portable encrypted backup
npmvc wallet import  --passphrase "..." --input key.enc  # restore from backup

# Recovery (lost key, guardians configured)
npmvc wallet add-guardian   --did did:key:z6MkFRIEND...
npmvc wallet set-threshold  --threshold 2
npmvc wallet recover        --old-did did:key:... --guardians did:key:a,did:key:b
npmvc wallet approve-recovery --request recovery-request.json
npmvc wallet apply-recovery --approvals approval-1.json,approval-2.json

# Rotation (did:webvh only)
npmvc wallet rotate

Commands

| Command | Purpose | |---|---| | init [--encrypt --passphrase ...] | Create publisher DID | | attest [--registry URL] | Sign attestations + optionally sync to registry | | verify | Verify the installed dep tree | | install-hook [--preset strict\|balanced\|permissive] | Add preinstall hook + policy | | policy init / policy show | Manage the policy file | | register | Register your DID on an npmvc registry | | audit publish / audit import | Issue / import a third-party scanner credential | | credential revoke | Revoke a credential on the registry | | credential handover | Sign a maintainer-handover credential | | wallet encrypt / decrypt | Toggle at-rest encryption of the key file | | wallet export / import | Encrypted key backup | | wallet rotate (did:webvh) | Rotate to the pre-committed backup key | | wallet add-guardian, set-threshold, guardians | Recovery setup | | wallet recover, approve-recovery, apply-recovery | Recovery flow | | anchor publish | Build a transparency-log Merkle root |

Threat model and trust root

See SECURITY.md for the pinned community trust-root DID, rotation policy, and known limitations.

Packages in this repo

  • @ajna-inc/npmvc (the CLI) — root package.json, sources in src/
  • packages/npmvc-web — the npmvc.com registry/UI
  • packages/github-action — GitHub Action wrapper
  • packages/verdaccio-plugin — early-stage stub, not for production use

License

Apache-2.0