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

@procedures/lib

v0.1.0

Published

Workspace procedures for pnpm monorepos: scan the packages, scaffold a new package, audit packages against a template, rename across the workspace, and program runners.

Readme

@procedures/lib

npm

npm install @procedures/lib

client-lib gives the procedures that manage the packages of the monorepo, and two runners of programs.

| Procedure | Function | |---|---| | lib.scan | Find the packages of the workspace, with their dependencies on other workspace packages | | lib.new | Make a package from the template | | lib.audit | Compare each package with the template | | lib.rename | Rename a package in each file of the workspace | | ecosystem.procedures | List the procedures of the packages | | dag.traverse | Start a procedure for each package, in the order of their dependencies | | core.catch | Start a deferred call, and give the error to a handler call |

Until October 2026, client-lib also had lib.install, lib.pull and lib.refresh, for one repository per package. The monorepo does not need them, and they are gone (DECISIONS-2026-10.md).

Use

import { Client, LocalTransport, PROCEDURE_REGISTRY } from "@procedures/client";
import "@procedures/lib"; // registers its procedures
import "@procedures/fs"; // lib.* reads and writes files through fs.*

const client = new Client(new LocalTransport({ registry: PROCEDURE_REGISTRY }));

const { packages, warnings } = await client.exec(["lib", "scan"], {});
const audit = await client.exec(["lib", "audit"], {});

The root of client-lib does not register client-fs. Without fs.*, lib.scan gives no packages and a warning for each, and lib.new and lib.rename fail. mark and the bundles load client-fs.

From the command line:

node packages/mark/dist/cli.js lib scan
node packages/mark/dist/cli.js lib new my-package
node packages/mark/dist/cli.js lib audit
node packages/mark/dist/cli.js lib rename @procedures/old-name @procedures/new-name --dry-run

The workspace root

Each procedure takes an optional rootPath. Without it, the root is the pnpm workspace that contains client-lib. With it, the folder must contain pnpm-workspace.yaml. Before, lib.new started a script from any folder that rootPath named (deep dive DATA-18).

lib.scan

Input: rootPath. The output has packages, a record by package name, and warnings. Each package gives name, repoPath, mark1russell7Deps (its dependencies in the ecosystem scopes @procedures/ and @mark1russell7/), currentBranch and gitRemote.

lib.new

Input: name (without the scope), preset (default lib), rootPath and dryRun.

The procedure makes packages/<name>. It starts cue-config init and cue-config generate, and it writes src/index.ts, src/register.ts and src/types.ts. It also sets the client.procedures field and adds a workspace:* dependency on client. Then start pnpm install and pnpm build. cue-config needs the CUE binary.

The output gives success, packageName, packagePath, created, operations and errors.

lib.audit

Input: rootPath and fix. For each package, the output gives the files and the folders of the template that are missing, and the problems of its pnpm configuration. With fix: true, the procedure makes the missing folders, and the missing files that have a default content.

The output also has flagNotices: the procedure flags whose short form is also a global flag of mark. After the command path, the flag of the procedure wins (deep dive CLI-7).

lib.rename

Input: oldName, newName, rootPath and dryRun. The procedure changes the package name, the dependencies, the imports and the dynamic imports in the workspace. The output lists each change and gives a summary.

ecosystem.procedures

Input: rootPath, namespace and includeMetadata. The output lists the procedures of the packages that have a client.procedures field.

dag.traverse

dag.traverse starts the visit procedure once for each package, with cwd set to the folder of the package. A package starts after the packages that it depends on.

| Field | Default | Function | |---|---|---| | visit | | A procedure path, or a call with $when: "$parent" (or $never) | | filter | | Only these package names | | root | | Only this package and the packages that it depends on | | rootPath | the workspace | The workspace root | | concurrency | 4 | The number of visits at the same time | | serialize | auto | When the visits in one git repository start one at a time: auto (when the visit uses a git procedure), repository (always) or none | | continueOnError | false | Continue after a failed visit | | dryRun | false | Give the plan only |

All packages of the monorepo are in one git repository. Concurrent git add commands fail on index.lock, so auto starts git visits one at a time (deep dive DATA-17).

await client.exec(["dag", "traverse"], {
  visit: { $proc: ["pnpm", "run"], input: { script: "build" }, $when: "$parent" },
  root: "@procedures/fs",
});

dag.traverse has the tag runs-refs: it starts the refs of its input. Thus a server with an expose rule lets it use only exposed procedures. A call in visit with $when: "dag.traverse" waits for this runner (PROGRAM-FORMAT.md, section 5).

core.catch

core.catch starts the try call. When it fails, core.catch starts the handler call with the error in its input (success: false, error, proc). Give both calls $when: "catch", so that they wait for this runner.

await client.exec(["core", "catch"], {
  try: { $proc: ["git", "commit"], input: { message: "auto" }, $when: "catch" },
  handler: { $proc: ["client", "identity"], input: { value: { continue: true } }, $when: "catch" },
});

The output gives success, result, error and continue. The calls of the try input start inside the error handling (deep dive DATA-22).

Related packages

  • client-dag: the graph algorithms of dag.traverse.
  • client-procedure: procedure.new, the scaffold of a procedure.
  • mark: the CLI that starts these procedures.