Skip to content

joinhottub/depwatch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

depwatch

A brand-neutral dependency-inventory core + CLI for JS/TS monorepos. Scan every workspace's declared dependencies, enrich them with the latest published version, flag what's genuinely outdated, get a one-line recommendation for each, and export the whole thing to CSV.

npm i -D @joinhottub/depwatch    # or: pnpm add -D @joinhottub/depwatch
npx depwatch --outdated          # the installed binary is `depwatch`
NAME           DECLARED          LATEST    STATUS
@types/node    ^20.11.0          22.10.5   Match your runtime
react          ^18.2.0           19.0.0    Hold — plan a migration
tsup           ^7.0.0            8.3.5     Bump when convenient
zod            ^3.22.0           3.24.1    Safe update

42 dependencies · 4 with a newer version available

Why

Most "outdated" tools answer "is there a newer version?" — which floods you with noise, because a newer version inside your declared range is not something you need to act on. depwatch answers the more useful question: "is there an update that sits outside what an install would already pull, and what should I do about it?" It's semver-aware, monorepo-aware, and gives you a reason for every recommendation instead of a wall of red.

It's also deliberately small and dependency-light (one runtime dep: semver), with a clean data-in/data-out core you can build your own dashboard or cron on top of.

CLI

depwatch [rootDir] [options]

  rootDir              Repo root to scan (default: current directory)

  --csv                Output RFC-4180 CSV instead of a table
  -o, --out <file>     Write to a file instead of stdout
  --outdated           Only show deps with a newer version outside the declared range
  --offline            Skip the npm registry (no network)
  --concurrency <n>    Parallel registry lookups (default: 12)
  -h, --help           Show help

Workspaces are auto-detected from package.json "workspaces" (npm/yarn/bun) and from pnpm-workspace.yaml. With no config it falls back to apps/* + packages/*.

Programmatic API

Everything is plain functions over plain data — no globals, no config files, no network unless you ask for it.

import {
  scanWorkspaceDependencies,
  fetchLatestVersion,
  isOutdated,
  recommend,
  dependenciesToCsv,
  type EnrichedDependency,
} from '@joinhottub/depwatch';

// 1. Pure filesystem scan — no network.
const records = scanWorkspaceDependencies(process.cwd());

// 2. Enrich with registry data (fail-soft: a blip returns null, never throws).
const enriched: EnrichedDependency[] = await Promise.all(
  records.map(async (r) => {
    const latestVersion = r.internal ? null : await fetchLatestVersion(r.name);
    return { ...r, latestVersion, outdated: isOutdated(r.ranges, latestVersion) };
  }),
);

// 3. Decide what to do, and serialize.
for (const dep of enriched) {
  const { level, action, why } = recommend(dep);
  console.log(dep.name, level, action, '—', why);
}
const csv = dependenciesToCsv(enriched);

What lives here vs. in your app

The core is intentionally just the reusable, brand-neutral bits. Persistence (a DB table), scheduling (a cron), auth, and any dashboard UI are deliberately left to the host application so this stays a small, embeddable library rather than a framework.

API surface

Export What it does
scanWorkspaceDependencies(root, opts?) De-duplicated dependency inventory across the workspace.
detectWorkspaceGlobs(root) The repo's workspace globs from package.json / pnpm-workspace.yaml.
fetchLatestVersion(name, opts?) Best-effort latest published version (fail-soft → null).
isOutdated(ranges, latest) Does latest satisfy none of the declared ranges?
recommend(dep) Rule-based { level, action, why } for a dependency.
dependenciesToCsv(rows) RFC-4180 CSV with proper escaping.

fetchLatestVersion takes an injectable fetchImpl, so it's trivial to unit-test or point at a private registry.

How "outdated" is decided

isOutdated(ranges, latest) is true only when a valid latest exists and it satisfies none of the declared ranges. So ^1.2.0 with latest 1.9.0 is not outdated (an install already gets it); with latest 2.0.0 it is. Workspace (workspace:*) deps and unparseable ranges are never outdated.

The recommend() rules then add judgment: runtime majors → hold and plan a migration; dev-only majors → bump when convenient; @types/*match your runtime, not the newest types; minor/patch ahead → safe update.

License

MIT © Hottub, Inc.

About

Dependency inventory + CLI for JS/TS monorepos — semver-aware "outdated", recommendations, and CSV export.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors