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

asyncdrop

v0.1.0

Published

Flags Express async route handlers with no try/catch around their awaited calls, in a codebase with no centralized async-error-catching middleware — a rejected promise there becomes a silent hang or crash, not a forwarded error.

Readme

asyncdrop

Static analyzer CLI that flags an Express async (req, res) => { ... } route handler that awaits without a surrounding try/catch, in a codebase with no centralized async-error-catching protection — no express-async-errors import, no catch-all wrapper (asyncHandler/ catchAsync/...), and not already on Express 5.

// Works every time in dev: the DB call always resolves. The day it
// rejects — a dropped connection, a timeout, a bad id — this becomes
// an unhandled promise rejection on Express 4, not a forwarded error.
// No error handler ever runs, and the request can hang forever with no
// response ever sent.
app.get("/users/:id", async (req, res) => {
  const user = await db.users.findById(req.params.id);
  res.json(user);
});

See DETAILS.md for the full gap analysis, the Express-4-vs-5 behavioral difference this tool has to account for to avoid false positives, and an honest list of what it can't see.

Install

npm install -g asyncdrop

Usage

npx asyncdrop check src
npx asyncdrop check src/routes.ts

Example output:

src/routes.ts:13  [GET /users/:id] async route handler awaits without a surrounding try/catch — a rejected promise here becomes an unhandled rejection, not a forwarded error, unless the codebase is on Express 5 or uses express-async-errors/a catch-all wrapper

asyncdrop: found 1 unguarded async handler finding(s) across 1 handler(s) scanned.

Exit codes: 0 clean (or skipped — see below), 1 an unguarded async handler was found, 2 usage error. Full flag/output reference in docs/USAGE.md.

What it detects

  • A route registered via app.get/post/put/patch/delete/all(...) or router.get/post/...(...) whose handler is async and contains at least one await that is not inside a try block.
  • Handlers wrapped in a recognizable catch-all utility (asyncHandler(...), catchAsync(...), wrapAsync(...), ...) are treated as protected — the wrapper is doing the forwarding job for them.
  • The whole project is skipped (nothing flagged) when:
    • the nearest package.json pins express to major version 5 (its router already forwards rejected promises to error middleware automatically — see DETAILS.md's Express 5 note), or
    • an express-async-errors import/require is found anywhere in the scanned files (it patches Express 4's router to do the same thing).

Parsing is done directly with the TypeScript Compiler API, so asyncdrop understands real TypeScript/JavaScript syntax rather than regexing source text — it never executes the code it scans.

What this is not

  • Not a general async/await linter — no-floating-promises (from typescript-eslint) and similar rules catch a broader class of unhandled-rejection shapes anywhere in a codebase, not specifically "route handler with no centralized catch path." asyncdrop is scoped tightly to the Express/Fastify route-registration call-site pattern.
  • Not a check on a bare 4-arg error-handling middleware being registered — see DETAILS.md for why that alone is not sufficient protection on Express 4 and isn't treated as one.
  • Not a runtime/observability tool — it never imports, requires, or executes the scanned code; everything is read as source text.

License

MIT © 2026 Jay