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

@app-studio/qa-seed

v0.5.0

Published

Seeds as per-feature modules composed in dependency order under a cross-process lock, plus the dependency-free HTTP verifier that doubles as the end-to-end readiness gate.

Readme

@app-studio/qa-seed

Seeds as per-feature modules, composed in dependency order under a lock — plus the dependency-free HTTP verifier that doubles as the end-to-end readiness gate.

What a seed is for

Not a foundation the system rests on. The world a given scenario needs, so it can be replayed in the same shape by anyone, forever. "An administrator invites someone who is already a member" needs a workspace, an administrator and that member; the seed for it is exactly that and nothing more.

Which is why seeds come after the API decisions, never before: data written before the API is data written against a guess.

Discovered, not declared

// src/features/identity/seed/index.ts
import type { SeedModule } from '@app-studio/qa-seed';

const seed: SeedModule<AppContext> = {
  key: 'identity',
  async run({ auth }) {
    const admin = await auth.signUp({ email: '[email protected]', password: 'password123456' });
    return [{ name: 'identity.adminId', value: admin.id }];
  },
};

export default seed;
const modules = await discoverSeedModules({ rootDir, pattern: 'src/features/*/seed/index.ts' });
await runSeed({ rootDir, modules, context });

Dropping the file into a feature makes it seed; deleting the feature deletes its seed. There is no central list, because a central list is the thing that silently goes wrong: a feature is removed, its entry stays, and the next person to read the list believes in a feature that no longer exists.

Three rules that are not style preferences

Call the real services, never SQL. An administrator inserted into a members table is a different administrator from one who accepted an invitation — no audit entry, no analytics event, no realtime publish. Every test that then relies on those side effects is testing a world the application cannot actually produce.

Declare the order; do not assume it. File order is not a dependency graph, and a seed that happens to work because of how a glob sorted its inputs breaks the day someone renames a feature. composeSeeds topologically sorts by dependsOn, names the cycle when there is one, and is deterministic so two runs of one registry produce one order.

Idempotence is the property that breaks. A seed run twice against a database somebody forgot to reset must produce the same world, not a second copy of it.

The lock

runSeed holds a cross-process lock for the duration. Not caution: two seed runs against one database interleave into a state neither of them describes, and the resulting failures look like application bugs — a row that exists twice, a unique constraint firing on data the code never wrote.

The lock is keyed by checkout, so two worktrees seed concurrently and two shells in the same checkout do not. A stale lock is reported with the holder's details and the exact command to clear it, never deleted automatically — two waiters can both observe a dead holder and both delete the file, and the second delete evicts a lock the first has just legitimately taken.

Verifying, over HTTP

import { expectNonEmpty, verifySeed, waitForSeed } from '@app-studio/qa-seed';

export const checks = [
  expectNonEmpty(
    'a workspace exists',
    '/api/workspaces',
    'Every journey signs in and lands in a workspace; with none seeded, they all fail on the first screen.',
  ),
];

Over HTTP and not over SQL, deliberately. In an end-to-end run the API often holds the only connection to the database — an embedded engine, a pooled connection, a container the test process cannot reach — so a SQL verifier would either fail to connect or, worse, connect to a different database and cheerfully report success.

Every check carries a proves line, and the report prints it. "Expected 1, got 0" sends somebody to read the check; "with none seeded, they all fail on the first screen" sends them to fix the seed.

The same function is the readiness gate. Nothing that drives a browser should start before it passes: a UI suite launched against an unseeded database fails somewhere in the middle of a screen, with a screenshot of an empty list and nothing saying the data was never there. qa e2e runs this between starting the API and starting anything a browser will talk to.

waitForSeed is the same checks with a deadline, for the boot window. Failure reports what was still wrong, not just that time ran out.

Exports

| Export | Purpose | | --- | --- | | SeedModule, composeSeeds | The unit, and the dependency-ordered composition. | | discoverSeedModules | Find them by looking. | | runSeed | Run them in order, under the lock, collecting published artifacts. | | verifySeed, waitForSeed, formatVerifyReport | Prove the world is there. | | expectNonEmpty, expectJson | The commonest checks, written out. |

Requirements

Node.js 20 or newer. No runtime dependencies beyond @app-studio/qa-core and a glob — the verifier in particular is dependency-free so it can run anywhere, including in a container that has nothing else installed.