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

e3d-netdoctor

v1.0.0

Published

Standalone CLI scaffold for local network slowdown diagnosis.

Readme

e3d-netdoctor

Point it at your network. Get told why it's slow.

A one-shot, no-UI CLI that captures live traffic and figures out whether your slowdown is your ISP, your own device, or one flaky destination — with its reasoning shown, not a black-box score. It's just as useful run by hand as it is scripted into automation, and it's built especially well for agents: the default output is the same structured JSON an agent already reasons over, no prose to re-parse and no UI to drive.

No dashboard. No account. No continuous monitoring. Run it, get an answer, move on.

Free to run locally (capture + report, no payment, no account, a deterministic template narrative). The one-shot paid-report command — capture, analyze, and get a report with a real AI-written narrative in a single call — is $5 by credit card via Stripe (--card, no crypto or wallet needed), or payable with E3D Token if you already hold it.

$ e3d-netdoctor paid-report --interface en0 --duration 30

Only analyze traffic on networks you are authorized to monitor.
Requesting e3d payment before capture/analysis...
{
  "requestId": "netdoctor:...",
  "payment": { "product": "netdoctor", "creditsSpent": 500, "creditsRemaining": 1500 },
  "findings": {
    "verdict": {
      "headline": "Likely upstream/ISP",
      "confidence": "High",
      "rationale": "7 of 8 independent destinations affected, spanning 3 different providers"
    }
  },
  "narrative": { "..." : "..." }
}

Why this exists

Every network engineer and Wireshark user has had this conversation:

"Is it my wifi, or is it Comcast again?"

That question is answerable from a single packet capture — if you know to group retransmissions and RTT outliers by destination and by local device, and weigh provider diversity instead of raw destination count. Most people don't do that math by hand. netdoctor does, every time, and shows its work.

Humans, automation, and agents — but agents especially

  • Humans get a one-shot answer without learning Wireshark: run report, read a plain-English verdict with its reasoning, done. --format markdown/html and --to make it easy to read in a terminal, a browser, or an inbox.
  • Automation/CI gets deterministic exit codes, no interactive prompts, and a non-interactive payment path (a pre-provisioned e3d credit key) — safe to run unattended on a schedule or in a pipeline.
  • Agents get the most out of it, because the whole tool is shaped like a single tool call: one command, one JSON result. The default report output is { findings, narrative } — the same structured shape an agent already reasons over, not prose it has to re-parse. The verdict is deterministic and rule-based (not another LLM call an agent has to trust blindly), the rationale is machine-readable text an agent can quote directly back to a user, and there's no UI, login, or browser interaction required for the core flow — only the optional wallet payment path below touches a browser, and only because that step inherently requires a human to approve a transaction.

What it actually does

  1. Captures a short live packet trace (tshark), or takes a .pcap you already have.

  2. Extends the parse with TCP-health signals the vendored e3d-pcap parsing core (src/vendor/) doesn't collect on its own: retransmissions, duplicate ACKs, out-of-order, zero-window stalls, per-flow RTT (SYN→SYN-ACK), and DNS response timing.

  3. Corroborates with host-level checks that don't depend on the capture at all — real ping and traceroute to the destinations the capture flagged, and netstat for local NIC error/collision counters and TCP-stack retransmit stats.

  4. Scores a verdict — deterministic, rule-based, unit-tested — into one of three categories:

    | Verdict | Means | |---|---| | Likely Upstream/ISP | Signal spread across many unrelated destinations and providers — not one device | | Likely Local | Signal concentrated on one local device (MAC) across many destinations — bad wifi, flaky NIC, bad cabling | | Likely Destination/Path-Specific | Signal confined to one or two destinations while everything else is clean |

    Confidence is always shown as reasoning ("7 of 8 destinations, 3 providers"), never a bare number. netdoctor always commits to one of these three — it never answers "inconclusive." With thin data it still picks the closest match and says so plainly in the rationale ("only 2 of the required 3 distinct destinations were observed"), rather than declining to call it.

  5. Writes the report. report/deliver (free) build a deterministic, template-based executive summary and per-section narrative straight from the structured findings — no AI call, ever, even if you have an API key set. paid-report always writes a real AI narrative instead — Claude or OpenAI using your own key if you have one configured, otherwise generated by e3d's own key as part of the $5 — grounded strictly in the same structured findings (never raw packets).

  6. Delivers it by email, with an optional PDF attachment.

  7. Gates paid-report behind an e3d pay-per-report payment — fails closed, no free runs, clear message on how to pay if it's missing. Pay with a pre-provisioned credit key (for automation), or with an E3D Token (wE3D) wallet directly (for a human with no e3d account) — see Paying for a report below.

Paying for a report

paid-report runs the same capture → verdict → report pipeline above, gated behind one payment of 500 e3d credits (0.5 E3D or wE3D at the current unit price, depending on payment method). Unlike report, the narrative is always written by a real AI model, not the deterministic template — using ANTHROPIC_API_KEY/OPENAI_API_KEY if you have one set, or e3d's own key otherwise, paid for out of the same 500 credits. Like report, it defaults to printing JSON to stdout — here that's the payment receipt plus findings/narrative — with --format/--output/--to working exactly the same way; email is opt-in via --to, not automatic.

How credits are remembered and used

A credit key's balance lives entirely on e3d's server — it's a running total (credits purchased minus credits spent) for that key, scoped to netdoctor. Buying more credits doesn't reset anything; it just adds to that same balance, and it never expires on its own. See docs/payment-gate.md for exactly how that balance is computed.

What the CLI itself remembers locally, on disk, depends entirely on which of the three payment methods below you use:

| Method | Remembered locally? | |---|---| | NETDOCTOR_PAYMENT_CREDIT_KEY (env var) | No — it's already yours to manage; the CLI only ever reads it. | | --card [packId] | No. The key is printed once after checkout and never cached — copy it into NETDOCTOR_PAYMENT_CREDIT_KEY yourself if you bought a multi-report pack and want to reuse it. | | --wallet <address>, one-off (no --credits) | No, by design — every run pays for exactly that one report. | | --wallet <address> --credits n, batch mode | Yes. The key and its last-known remaining balance are saved to ~/.config/e3d-netdoctor/config.json, keyed by wallet address, and reused automatically on future --wallet runs until the balance drops below one report's cost (500 credits) — at which point netdoctor buys another batch. |

In short: only wallet batch mode gets automatic local memory. Every other path either requires you to hold onto the credit key yourself, or intentionally starts fresh every time. There are three ways to pay, aimed at three different users:

  • A pre-provisioned credit key (NETDOCTOR_PAYMENT_CREDIT_KEY) — for automation, CI, or anyone who already has an e3d account funded ahead of time. Non-interactive: no browser, no prompts, safe to run unattended on a schedule.

  • --card [packId] — for a human who'd rather not touch crypto at all:

    e3d-netdoctor paid-report --interface en0 --card

    Prints a Stripe Checkout URL; open it, pay with a card, and netdoctor picks up automatically once the payment completes. packId selects the credit pack — single (500 credits, one report, the default), five (2,500 credits), or twenty (10,000 credits). Nothing is saved locally; if you buy a multi-report pack, copy the printed credit key into NETDOCTOR_PAYMENT_CREDIT_KEY to reuse it on future runs. Cannot be combined with --wallet.

  • --wallet <address> — for a human who wants to pay for a report directly with E3D Token, with no e3d account or pre-funded credit key at all:

    e3d-netdoctor paid-report --interface en0 --wallet 0xYourAddress

    netdoctor prints a one-time URL; open it, connect MetaMask, and approve a single token transfer. netdoctor polls in the background and picks up automatically once the payment is confirmed — nothing to copy/paste back into the terminal.

    The benefit over the credit-key path isn't just convenience: your wallet's private key never touches netdoctor or any e3d server. The browser talks directly to your wallet and only ever reports a transaction hash back — never a secret. netdoctor never sees, asks for, or stores a private key, and you never manually handle a tx hash or credit key either; the whole exchange happens over a short-lived, single-use payment session it polls for you.

    --payment-method picks which chain/token to pay with:

    • ethereum (default) — pay with E3D on Ethereum mainnet.
    • base — pay with wE3D on Base; usually lower gas fees.
    e3d-netdoctor paid-report --interface en0 --wallet 0xYourAddress --payment-method base

    Two spending modes (independent of which chain you pick):

    • One-off (--wallet <address>, no --credits): pay for exactly this one report. Nothing is saved locally — the next paid-report starts a fresh payment.
    • Batch (--wallet <address> --credits n): buy a reusable batch of n credits once; the resulting credit key is saved to ~/.config/e3d-netdoctor/config.json (keyed by wallet address) and reused automatically by future paid-report --wallet runs until it runs low — fewer wallet approvals if you run reports regularly.

See docs/payment-gate.md for the credit-key flow's configuration and failure-mode details.

Quickstart

npm install                      # no dependencies to install
e3d-netdoctor preflight           # confirms tshark is installed
e3d-netdoctor smoke ./fixtures/sample-syn.pcap
e3d-netdoctor report ./fixtures/retransmission-handshake.pcap

report defaults to printing { findings, narrative } as JSON to stdout — built for agents to consume directly, no parsing of prose required. Ask for markdown or HTML instead, write to a file, or email it:

e3d-netdoctor report ./fixtures/retransmission-handshake.pcap                          # JSON to stdout (default)
e3d-netdoctor report ./fixtures/retransmission-handshake.pcap --format markdown        # markdown to stdout
e3d-netdoctor report ./fixtures/retransmission-handshake.pcap --format html            # HTML to stdout
e3d-netdoctor report ./fixtures/retransmission-handshake.pcap --format html --output out.html
e3d-netdoctor report ./fixtures/retransmission-handshake.pcap --to [email protected] --pdf

When --output and/or --to are used, report prints a small JSON summary (verdict, confidence, output path, delivery info) instead of the raw content.

Add --speed-test to also run a real download/upload throughput measurement (against a public Cloudflare speed-test endpoint) and fold the Mbps numbers into the System Diagnostics section. It's opt-in — off by default — since it uses real bandwidth and adds several seconds to the run:

e3d-netdoctor report ./fixtures/retransmission-handshake.pcap --speed-test

Add --redact before sharing or publishing a report: it replaces your local IPs/MACs with stable pseudonyms (local-device-1, local-device-2, ...) and strips the local capture file path, while leaving external destination IPs and ISP traceroute hostnames real — that's the verifiable evidence the report exists to show, only your own network's identity is hidden. This is also the precondition for mint (below) — nothing gets published or tokenized with your home network's real IPs/MACs in it.

e3d-netdoctor report ./fixtures/retransmission-handshake.pcap --redact --output report.json

Minting a report as an NFT

mint tokenizes an already---redacted report as an NFT via E3DNFTManager (the same shared contract used across E3D products — no netdoctor-specific contract). It requires the saved report file to have redacted: true (refuses otherwise) and --confirm-public, since minting pins the report to IPFS permanently and publicly:

e3d-netdoctor mint report.json --wallet 0xYourAddress --confirm-public

netdoctor renders an HTML certificate (from the saved findings/narrative) and a PNG screenshot of it, uploads both plus the structured findings to IPFS via e3d.ai, then prints a one-time https://e3d.ai/mint?session=... URL — open it, connect MetaMask, and approve the mint (same no-custodial-keys model as --wallet payments: your wallet signs directly, netdoctor and e3d.ai never see or touch it). Minting always happens on Ethereum mainnet regardless of which --payment-method was used to pay for the report itself, and costs 100 E3D + gas — a separate cost from the 500 credits spent generating the report. Once confirmed, netdoctor prints {tokenId, txHash, etherscanUrl}.

Full command list:

preflight                                  Check whether tshark is installed locally.
smoke <file.pcap>                          Parse a capture, print rows/diagnostics.
capture [iface] [seconds]                  Run a live tshark capture (default 30s).
report <pcap> [--format json|markdown|html] [--output file] [--to email] [--pdf] [--no-system-diagnostics] [--speed-test] [--redact]
                                            Defaults to JSON on stdout; --format selects markdown/html;
                                            --output writes to a file; --to emails it (--pdf attaches a PDF).
deliver <pcap> <to> [--pdf] [--no-system-diagnostics] [--speed-test]
paid-report [--pcap file | --interface iface] [--duration s] [--format json|markdown|html]
            [--output file] [--to email] [--pdf] [--request-id id] [--speed-test] [--redact]
            [--wallet address [--credits n] [--payment-method ethereum|base]]
                                            Same defaults/flags as report, gated behind a 500-credit
                                            payment (credit key or --wallet).
mint <report.json> --wallet address --confirm-public [--name "..."] [--description "..."]
                                            Tokenize a --redact'd report as an NFT (E3DNFTManager,
                                            Ethereum mainnet). 100 E3D + gas, paid from --wallet.

Every capture/analysis entrypoint prints a reminder up front: only analyze traffic on networks you are authorized to monitor.

No external dependencies to install

Everything beyond parsing (which vendors e3d-pcap's tested core under src/vendor/) is built on Node's standard library and the system tools you already have:

  • Email — a small SMTP client on node:net/node:tls (STARTTLS + AUTH LOGIN). No nodemailer.
  • PDF export — shells out to a locally installed Chrome/Chromium/Edge with --headless --print-to-pdf, the same way netdoctor already shells out to tshark. No puppeteer, no bundled Chromium download.
  • Payment client — a small, self-contained e3d payments client, not a runtime dependency on another repo.

npm install has nothing to resolve at all — the e3d-pcap parsing core is vendored directly under src/vendor/, not pulled in as a package — so there's nothing to silently fail on a machine without internet access.

Configuration

| Purpose | Env vars | |---|---| | Narrative generation | report/deliver always use a deterministic template, regardless of these. paid-report uses ANTHROPIC_API_KEY (preferred if set) or OPENAI_API_KEY (used if Anthropic's isn't set); if neither is set, it calls e3d's hosted narrative endpoint instead (paid for out of the report's 500 credits) rather than falling back to the template. Optional NETDOCTOR_ANTHROPIC_MODEL/NETDOCTOR_OPENAI_MODEL/NETDOCTOR_HOSTED_NARRATIVE_URL to override the defaults. | | Email delivery | NETDOCTOR_SMTP_HOST, NETDOCTOR_SMTP_PORT, NETDOCTOR_SMTP_SECURE, NETDOCTOR_SMTP_USER, NETDOCTOR_SMTP_PASSWORD | | PDF export | NETDOCTOR_BROWSER_PATH (auto-detected otherwise) | | Payment gate | NETDOCTOR_PAYMENT_CREDIT_KEY (required); NETDOCTOR_PAYMENT_SERVICE_KEY and E3D_BASE_URL are optional, with working defaults — see docs/payment-gate.md |

Testing

node --test

Every external boundary — tshark, ping/traceroute/netstat, SMTP, PDF rendering, the payment API — is exercised through dependency injection so the suite runs offline and fast, plus a real local-socket SMTP conversation and real fixture .pcap parses so the important paths are proven end-to-end, not just mocked.