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

sealcode

v1.5.0

Published

Lock your source code in your own git repo. Stop AI agents, scrapers, and curious eyes from reading what's yours.

Readme

sealcode

Lock your source code inside your own git repo. Stop AI agents, scrapers, and curious eyes from reading what's yours.

npm install -g sealcode

Renamed from vaultline. Existing vaults keep working unchanged — the on-disk format is unchanged, .vaultlinerc.json is still read, and VAULTLINE_PASSPHRASE is still accepted as a fallback.

What problem does this solve?

You push code to a private repo. You think it's safe. But anyone (or any AI) with read access to that repo — a contractor, a teammate's compromised laptop, a future Copilot indexing run, a leak — can read every line.

sealcode wraps your source files in AES-256-GCM ciphertext before they touch git. Your repo becomes a folder of opaque binary blobs with a stub package.json. To anyone without your passphrase, your codebase is uniformly random bytes.

To you, one command brings it all back:

sealcode unlock      # readable code is restored
# ... edit ...
sealcode lock        # back to ciphertext
git commit && git push

Quickstart (60 seconds)

cd your-project
sealcode init                 # interactive wizard
# 1. Auto-detects your stack (Node, Python, Go, Rust, Ruby, PHP, Java, ...)
# 2. Picks safe include/exclude defaults
# 3. Asks for a passphrase
# 4. Shows a recovery code — write it down ONCE
# 5. Locks every source file immediately

git add . && git commit -m "vault initialized" && git push

When you want to work on it:

sealcode unlock
npm install
npm run dev

When you're done:

sealcode lock
git commit && git push

Why this beats git-crypt, git-secret, sops, etc.

| | sealcode | git-crypt | git-secret | sops | |---|---|---|---|---| | Encrypts whole files (not just diffs) | ✅ | partial | ✅ | ❌ (values only) | | Filenames hidden | ✅ | ❌ | ❌ | ❌ | | Repo metadata hidden (package.json, deps) | ✅ | ❌ | ❌ | ❌ | | Passphrase-based (no GPG keyring) | ✅ | ❌ | ❌ | partial | | Recovery code if you lose passphrase | ✅ | ❌ | ❌ | ❌ | | Works on any language/stack | ✅ | ✅ | ✅ | ✅ | | Auto-detects your ecosystem | ✅ | ❌ | ❌ | ❌ | | Built-in drift detection | ✅ | ❌ | ❌ | ❌ |

The big one: sealcode hides that your code exists at all. Other tools encrypt the files but leave the folder structure, the filenames, and the package.json (with every telltale dependency) in plain view.

Commands

sealcode init            # one-time setup; interactive wizard
                         #   --preset auto             universal coverage via git ls-files
                         #                             (default since 1.4.0)
                         #   --allow-monorepo          override the multi-microservice
                         #                             guard (one vault for the whole tree;
                         #                             billed as one project)
sealcode scan            # dry-run: show what would be locked, with coverage
                         #          report, suspicious-exclusion hints, and a
                         #          monorepo / multi-microservice notice if any
                         #          sibling service directories are present
sealcode lock            # encrypt source → vendor/ blobs (removes plaintext)
sealcode unlock          # decrypt blobs → restore source (removes stubs)
sealcode verify          # confirm every blob decrypts & matches its hash
sealcode status          # show locked/unlocked + drift since last lock
sealcode status --check  # exit 1 if unlocked (used by git hook). 1.4.1+: strict — passes only when locked.
sealcode status --check --allow-clean-unlock   # 1.4.1+ escape hatch: only fail on drift
sealcode status --json   # machine-readable state (editors / scripts)
sealcode rotate          # change passphrase (blobs unchanged); env: SEALCODE_OLD_PASSPHRASE / SEALCODE_NEW_PASSPHRASE
sealcode backup <dir>    # copy locked vault + config snapshot to a new folder
sealcode restore <dir>   # restore from backup (use --force if locked dir exists)
sealcode install-hook    # git pre-commit: block any commit while the project is unlocked (strict by default in 1.4.1+)
sealcode install-hook --lenient   # pre-1.4.1 behavior: only block when the working tree has drifted vs the lock
sealcode uninstall-hook  # remove hook block
sealcode panic           # immediate re-lock + session wipe
sealcode logout          # clear cached session, force passphrase next time
sealcode remove          # permanently uninstall sealcode from this project (requires passphrase; emails project owner if linked)
sealcode presets         # list supported ecosystems
sealcode share <opts>    # mint a temporary access code (--email <addr> wraps the key for them)
                         #   1.1 controls (all optional):
                         #     --paths src/api/,tests/    only decrypt these prefixes
                         #     --mode ro                  read-only; watcher re-locks on edit
                         #     --watermark "Licensed to {email} · grant {grantId}"
                         #     --idle 30                  auto-lock after N idle minutes
                         #     --allow-ip 10.0.0.0/8      restrict redeem + heartbeat IPs
                         #     --allow-country US GB      ISO-2 country allowlist (Cloudflare-fed)
                         #     --single-device            hard-reject 2nd device fingerprint
                         #     --nda "text"               require typed "I agree" on redeem
sealcode redeem <code>   # accept a code; auto-unlocks + spawns watcher when team-shared
sealcode watch <code>    # poll the server with long-poll (~1s revoke); --daemon for background
sealcode lockdown        # 1.1: panic — revoke ALL active grants for the linked project
sealcode install-service # macOS launchd / Linux systemd unit so the watcher survives reboots
sealcode uninstall-service
sealcode pro             # Pro tier info
sealcode where           # debug: print paths and state (no secrets)

Aliases: sc, sealcode seal = lock, sealcode open = unlock.

Unlinking vs. removing

There are three different "undo" actions, and it's worth being precise about which one you want:

| Command | What it does | Touches the server? | Reversible? | |---|---|---|---| | sealcode link --remove | Forgets the dashboard association on THIS checkout. The vault stays. The server still has the project. | No. | Yes — just sealcode link <id> again. | | Delete project (dashboard) | Releases the paid slot and the server-side repo binding. The local vault is untouched. | Yes (owner only). | No (the slot is gone). | | sealcode remove | Permanently uninstalls sealcode from this local repo. Decrypts files back to plaintext, deletes vendor/, the config, and the cached session. | Yes if linked: emails the owner and audit-logs project.remove BEFORE local destruction. | No. |

sealcode remove requires the project passphrase (even if a session is unlocked) and a typed yes-remove confirmation. When the project is linked, it refuses to run if it can't reach sealcode.dev — that way no one can bypass the owner email by cutting the network. Use --offline to override explicitly.

Other useful flags:

sealcode remove --confirm yes-remove   # skip the interactive prompt (for scripts)
sealcode remove --burn                 # discard ciphertext WITHOUT decrypting first (data loss)
sealcode remove --offline              # don't notify the owner (we still try first)

One vault per project

sealcode is licensed and operated per project, and the CLI plus the server enforce that.

Locally, at sealcode init — if your repo is a monorepo with multiple microservices (a root pnpm-workspace.yaml, a services/-style layout with several package.json files, etc.), sealcode init refuses at the root and tells you which subdirectories to initialize separately. Each service then gets its own keys, its own grants, its own audit trail, and — going forward — its own billing line item.

If you genuinely want one vault for the whole tree (small solo repo, intentional experiment monorepo) pass --allow-monorepo to override. Run sealcode scan first to see what was detected.

Server-side, at sealcode link — each project record on sealcode.dev is pinned 1:1 to a single local repository. The first sealcode link <id> records an opaque fingerprint of the repo's vault salt on the server; any later link attempt from a different local repo is rejected with HTTP 409 and SEALCODE_PROJECT_REPO_MISMATCH. Teammates cloning the same repo pass the check because they share the same salt.

If you really do need to migrate a paid project to a new repo, the project owner can re-pin with:

sealcode link --force <projectId>

The force flag is owner-only and gets audit-logged as project.link.force.

Editor support

A VS Code companion lives in tools/vaultline-vscode/ — it shows the current lock state in the status bar when the CLI is on your PATH. (Rename in flight; the extension itself works against either sealcode or vaultline on PATH.)

CI (GitHub Actions)

- run: npm install -g sealcode
- env:
    SEALCODE_PASSPHRASE: ${{ secrets.SEALCODE_PASSPHRASE }}
  run: |
    sealcode unlock
    npm install --omit=dev
    npm run build

Supported stacks (auto-detected)

| Marker file | Preset | Locked dir | |---|---|---| | package.json (no Next config) | Node.js / TypeScript | vendor/ | | next.config.* | Next.js | vendor/ | | requirements.txt / pyproject.toml / setup.py | Python | _site_packages/ | | manage.py | Django | _site_packages/ | | go.mod | Go | internal/sealed/ | | Cargo.toml | Rust | target/.cache/ | | Gemfile | Ruby on Rails | vendor/sealed/ | | composer.json | PHP / Laravel | storage/sealed/ | | pom.xml / build.gradle* | Java / JVM | .sealed/ | | (none of the above) | generic | vendor/ |

Each preset uses a lockedDir name that looks native to its ecosystem — Go projects don't get a suspicious folder called locked/, they get internal/sealed/. Stealth by camouflage.

How the crypto works (the short version)

  • Algorithm: AES-256-GCM with a random 12-byte IV per blob; gzip before encrypt.
  • Key derivation: scrypt(passphrase, salt) → 32-byte wrapping key, N=2^17, r=8, p=1 (~1s, ~128MB).
  • Master data key: randomly generated, stored on disk wrapped twice — once by your passphrase, once by a 128-bit recovery seed (the 30-char recovery code you wrote down at init).
  • File-on-disk format: [12B IV][16B GCM tag][ciphertext] with no header bytes. Indistinguishable from random data.
  • Filenames inside vendor/: HMAC-SHA256 of the path, sharded by first 2 hex chars, truncated to 12. Stable across re-locks, indistinguishable across files.
  • No # CV1 or other text signatures that would let file(1) / scrapers / AI identify the format.

Where does the passphrase live?

Wherever you put it. The tool checks:

  1. Cached session (~8h after last unlock — stored at ~/.sealcode/sessions/<id>, encrypted with a host-binding key)
  2. SEALCODE_PASSPHRASE env var (use in CI). VAULTLINE_PASSPHRASE is accepted as a fallback for projects upgrading from vaultline 1.x.
  3. Interactive prompt

sealcode never writes your passphrase to disk in any recoverable form. Lose your passphrase AND your recovery code, and your code is gone. We can't help you. That's not a bug — it's the entire point.

Back up your recovery code in:

  • a password manager (1Password / Bitwarden as a secure note)
  • a printed sheet
  • an encrypted USB / hardware key

CI / deploy

# GitHub Actions
- run: npm install -g sealcode
- env:
    SEALCODE_PASSPHRASE: ${{ secrets.SEALCODE_PASSPHRASE }}
  run: |
    sealcode unlock
    npm install --omit=dev
    npm run build       # produces dist/main.js
- run: rsync dist/ user@server:/app/dist/

Your production server never sees the passphrase or the vault. It only runs the built dist/.

Pro features (coming soon)

The free CLI handles lock / unlock / verify forever. sealcode Pro adds:

  • Team key sharing — invite teammates, no passphrase exchange needed
  • Key rotation across N projects with one command
  • Audit log — see who unlocked what, when
  • Cloud key escrow — passphrase recovery via account auth
  • Temporary access codes — time-boxed, revocable read access to a project
  • CI/CD tokens — short-lived deploy keys, no long-lived secrets in Actions

Start a 14-day trial at sealcode.dev/pro.

FAQ

Does this affect git diffs? Yes — vendor/ blobs change every lock (random IV). For human review, diff your local unlocked tree before locking. A sealcode diff <commit> command is on the Pro roadmap.

Can I encrypt only some files? Yes — edit .sealcoderc.json's include array.

Does it work on Windows? Yes. Forward-slash normalization in opaque names; tested on macOS, Linux, Windows.

What's the perf cost? First unlock with passphrase: ~1s (scrypt). Subsequent commands within 8h: <100ms (cached session). Lock/unlock of a 1000-file repo: ~2s.

Is this audited? Not formally. The crypto is standard primitives (AES-256-GCM, scrypt) used in their textbook configurations. Audit yourself at the repo. We'll fund a formal audit once revenue supports it.

I had vaultline installed before — do I lose my vault? No. The on-disk format is unchanged. sealcode reads any existing .vaultlinerc.json, your old ~/.vaultline/sessions/ cache, and VAULTLINE_PASSPHRASE env var. On the next sealcode lock the project will start writing the new config name (.sealcoderc.json), but the encrypted blobs themselves never need to be re-encrypted.

Contributing & tests

The CLI ships with a small fast test suite that runs in a tmpdir — no Postgres, no network. From tools/sealcode-cli/:

npm test

The seven targeted regression tests live under test/ and cover:

  • envelope wrap/unwrap round-trip (the team-share crypto core)
  • auto-preset coverage on a synthetic Next.js repo (the 1.4 motivating bug)
  • preserveUnseen semantics across scoped re-locks (1.3.6 safety guard)
  • read-only mode re-lock after EACCES (1.3.3 stub-write fix)
  • watcher heartbeat classification of 5xx / network blips as transient
  • unlock-check blocking unlock on revoked / expired server responses
  • stale-pubkey warning when sharing to a recipient whose published key is >30 days old

Filter to a single test with FILTER=auto-preset npm test.

License

MIT. See LICENSE.