3.1 KiB
discover/discover.ts
(no submodules)
Purpose
Implements the filesystem walker that produces a validated SuavePlanManifest
from a populated packages/<category>/<plugin>/<pkg>/package.json tree. Both
the synchronous discoverPackages and the async discoverPackagesIter live
here. The module is the only server-tier surface in @suaveplan/overview; it
ships under the ./discover sub-path export so universal consumers can avoid
the node:fs / node:path imports entirely.
Discovery is straightforward: walk three directory levels deep, read each
package.json, infer its tier, collect workspace deps, validate against
PackageRecordSchema, then aggregate the resulting rows into a manifest.
Features
- Synchronous
discoverPackagesreturning a fully-validated manifest - Async
discoverPackagesIterhonouringAbortSignal onError: "throw" | "skip"for graceful handling of malformedpackage.jsonfiles- Optional
tierHintsextendingSERVER_DEP_HINTS - Emits
overview.packages_discovered_total,overview.records_rejected_total{reason}, andoverview.discover_duration_ms - Built-in roll-up so the manifest carries
plugins,categories, andtierCountsready for consumption
Usage: Basic
import { discoverPackages } from "@suaveplan/overview/discover";
const manifest = discoverPackages({ root: process.cwd() });
console.log(`Found ${manifest.packages.length} packages.`);
Usage: Advanced
import { discoverPackagesIter } from "@suaveplan/overview/discover";
const controller = new AbortController();
setTimeout(() => controller.abort(), 5_000);
try {
for await (const r of discoverPackagesIter({
root: "/repo",
signal: controller.signal,
onError: "skip",
tierHints: new Set(["custom-native-binding"]),
})) {
process.stdout.write(`${r.name}\n`);
}
} catch (err) {
// OverviewError with code OVERVIEW.DISCOVERY_ABORTED when the signal fired.
}
onError: "skip" is the right mode for tooling that should never abort on a
single bad package.json (e.g. a long-running watcher); "throw" is right for
one-shot CLIs that prefer a hard fail on corruption.
API Reference
discoverPackages(options: DiscoverOptions): SuavePlanManifestdiscoverPackagesIter(options: AsyncDiscoverOptions): AsyncGenerator<PackageRecord>interface DiscoverOptions { root, onError?, tierHints? }interface AsyncDiscoverOptions extends DiscoverOptions { signal? }type DiscoveryErrorMode = "throw" | "skip"
Implementation Notes
The walker enforces exactly three directory levels (category → plugin →
package). Anything shallower or deeper is silently ignored — partial-migration
trees are common and a permissive walker keeps the tooling robust.
existsSync + statSync are used to filter non-directories and packages
without a package.json; both are cheap on a populated tree because the OS
will have cached the directory listings. The histogram observation uses
performance.now() when available (it always is in Node 20+/Bun) and falls
back to Date.now() otherwise.