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

@zodo/zmpm

v0.1.1

Published

Zodo Meteor Package Manager — vendor Meteor packages into an app's packages/ dir from GitHub Releases or any tarball URL, with auth and transitive-dependency resolution. A generic alternative to Atmosphere for private/self-hosted packages.

Readme

zmpm — Zodo Meteor Package Manager

Vendor Meteor packages into an app's packages/ directory from GitHub Releases or any tarball URL, with authentication and transitive-dependency resolution. A generic, registry-free alternative to Atmosphere for private/self-hosted Meteor packages.

Meteor already treats anything in packages/<dir>/ as a local package and builds it itself — so zmpm add gives you meteor add-able packages without a package server. What you give up vs Atmosphere is meteor update semantics; zmpm update fills that gap.

Usage

Run with npx (no install):

npx @zodo/zmpm add gh:zodo-dev/meteor-packages:[email protected]

That downloads the release tarball into packages/ai-kit/ and, because ai-kit declares zodo:secrets, also pulls packages/secrets/. Then in your app:

meteor add zodo:ai-kit

Commands

zmpm add <spec>...        install package(s) into <dest>/ and update zmpm.json
zmpm update [<name>...]    re-fetch installed packages (all, or the named ones)
zmpm install              install everything recorded in zmpm.json (like npm ci)
zmpm remove <name>...      remove package folder(s) + lockfile entries
zmpm pack <dir>            build a correctly-structured release tarball from a dir
zmpm list                  show installed packages from zmpm.json

Source specs

| Spec | Meaning | |---|---| | gh:<owner>/<repo>:<pkg>[@<version>] | GitHub Release asset (default @latest). Resolves tag <pkg>-v<version>. | | https://host/path/pkg-x.y.z.tgz | any tarball over HTTP(S) | | file:<path> or ./path.tgz | a local tarball (e.g. from zmpm pack) |

Options

| Option | Meaning | |---|---| | --dest <dir> | target packages dir (default packages, or the lockfile's dest) | | --token <token> | GitHub token (else ZMPM_GITHUB_TOKEN / GITHUB_TOKEN / GH_TOKEN) | | --header "K: v" | extra HTTP header for http(s) specs (repeatable) | | --config <file> | path to a .zmpmrc (else ~/.zmpmrc, ./.zmpmrc) | | --credential-helper <cmd> | external command that returns auth for a URL | | --no-deps | do not resolve same-org transitive dependencies | | --gitignore / --no-gitignore | manage / stop managing .gitignore (default: manage) | | --force | re-download even if the installed version already matches | | --cwd <dir> | run as if in <dir> (where zmpm.json + packages/ live) |

Authentication

Three mechanisms, applied in this precedence (later wins): .zmpmrc host entry → credential helper → --header.

1. Inline / env (simplest)

# private GitHub repo — token with contents:read
ZMPM_GITHUB_TOKEN=ghp_xxx npx @zodo/zmpm add gh:zodo-dev/meteor-packages:[email protected]
# any authenticated URL
npx @zodo/zmpm add https://pkgs.example.com/zodo-seo-ssr-0.1.0.tgz --header "Authorization: Bearer $T"

Release assets on a private repo are fetched via the assets API (not the browser URL); the redirect to signed storage drops the token, as it should.

2. .zmpmrc file (per-host, like .npmrc)

Put static credentials in ~/.zmpmrc (global) or <app>/.zmpmrc (project). Gitignore it — it holds secrets. See examples/.zmpmrc.example:

{
  "hosts": {
    "api.github.com": { "token": "ghp_read_token" },
    "pkgs.example.com": { "headers": { "Authorization": "Bearer STATIC" } }
  },
  "credentialHelper": "node ./examples/credential-helper.example.js"
}

3. Credential helper (dynamic — for storage / pre-signing)

For auth that must be computed per request (e.g. pre-signing an S3/GCS/OCI URL, minting a short-lived token), point zmpm at an external command. zmpm writes a JSON request to its stdin and reads a JSON response from stdout:

request:  { "url": "<requested url>", "host": "<host>", "method": "GET" }
response: { "headers": { "<name>": "<value>" }, "url": "<optional rewritten url>" }

Returning url makes zmpm fetch a different URL — the storage case: hand back a signed URL that carries its own auth. Runnable sample: examples/credential-helper.example.js.

npx @zodo/zmpm add https://store.internal/secrets.tgz \
  --credential-helper "node ./scripts/sign-url.js"

Transitive dependencies

For a gh: install, zmpm reads the fetched package's package.js, finds api.use('<same-prefix>:…') dependencies (e.g. zodo:*), maps each to a folder (an optional zmpm.aliases.json at the repo root overrides the default name→folder mapping), and installs those from the same repo recursively. A dependency in a different repo must be added explicitly. http(s) installs do not auto-resolve dependencies (there is no repo to resolve them from).

Config + lockfile (zmpm.json)

zmpm.json (next to the app) is both config and lockfile — it records the target dir, the gitignore preference, and every installed package + its source:

{
  "dest": "packages",
  "gitignore": true,
  "packages": {
    "zodo:ai-kit": { "folder": "ai-kit", "version": "0.2.0", "source": "gh:zodo-dev/meteor-packages:[email protected]", "direct": true },
    "zodo:secrets": { "folder": "secrets", "version": "0.1.0", "source": "gh:zodo-dev/meteor-packages:[email protected]", "direct": false }
  }
}
  • dest — where packages are vendored. Set once with --dest; persisted here so later commands don't need it.
  • packagesdirect: true = you asked for it; false = pulled as a transitive dep. zmpm update follows the direct roots.
  • Commit zmpm.json (it has no secrets). zmpm install reinstalls exactly this set — use it in CI. zmpm update re-fetches the direct entries.

.gitignore management

By default zmpm keeps a managed block in <app>/.gitignore so vendored packages are not versioned (Meteor rebuilds them from the tarball / next zmpm install):

# --- zmpm managed (vendored Meteor packages; do not edit) ---
/packages/ai-kit/
/packages/secrets/
# --- end zmpm managed ---

The block is regenerated on every add/remove/update; your other .gitignore content is never touched. Opt out with --no-gitignore (persisted as "gitignore": false), which also removes the block. If you prefer to commit the vendored packages, use --no-gitignore.

Examples

# 1. Install a package (public repo) + its deps, then wire it into Meteor
npx @zodo/zmpm add gh:zodo-dev/meteor-packages:[email protected]
meteor add zodo:ai-kit

# 2. Private repo — token with contents:read
ZMPM_GITHUB_TOKEN=ghp_xxx npx @zodo/zmpm add gh:zodo-dev/meteor-packages:ai-kit@latest

# 3. Pin a version and a custom target dir (persisted to zmpm.json)
npx @zodo/zmpm add gh:zodo-dev/meteor-packages:[email protected] --dest app/packages

# 4. Direct tarball URL with a static header
npx @zodo/zmpm add https://pkgs.example.com/zodo-cookie-consent-0.1.0.tgz \
  --header "Authorization: Bearer $REGISTRY_TOKEN"

# 5. Object storage via a credential helper that returns a pre-signed URL
npx @zodo/zmpm add https://store.internal/zodo-secrets.tgz \
  --credential-helper "node ./scripts/presign.js"

# 6. Reproducible install in CI (reads zmpm.json, like npm ci)
GITHUB_TOKEN=$CI_TOKEN npx @zodo/zmpm install

# 7. Update all direct packages to their source spec (@latest re-resolves)
npx @zodo/zmpm update

# 8. Update just one; inspect; remove one
npx @zodo/zmpm update zodo:ai-kit
npx @zodo/zmpm list
npx @zodo/zmpm remove zodo:cookie-consent

# 9. Commit the vendored packages instead of gitignoring them
npx @zodo/zmpm add gh:zodo-dev/meteor-packages:[email protected] --no-gitignore

# 10. Build a release tarball locally (correct structure), then test it
npx @zodo/zmpm pack ./ai-kit --out zodo-ai-kit-0.2.0.tgz
npx @zodo/zmpm add file:./zodo-ai-kit-0.2.0.tgz   # install the local tarball to verify

zmpm pack guarantees the layout the resolvers expect — a single top-level folder, with .npm/, node_modules/ and VCS excluded — so a hand-rolled tar can't produce a broken (nested / missing-top-level) package.

A typical CI step for an app that vendors from a private repo:

- name: Vendor Meteor packages
  env:
    GITHUB_TOKEN: ${{ secrets.PKG_READ_TOKEN }}
  run: npx @zodo/zmpm install       # installs exactly what zmpm.json pins

Notes

  • Downloaded tarballs are source packages; Meteor compiles them locally. Build output (.npm/, node_modules/) is regenerated by Meteor — the release tarballs exclude it.
  • zmpm never runs Meteor for you — after zmpm add, run meteor add <name>.

License

Apache License 2.0 — Copyright 2026 Zodo.