Test the npm package users will actually install, not just the source tree you happen to have locally.
I built PackSmoke after running into a common packaging gap: repository tests can pass while the published tarball is missing a bin file, declaration file or other artifact that consumers depend on. PackSmoke creates the real package tarball, inspects it, installs it into a clean temporary project and checks the basic package contract.
npx --yes packsmoke .JSON output for CI:
npx --yes packsmoke . --jsonSkip the clean consumer installation when you only want artifact checks:
npx --yes packsmoke . --no-installPackSmoke currently requires Node.js 22+ and npm 11+.
- creates the package with
npm pack --json --ignore-scripts - verifies
mainandtypes/typingstargets when present - checks declared
bintargets and JavaScript shebangs - warns when expected README/LICENSE files are missing from the tarball
- flags local
file:dependencies that should not escape into a release - warns about
link:andworkspace:protocols - checks the packed filenames for common sensitive files such as
.env, private keys and.npmrc
The sensitive-file check is path-based; PackSmoke is not a secret-content scanner.
The generated tarball is installed into a temporary consumer project with lifecycle scripts disabled. PackSmoke then verifies the installed package metadata and npm-created bin shims, including Windows .cmd shims.
PackSmoke
Package: my-package@1.0.0
PACK
✓ 12 files
ENTRY POINTS
✓ main -> dist/index.js
✓ types -> dist/index.d.ts
INSTALL
✓ clean consumer installation succeeded
✓ installed package metadata matches
Result: PASSED
A failed package contract exits with code 1; CLI/configuration errors use code 2.
PackSmoke relies on lifecycle scripts staying disabled during both packing and installation. It checks the npm version up front and fails cleanly on older versions rather than silently changing that safety assumption.
It also invokes npm without a shell where possible and never executes the binaries from the package being inspected.
PackSmoke is deliberately narrower than a full package linter. It focuses on the physical tarball and what happens when a clean consumer installs it.
For deeper package.json/module-compatibility analysis, publint is a good complementary tool. Using both catches different classes of release mistakes.
- run: npx packsmoke . --jsonIf your project generates dist/ or other release files in a build step, run that build before PackSmoke. PackSmoke does not execute prepack or other lifecycle scripts for you.
PackSmoke does not currently perform full exports condition analysis, execute installed binaries, scan file contents for secrets, or validate every ESM/CJS compatibility case.
MIT