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

@kaynooo/cli-pkg

v0.16.2

Published

pkg: check an npm package before it is added, for a guessed name, a version under two weeks old and install scripts.

Readme

pkg

Checks an npm package before it is added: a guessed or typosquatted name, a version published less than two weeks ago, and install scripts.

bun install -g @kaynooo/cli-pkg
pkg esbuild
pkg [email protected] @types/node --json
pkg check --from package.json
echo "zod esbuild" | pkg check -
pkg outdated

What it prints

  • Whether the name exists, the version the request resolves to (an exact version, a dist-tag or a range), the latest version, and the highest stable version at least two weeks old (safe), each with its publish date.
  • Weekly downloads (public registry only), licence and repository.
  • Warnings for a version under the minimum age (with the safe version to use instead; a fresh version clear of an advisory at blockSeverity or above that safe has is let through, with a warning naming the GHSAs it fixes), preinstall, install and postinstall scripts, a deprecated version, and a name that is a near miss of a popular package (one or two edits, other separators or case, or the same name under another scope).

pkg exits 1 when a package is blocked (missing, the request matches no version or is not a valid range, the resolved version is too fresh (unless it fixes an advisory of the safe version at the threshold) or has no publish date on npmjs.org, its licence is outside the allowlist, or an advisory reaches the threshold), 2 when it could not check (the registry unreachable, slower than 10 s or answering badly, a broken .pkgrc.json, bunfig.toml or .npmrc) or on a usage error; other warnings exit 0. --json prints one report, or an array for several names, --min-age <days> changes the 14 days.

Config: licence allowlist and advisory threshold

pkg reads its own settings from a .pkgrc.json in the current folder or any folder above it, then from ~/.config/kaynooo-cli/pkg.json (the older ~/.config/pkg/config.json is read while the new file is missing); each key comes from the nearest file that sets it, and comments are allowed.

{ "licenses": ["MIT", "ISC", "Apache-2.0", "BSD-3-Clause"], "blockSeverity": "high" }
  • licenses is the allowlist of SPDX ids, compared without regard to case. An expression is allowed when one side of an OR is and every term of an AND is; a WITH exception is ignored. With an allowlist set, pkg check refuses a package whose licence is outside it or missing (a legacy SEE LICENSE IN or UNLICENSED counts as outside), so the bun add the guard checks through pkg check is refused with it. Without the key the licence is only printed.
  • minAge (a whole number of days, 14 when no config sets it) is how old a version must be when --min-age is not given, in check, audit and outdated.
  • concurrency (a positive whole number, 8 when no config sets it) is how many registry lookups audit and outdated run at once.
  • blockSeverity (low, moderate, high or critical, high when no config sets it) makes pkg check ask the registry for the advisories of the exact name@version and refuse it when one is at that severity or above. The request is the one bun audit makes: a POST of {"name": ["version"]} to <registry>/-/npm/v1/security/advisories/bulk. A registry without that endpoint (a private one, say) leaves the version unrefused with a warning, while an advisory request that fails (unreachable, a 5xx, not JSON) exits 2, since the advisories could not be read.

Auditing a lockfile

pkg audit
pkg audit ~/Workspace/app --level high --prod --ignore GHSA-238p-pmpm-9mq7 --json

pkg audit [dir] reads the bun.lock of the folder and runs the checks of pkg check on every registry package it pins (workspace, git and link sources left out): the age of the version, install scripts, a deprecated version, a near miss of a popular name and the licence allowlist. It also lists the known advisories of every pinned version, each with its GHSA, severity and the version that fixes it when the range ends at one. Findings come grouped per package, each package looked up on the registry once per run, and all advisories fetched in one request per registry.

  • --level <low|moderate|high|critical> (moderate) keeps only the advisories at that severity or above, --prod audits only the packages a production or optional dependency of a workspace reaches, and --ignore <GHSA or id> (repeatable) skips an advisory; blockSeverity is for pkg check and does not apply here. The three flags are the ones of audit.
  • --json prints a flat array, one {name, version, license, blocked, warnings, advisories} per package with a finding, each advisory being {id, ghsa, url, title, severity, vulnerable, fixed}. audit --json nests the same advisory rows (without vulnerable) in {repo, path, findings, error} per repository.
  • --min-age <days> changes the 14 days.
  • Use pkg audit to vet one repository in depth (age, install scripts, licences and advisories, with the registry as the source); use ws audit to sweep many repositories for advisories only, through bun audit.
  • A pin under the minimum age fixing an advisory of the safe version at blockSeverity or above (not one --ignore skips) is let through as pkg check lets it, a warning naming the GHSAs.
  • It exits 1 when a package is missing, too fresh or outside the allowlist, or an advisory remains after the level and the ignores; install scripts and near misses alone exit 0. When the advisories of a registry could not be read it warns which, never prints a clean result for them, and exits 2 unless something already blocks.
  • An npm: alias ("lodash": "npm:[email protected]") is audited as the package it names.

Moving consumers onto a release

pkg consumers @kaynooo/cli-kit
pkg bump @kaynooo/cli-kit 0.8.0 --dry-run
  • pkg consumers <name> lists every package.json under --root (the configured workspace folder, ~/Workspace by default) depending on the package, node_modules, dist, build, vendor, target, coverage, the names in the ignore array of ~/.config/kaynooo-cli/config.json and dot folders left out and nothing deeper than 5 levels below --root (point --root at the folder to reach further): the folder, the kind of dependency, the version it asks for and the manager its nearest lockfile pins; --json for the rows.
  • pkg bump <name> [version] waits until the package's registry serves the version (every 5 s, -t 10m; the latest when none is given, an exact version otherwise, never a range or a tag), then vets it with the checks of pkg check (advisories, licence allowlist) before any folder is touched, and runs bun add --exact --no-cache <name>@<version> in each of those folders, one after another, as the same kind of dependency (--dev, --optional), a line per folder. A version the vetting blocks is refused with its reasons and exit 1; --force bumps it anyway. A bump adopts a release on purpose, often one just made, so it checks no minimum age unless --min-age <days> asks for one. A dependency declared through an alias of the package ("kay": "npm:@scope/name@~1.2.0") is found and bumped under its own key, keeping its ~ or ^; --only <name|glob> and --except <name|glob> (repeatable) narrow the folders, and a package nothing depends on names similar dependencies. A dependency that is not a registry version (workspace:, link:, file:, git, a URL, another package's npm: alias, catalog:), a peerDependencies range, a folder already on the version and one whose lockfile pins another manager are left alone and said so; --dry-run prints what would run. On a terminal with no --only or --except, a checklist asks which consumers to bump (the ones left out last time unchecked, what is unchecked now remembered in ~/.config/kaynooo-cli/pkg-excluded.json), then the plan is printed and confirmed; --yes skips both, as a pipe does. A transient registry error is retried until the timeout. It exits 1 when the vetting refuses the version, an install fails or the registry has no such package (at once, without waiting), 2 when the version never shows within the timeout.
  • pkg bump <name> [version] --all-consumers leaves alone a folder whose package.json or lockfile already has uncommitted changes, so that gc never commits them as the bump, and goes on in each folder whose install went through: it runs the folder's own check and, only when that passes, commits with gc 'chore(deps): bump <name> to <version>' -- package.json <lockfile> (the bun.lock or bun.lockb nearest the folder, a monorepo's at its root). A folder whose check fails stays uncommitted. It ends on a summary line of the folders bumped and committed, bumped and failing, and skipped, exits 1 when an install, a check or a commit failed, and never pushes. With --dry-run it lists the bun add, check and gc each folder would run.
  • pkg <name> alone still runs pkg check.
  • pkg check --from <package.json> checks every registry dependency of a manifest (dependencies, devDependencies and optionalDependencies, each as name@range so it resolves what an install would; peer ranges and workspace:, link:, file:, git, URL and npm: sources left out). Names also come from stdin, separated by spaces or lines, with - as the argument or when nothing else names a package and stdin is piped; the three sources add up.
  • pkg outdated [dir] lists the dependencies of the folder's package.json with a newer version safe to take: the safe of pkg check (the highest stable version at least --min-age days old, 14 by default), with the change (major, minor, patch), its age and, while the newest version is still too fresh, that latest. The version in use is the highest one the folder's bun.lock pins that the range allows, else the exact version written, else the first version of the range. It reads the registry's metadata only (no advisories), changes nothing, exits 0 whether or not something is outdated and 2 when the registry could not be read. 50 rows at most (--limit, --full), --json for the rows.

Registries

The metadata comes from the registry the name is installed from. A @scope/ name follows @scope:registry= in the nearest .npmrc or [install.scopes] in the nearest bunfig.toml, walking up from the current directory and ending at the home directory, and a scope key wins over a nearer plain registry=, as it does for npm; the token (_authToken, or token in bunfig, with ${VAR} or $VAR expanded) is sent to that registry only, matched on a path boundary, over https (or http to localhost) only, and never printed. Environment variables are expanded in tokens only, never in a registry address. Every request has a 10 s deadline. Downloads come from the npmjs.org API, so they show - for any other registry. A registry that does not return publish times (Forgejo's does not) leaves the age unchecked, which pkg says in a warning.

The folder's package manager

pkg manager dev

pkg manager <install|dev|remove|update|exec> prints the command the manager of this folder runs for the action, such as bun add -d, composer require --dev or pnpm dlx. The manager is the one whose lockfile (bun.lock, bun.lockb, yarn.lock, pnpm-lock.yaml, package-lock.json, uv.lock) or composer.json is nearest, here or in a parent folder, bun when none is found. --json prints {manager, action, command}.

A shell abbreviation can call it through a small function, in fish function __nd; pkg manager dev; end then abbr -a nd --function __nd.

Maintenance

  • bun run popular regenerates src/popular.json, the 500 most downloaded names from the npm-high-impact list.
  • bun run record re-records the trimmed registry responses in tests/fixtures; the tests never touch the network.