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

cursedops

v0.4.0

Published

The build-and-ops answers this generation's apps wrote independently and identically: finding a generation's roots without knowing a path, macOS launchd agent install/replace/remove, the scaffolding of a deployed smoke, and the static-serving helpers eigh

Readme

cursedops

Build-and-ops answers that the apps here wrote independently and identically.

bun add cursedops

| subpath | what it is | |---|---| | cursedops/roots | finding a generation's roots, and a checkout's package root, without knowing a path | | cursedops/launchd | installing, replacing and removing a macOS launchd user agent | | cursedops/smoke | the scaffolding of a deployed smoke — the ledger, the fetch, the DNS hint, the exit code — and the one check no app owns: every address of a deployment serving the same built client | | cursedops/serve | the static tier's four helpers — the path-traversal guard, the MIME table, the hashed-asset test, the crash handlers | | cursedops/api-floor | the rule that an unmatched /api/... is a phrase and never the app shell — the namespace predicates, the trailing-slash normaliser and the default 404 body. No node: import, so it mounts inside a Worker | | cursedops/build-info | which commit a checkout-served process is running and whether its tree was dirty — read once at load, and a null retried in the background rather than cached for the life of the process. node:child_process, so never in a Worker | | cursedops/bound-lists | the static check that no SQL builds an IN (…) list one ? per value — the shape D1 500s on past 100 ids. Test-time only; the recorded third exception, see below | | cursedops/public-surface | the ratchet on a LIBRARY's public surface — a symbol count per export subpath against a committed baseline that may only fall — and its public-surface bin. Not an app's: the one entry here admitted for three published libraries, see below |

Bun, zero runtime dependencies, ships TypeScript source. Nothing here knows an app's name, a hostname, a port or a route. typescript is an optional peer: only cursedops/public-surface imports it, and nothing else here ever loads it.

🔴 The ceiling, and why this library has one

This exists because apps/desk and apps/flix answered the same six build-and-ops questions independently, and three of the six came out the same. It does not exist because sharing is good.

The library it replaces reached 277 files in a previous generation, on the reasoning that a module used by 8 of 8 apps is a module worth sharing. What that produced was an app whose entire vite.config.ts was one line it could not read, a build system no app could opt out of, and a monorepo that could not be relocated. Every one of those 277 files was individually defensible.

So the entry rule here is arithmetic, not judgement:

  1. Two apps wrote it independently. Not one app and a plan for a second — two working implementations, in the tree, that a diff says are the same.
  2. It is mechanism, not identity. If a function would need to know an app's name, port, hostname, routes or health-payload shape, it belongs in the app. Every function here takes those as arguments or does not see them at all.
  3. It is a trap somebody paid for. Each thing in here is a measured incident turned into a check — the file headers carry the dates and the costs. A convenience that has never prevented anything is not a reason to add a dependency to eight apps.

A fourth rule follows from the first three: an addition that only one app will use does not go in. That is a library that exists to be refactored later.

🔴 sameDeployedShell is the one entry that rule 1 did not let in, and it is recorded here rather than quietly excepted. It was written once, by patterns, not twice — what admits it is rule 3 at a size rule 1 cannot measure: the fault it catches was invisible for six days on the app that had it, and the other five apps behind or moving behind an edge Worker still cannot tell a working deploy from a working cache. A check told ONE NAME is a check about that name; this one is about a property every deployment with two addresses has. It buys the exception by being pinned to a failure it has actually caught — src/smoke.test.ts runs it against the genuine 2026-09-12 shell.

🔴 public-surface is the second recorded exception, and the first whose callers are not apps. Rule 1 is met — more than met — but by three LIBRARIES: cwip, cursedbelt and cursedbelt-server each carried scripts/publicSurface.ts (430, 455 and 476 lines), and by 0.2.6 the bodies had already forked, which is what admits it. Measured 2026-09-22: cwip's threw on a bare-specifier export * where the other two resolved and counted it, so the three numbers were not commensurable; and when the ESM-extension fix (task 269) made ./x.js the spelling of an internal specifier, cursedbelt-server's and cursedbelt's copies each had to be taught ./x.js./x.ts by hand, separately, while cwip's never was. Each library is published on its own and its gate must pass from a lone checkout, so neither a file: import nor a reach into $FORGE/tools could share it; a published version could, and this package is already that for the fleet. It is a devDependency of each library, so nothing their consumers install changed. On adoption all three measured identical per-subpath counts to their own copies (cwip 60 subpaths/2,089 symbols, cursedbelt 51/1,837, cursedbelt-server 34/992) — a consolidation that moves a count has changed the measurement, not the plumbing.

🔴 bound-lists is the third recorded exception, admitted by rule 3 at three consumers. It was written once, by collections (src/server/boundLists.test.ts, 2026-09-22), after the shape it refuses drew an empty gallery for every folder over 100 files on D1. The same day music was found carrying 24 sites and vault four — the identical trap in two more D1 Workers — so the choice was two more copies of the scanner or one here. Copies are what check-copies exists to refuse, and a forked scanner is a check that quietly stops matching. It is mechanism only: each app passes its own root and directories and keeps its own "not vacuous" assertion about which files the scan must reach.

What was deliberately left in the apps

The comparison that produced this library found three areas that are genuinely different and must stay that way. tasks/Procedures/graduate-an-app.md in the generation repo carries the full verdict table, because the next app to graduate is who needs to read it:

  • the builddesk compiles a single binary with bun build --compile; flix is a Vite SPA with an asset budget. Not the same problem.
  • the supervisordesk runs a watcher that rebuilds on a commit; flix deliberately has none, and its deploy reinstalls the agent instead. That difference changes what a rollback is in each app.
  • the app config — how an app decides it is deployed, and what that turns on, is the app.

deploy.ts is a fourth: the two scripts share a shape and roughly thirty lines of helpers, but they sequence genuinely different steps and a shared deploy driver is exactly the 277-file mistake starting again. What they share instead is the exit-code contract in cursedops/smoke0 keep, 1 roll back, 2 edge fault, do not roll back — which is the only part both deploy scripts actually read.

cursedops/roots

import { forgeRootFrom, packageRootFrom, requireForgeState } from "cursedops/roots";

const generation = forgeRootFrom(import.meta.url);   // string | null
const checkout = packageRootFrom(import.meta.url);   // string | null
const state = requireForgeState(import.meta.dir);    // string, or a thrown message

A generation is defined by a forge.env above the checkout — the same rule its check-paths and its runner use, so the three cannot disagree. Everything returns null rather than guessing, because a function that invented a root would write files into a stranger's tree.

🔴 A git worktree counts (0.2.5). Worktrees live outside every generation by construction, so the walk up alone answered null there and a repo whose gate asks for the root was red in every worktree — the runner's subset gate included. When the walk fails, git rev-parse --git-common-dir leads back to the primary checkout and the walk runs from there. A clone is its own primary and still gets null.

🔴 The state root is read out of forge.env, never spelled here. A published library that hardcoded $HOME/.<name> would be correct for exactly one generation and silently wrong for its successor — which is the defect this replaced.

cursedops/launchd

import { renderPlist, replaceAgent, answering, declaredBy } from "cursedops/launchd";

const conflict = await declaredBy(LABEL, "managed-by=olddeployer");
if (conflict) throw new Error(`a retired deployer still declares ${LABEL}: ${conflict}`);

const { boot } = await replaceAgent(LABEL, renderPlist(spec), { also: LEGACY_LABELS });
if (boot.code !== 0) throw new Error(boot.out);
if (!(await answering(`http://127.0.0.1:${port}/healthz`))) throw new Error("a pid is not a service");

RunAtLoad and KeepAlive are not defaulted — a server wants both, a nightly snapshot wants neither, and a kit that decides gets one of them wrong.

cursedops/smoke

import { createSmoke, guarded } from "cursedops/smoke";

const smoke = createSmoke({ base: process.env.MYAPP_SMOKE_URL ?? "https://…" });
await guarded(smoke, "gate", async () => {
  const response = await smoke.anonymous("/api/v1/private");
  smoke.record("gate", response.status === 401, `anonymous → ${response.status}`);
});
smoke.finish();   // exits 0, 1 or 2

One check, and it is about the ADDRESSES of a deployment rather than about any app:

import { sameDeployedShell } from "cursedops/smoke";

// every address of one deployment, not "edge vs origin" — an app may have no
// origin left. A Worker's second address is its uncached *.workers.dev preview.
await sameDeployedShell(smoke, [smoke.base, `http://127.0.0.1:${port}`]);

🔴 It refuses when the addresses name different built assets, and it records that as an edge fault (exit 2), never a rollback — the origin is serving what this checkout built, and reverting it cannot reach the Worker, cache rule or Assets binding in front. Measured 2026-09-18 on patterns: the edge served a shell built 2026-09-12 out of a Worker nobody knew about, and every automated surface stayed green for six days. Only same-origin .js/.css references are compared, because the zone injects a Web Analytics beacon in front of the edge and not on loopback — a check that reds on a healthy deploy is one somebody turns off.

Nothing else. The checks are the part desk and flix wrote differently on purpose, and a shared kit that starts absorbing route lists and health-payload shapes is how the last one reached 277 files.

cursedops/api-floor

import { API_PREFIX, apiNotFoundBody, canonicalApiPath, canonicalApiRequest } from "cursedops/api-floor";

// AFTER the app's routes, BEFORE the static catch-all, and `all` not `get`.
const floor = (c) => {
  const urlPath = new URL(c.req.url).pathname;
  // A trailing slash is never meaningful under /api/ — re-dispatch, once.
  if (canonicalApiPath(urlPath) !== null) return app.fetch(canonicalApiRequest(c.req.raw));
  return Response.json(apiNotFoundBody(c.req.method, urlPath, "myapp", commit), { status: 404 });
};
app.all(API_PREFIX, floor);
app.all(`${API_PREFIX}/*`, floor);

🔴 Measured 2026-09-17 on station: a page that had never loaded on any commit, because its client asked for /api/openclaw/, Hono mounts a sub-app's get("/") at the mount point without the trailing slash and matches strictly, and the miss fell into app.get("*") and came back as 1.7 KB of index.html with a 200. The client read that HTML honestly — "an API older than this page" — and sent the owner to deploy a commit that could not have helped.

🔴 Wire it inside the router, never as a wrapper around the host's fetch. A router has more callers than Bun.serve — a Worker's export default, and every harness that drives app.fetch — and a wrap installed at one of them is absent from the rest. That is the exact fault the previous generation's artifact shipped for six days with a green harness.

Both patterns are registered although "/api/*" alone already matches a bare /api on [email protected] (measured 2026-09-18) — that is an undocumented property of one matcher version, and one extra route registration is cheaper than a floor with a hole in it the day it tightens.

No node: import, no Bun. global, no process — asserted by apiFloor.test.ts, not by this paragraph — so it mounts unchanged inside a Cloudflare Worker, which is where patterns mounts it. apiNotFoundBody is the DEFAULT body and not the only one: an app whose API namespace is not behind a gate keeps a terser phrase of its own and takes the predicates.

cursedops/serve

import { contentTypeFor, fileWithin, installCrashHandlers, isHashedAsset } from "cursedops/serve";

installCrashHandlers("myapp");                        // one log line, then exit 1
const file = fileWithin(clientDir, url.pathname);     // null unless it is really inside
if (!file) return c.notFound();
return new Response(Bun.file(file), {
  headers: {
    "content-type": contentTypeFor(file),
    "cache-control": isHashedAsset(url.pathname) ? ONE_YEAR : "no-cache",
  },
});

🔴 fileWithin is the reason this subpath exists rather than the convenience of the other three. It is the check that stops %2e%2e%2f reaching the filesystem, and on 2026-09-17 there were eight of it — one per app, character-identical, with nothing in the generation counting them. Eight copies of a security guarantee are eight guarantees: a fix in one is a fix in one.

The verdict for every symbol in the serve.ts family

Measured 2026-09-17 across collections, family, flix, music, patterns, roms, station and vault — the eight apps that have a src/server/serve.ts. The files are 247–387 lines and all eight differ, which is why no diff ever flagged them; the bodies below were compared with whitespace and comments normalised away.

| symbol | identical in | verdict | |---|---:|---| | fileWithin | 8 of 8 | moved. The traversal guard. Entry rule 3 — a trap somebody paid for — in its purest form | | installCrashHandlers | 8 of 8 | moved. The app's name is a parameter; it is the only app-shaped thing the four touch | | contentTypeFor | 8 of 8 | moved. Extension → MIME, plus its private CONTENT_TYPES table, which was also 8 of 8 | | isHashedAsset | 8 of 8 | moved. Vite's own output convention, which is the bundler's identity and not the app's | | clientDirOf | 6 of 6 that have it | stays. One line, and six apps pin it with their own clientDir.test.ts against their own vite.config.ts. WHERE an app's build writes is app identity — entry rule 2 — and it is the line that once served public/ and took a live app down | | createServer / createApp | 0 — all eight differ | stays. Route tables, health payloads, gates and body limits. This is the 277-file mistake's front door | | parseRange / fileResponse | flix and station only | stays for now. Two apps, so rule 1 is satisfiable, but rule 3 is not: nothing has been paid for yet, and a Range implementation shared by two apps that stream different things is a guess. The trigger to revisit is a THIRD app that needs byte ranges | | API_PREFIX, isApiPath, canonicalApiPath, canonicalApiRequest, apiNotFoundBody | station only | stays. One app, and rule 4 says an addition one app will use does not go in. apiNotFoundBody also writes a sentence the owner reads on a page — identity, not mechanism |

🔴 The task that ordered this move recorded contentTypeFor and isHashedAsset as 7 of 8, with station differing. They did not differ. All four bodies were identical in all eight apps when the move was made, so nothing had to converge and no app's behaviour changed on adoption. The count came from a census of the whole serve.ts family rather than of these two bodies; bun tools/check-copies.ts in the generation repo is the live answer either way.

One behaviour is NOT a byte-for-byte carry, and src/serve.ts's header argues it in full: the eight copies checked containment lexically and were therefore blind to a symlink under the root pointing out of it. fileWithin here resolves the real path of both sides after the lexical check, which refuses the escape while leaving every input the eight copies refused refused, at the same cost. A symlinked ancestor of the root cancels out — which is the failure a one-sided realpath would have shipped to every app on this machine, and is its own test.

cursedops/public-surface

# in the library's package.json — `bun run surface` / `bun run surface --prune`
"surface": "public-surface"            # cwip adds --peers
import { run } from "cursedops/public-surface";

const { fresh, grown, stale, peers } = await run({ root: packageDir });   // all four [] when clean

publicSurface.baseline at the package root is one <count> <subpath> line per export subpath. It fails on a subpath the baseline does not list, on one that GREW, and on an entry that shrank or matches nothing — so a deleted module cannot leave an allowance behind. --prune only ever lowers; new surface is a line added by hand in a commit that says why. What a count includes and excludes, and the three measurements that each produced a copy of this, are in the header of src/publicSurface.ts.

It is a check a library runs on ITSELF. It never asks who imports the library — that is cross-repo, and a repo's gate proves that repo.

Verifying

cd "$FORGE/libs/cursedops" && bun run verify

paths, typecheck, lint, then the suite. It runs as prepublishOnly, so a publish cannot go out around it.