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

ts-flight

v1.0.0

Published

Flight recorder for Node.js processes: runs a target script as a child process, attaches a probe, and records memory, CPU, event-loop delay, active handles, stdio and crashes into a single JSON/HTML/Markdown report.

Readme

Flight Recorder

A profiler for Node.js processes. Flight runs a target script as a child process, attaches a probe to it, and records what the process did while it ran: memory, CPU, event-loop delay, active handles, stdio, and crashes. When the child exits it writes a single JSON report, and optionally an HTML and Markdown view of the same data.

HTML report

How it works

Flight never instruments your code. It spawns

node --import probe/register.ts <target> [target args...]

The probe (probe/register.ts) runs inside the child before the target loads. On a fixed interval (--sample-ms, default 250 ms) it samples process.memoryUsage(), process.cpuUsage(), the event-loop delay histogram (monitorEventLoopDelay), and active handles, and it listens for warning, unhandledRejection, and uncaughtException. Each sample is appended as one JSON line to an NDJSON file under out/.

The parent (src/run.ts) owns the child: it forwards SIGINT/SIGTERM, enforces --timeout-ms, and force-kills after --kill-timeout-ms if the child ignores the shutdown signal. When the child closes, the parent reads the NDJSON stream, folds it into a canonical report (src/report.ts, schemaVersion: 1), and writes it out.

Requirements

Node.js with native TypeScript support and --import of .ts files (developed on Node 24). No build step, no runtime dependencies — @types/node and typescript are dev-only.

Usage

Run a target and write the default JSON report (reports/flight.json):

npm run flight -- fixtures/hello.ts

Write the HTML and Markdown views as well:

npm run flight -- --html reports/flight.html --markdown reports/flight.md fixtures/buffer-leak.ts

Flight exits with the child's exit code, so it slots into a shell pipeline or CI step unchanged.

Run options

| Flag | Description | | --- | --- | | --json <path> | JSON report path (default reports/flight.json) | | --html <path> | Also write a self-contained HTML report | | --markdown <path> | Also write a Markdown summary | | --sample-ms <ms> | Probe sample interval (default 250) | | --timeout-ms <ms> | Stop the target after this deadline | | --kill-timeout-ms <ms> | Force-kill after a forwarded shutdown (default 5000) | | --env KEY=value | Set a child environment variable (repeatable) | | --env-file <path> | Load child environment values from a file | | --node-flag <flag> | Pass a Node runtime flag to the child (repeatable) | | --runs <n> | Run the target n times and aggregate (default 1) | | --max-rss <bytes> | Exit 1 if peak RSS exceeds this | | --max-loop-delay-ms <ms> | Exit 1 if max event-loop delay exceeds this | | --fail-on-failures | Exit 1 if the child records any fatal failure | | --intermediate-reports | Also write the per-aspect debug files under reports/ |

Secret-looking child environment values (keys matching TOKEN, SECRET, PASSWORD, KEY, CREDENTIAL) are redacted in the report.

Budget gate

--max-rss, --max-loop-delay-ms, and --fail-on-failures turn a run into a pass/fail check. Each breach prints a BUDGET VIOLATION: line to stderr and forces a non-zero exit, so a single run can guard a threshold in CI:

npm run flight -- --max-rss 134217728 --fail-on-failures fixtures/buffer-leak.ts

Multi-run aggregation

A single run is noisy. --runs N runs the target N times sequentially, writes each run to reports/runs/run-NN.json, and writes an aggregate report whose standard numeric fields hold the mean across runs:

npm run flight -- --runs 5 --json reports/agg.json --markdown reports/agg.md fixtures/hello.ts

The aggregate keeps the canonical report shape, plus an aggregate block with mean / p95 / min / max / stddev and the raw per-run values for each metric. Because the shape is unchanged, compare reads an aggregate report directly (see below).

Comparing reports

compare diffs two or more reports against a baseline and writes a Markdown table of deltas:

npm run flight -- compare reports/before.json reports/after.json --markdown reports/diff.md

The first input is the baseline unless you pass --baseline <path>. It compares duration, peak memory (RSS / heap / external / array buffers), total CPU, max event-loop delay, exit status, and warning / failure counts.

--fail-on-regression <percent> makes compare exit 1 when any metric worsens beyond the given percentage versus the baseline — pairing aggregate reports with this flag gives a statistically meaningful regression check.

Reports

  • JSON — the canonical report. Stable schemaVersion, consumed by compare. This is the source of truth.
  • HTML — a self-contained page (shown above): summary cards, a metrics table, a warnings/failures table, and the event timeline.
  • Markdown — a short summary table plus a timeline excerpt, for pasting into a PR or issue.

Layout

probe/register.ts   probe injected into the child via --import
src/run.ts          spawns the child, owns signals/timeouts, parses the probe stream
src/report.ts       buildReport (canonical JSON) + HTML and Markdown renderers
src/aggregate.ts    --runs aggregation (mean/p95/min/max/stddev)
src/compare.ts      compare mode: baseline diff, regression gate
src/budget.ts       --max-rss / --max-loop-delay-ms / --fail-on-failures checks
src/cli.ts          argument parsing and the run / compare entry points
src/utils.ts        probe parsing, formatting, and stat helpers
fixtures/           sample targets (leaks, CPU loops, warnings, crashes, servers)

Fixtures

fixtures/ holds targets that exercise specific behaviours — buffer-leak.ts grows RSS, cpu-loop.ts burns CPU, warning.ts emits a process warning, unhandled-rejection.ts and uncaught-exception.ts crash, hanging-server.ts keeps the event loop alive. Use them to see what each section of a report looks like.

Credits

Built as a lab following @ishtms's Node.js material.