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

@speqkit/installer

v0.3.0

Published

Resolves plugins against the npm registry, verifies them, and puts them in the store. No npm CLI involved.

Readme

@speqkit/installer

Resolves plugins against the npm registry, verifies them, and puts them in a store. It never shells out to npm, pnpm or yarn.

That restriction is the whole point. A Go service should be able to run speq tests without a package.json, a node_modules, or a Node toolchain — so the one thing the installer cannot do is require the package manager it is replacing.

The split

The registry is npm. The installer is ours. Building a registry would mean building auth, mirroring, takedowns and trust, for nothing: every plugin author already has an npm account and npm publish already works. Building the installer is what keeps a Node project's furniture out of a repository that is not a Node project.

The store

Plugins live once per machine, in ~/.speq (or $SPEQ_HOME), never in the project:

~/.speq/store/
  @[email protected]/
    node_modules/
      @speqkit/plugin-http/          the package itself
      semver -> ../../[email protected]/node_modules/semver

The layout is pnpm's, for pnpm's reason: a dependency is a symlink that sits inside the depending package's own directory, so Node's ordinary resolution — which follows real paths — still finds it, and two plugins wanting different versions of the same library each get their own. Links are relative, so the store stays movable.

The project commits one file: speq.lock.

lockfileVersion: 1
presets: []
plugins:
  - spec: "@speqkit/plugin-http@^2.1.0"
    name: "@speqkit/plugin-http"
    version: 2.1.4
packages:
  "@speqkit/[email protected]":
    resolved: https://registry.npmjs.org/@speqkit/plugin-http/-/plugin-http-2.1.4.tgz
    integrity: sha512-…
    dependencies:
      "@speqkit/plugin-api": 1.4.0

Two passes, because presets come first

A preset is an ordinary npm package that contains a speq.yaml, and extends: "@acme/speqkit-preset" is how one platform team pins the plugin set for thirty services at once. That creates an ordering problem: the config cannot be read until the package it extends is on disk. So install() takes two callbacks rather than two lists — it fetches the extends targets, and only then asks for the flattened plugin list.

Where a plugin can come from

plugins:
  - http                                       # the registry, short name
  - "@acme/speqkit-plugin-legacy@^2.1.0"       # the registry, private scope
  - github:acme/speqkit-plugin-legacy#v2.1.0   # a repository
  - git+ssh://[email protected]/qa/plugin.git#main
  - https://builds.acme.dev/plugin-1.4.0.tgz   # a packed tarball

github:, gitlab: and bitbucket: are shorthands for the obvious HTTPS URL; git+https:, git+ssh:, git+file: and git: are passed to git as written. A #ref is a branch, a tag or a commit, and no #ref means the default branch.

Repository sources shell out to git, and that is a deliberate exception to the rule that governs the rest of this package. speq install speaks the npm registry's HTTP API itself because npm is the tool being replaced — requiring it would cancel the whole idea. Git is not being replaced by anything, it is already on the machine of whoever owns the repository, and going through it buys three things hand-written HTTP would not: private repositories work through the credentials and ssh agent that are already set up, self-hosted hosts need no per-vendor API dialect, and the commit is verified by git rather than trusted from a vendor's JSON. Only a git spec needs git — nothing else here does, including inside the standalone binary.

A ref is resolved to a commit at install time, and only the commit is locked. #main in speq.yaml means something different next month; --frozen in CI installs the commit that was reviewed. The store keys the checkout by that commit as semver build metadata — 1.4.0+8f2c1ade9b7c — because two commits can carry the same version, and a dependent asking for ^1.4.0 should still be satisfied.

No build ever runs. Not running install scripts is what makes installing from a repository defensible at all, so a repository whose entry point is not committed is refused at install time with the reason, rather than installing cleanly and failing to load minutes later inside a plugin loader that cannot say why.

A tarball URL is hashed on arrival and the hash goes in the lock, since no registry published one to compare against. The registry token is never sent to a host that is not the registry.

Things it refuses to do

  • Follow a link entry in a tarball, or write a path containing .. or a leading /. This is the one place an installer reliably grows a security hole; both are refused loudly rather than sanitised quietly.
  • Install a tarball whose hash does not match what the registry published.
  • Think for itself under --frozen. It replays the lock, and fails if speq.yaml has drifted from it, which is exactly the mistake CI exists to catch.
  • Delete anything on speq remove. The store is shared; a plugin one project stopped using is still cached for the next.

Not built yet

  • Reading .npmrc. A private registry works through SPEQ_REGISTRY and NPM_TOKEN.
  • A repository that depends on another repository. A package's own dependencies are resolved from the registry whatever the package itself came from, because that is what a range in a package.json means.

The standalone binary used to be on this list. It is now built by scripts/build-binary.mjs and installed with brew install speqkit or curl … | sh, so nothing here needs a Node runtime on the machine. The store it writes to and the lock it replays are the same either way — the binary is a different way of shipping this code, not a different code path through it.