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

@nreactive/express

v0.2.0

Published

Express middleware for @nreactive/core — automatic request-context propagation and error capture

Readme

@nreactive/express

Express 4/5 middleware for @nreactive/core — automatic request-context propagation and error capture for the nreactive AI error-fix pipeline.

  • Wraps every request in an AsyncLocalStorage context — method, url, request ID, scrubbed headers, and req.user are attached to any error captured during handling.
  • Captures anything that reaches Express's error-handling chain (next(err) + thrown errors inside handlers).
  • Zero runtime dependencies of its own — just @nreactive/core (peer) and Express.
  • Works with Express 4 and 5. Node ≥ 20.

Install

npm install @nreactive/core @nreactive/express
# or: pnpm add @nreactive/core @nreactive/express
# or: yarn add @nreactive/core @nreactive/express
# or: bun add @nreactive/core @nreactive/express

AI-assisted setup

Paste the prompt below into Claude Code, Cursor, Copilot, or any agent with file-write access. It has enough information to finish the integration end-to-end — no manual wiring required.

You are adding the @nreactive/core + @nreactive/express SDKs to this Express project. nreactive is a production error-monitoring service that opens AI-generated pull requests to fix the errors it catches.

  1. Detect the package manager from the lockfile (package-lock.json → npm, pnpm-lock.yaml → pnpm, yarn.lock → yarn, bun.lockb → bun).
  2. Install @nreactive/core and @nreactive/express with that package manager.
  3. Create a file src/observability/nreactive.ts (or .js if the project is not TypeScript) that imports init from @nreactive/core and calls it with { appId: process.env.NREACTIVE_APP_ID, environment: process.env.NODE_ENV, release: process.env.APP_VERSION }. Export nothing — the module is used for its import side effect.
  4. In the server entry file (commonly src/index.ts, src/server.ts, or the main field of package.json), add import "./observability/nreactive"; as the very first import, before any framework imports including express.
  5. In the Express app setup:
    • Call app.use(requestHandler()) from @nreactive/express before any routes.
    • Call app.use(errorHandler()) from @nreactive/express after all routes and after any other error middleware.
  6. Add NREACTIVE_APP_ID= to .env.example (create it if missing) and document the variable in the README's environment-variables section. The user will obtain their App ID from https://nreactive.com/dashboard/apps.
  7. Do not invent additional configuration. Restart the server and throw a test error from a route to confirm events appear in the nreactive dashboard.

Stop and ask if the project structure doesn't match these assumptions (for example, if the project is not using Express).

Quick start

// src/observability/nreactive.ts — imported FIRST in your entry file
import { init } from "@nreactive/core";

init({
  appId: process.env.NREACTIVE_APP_ID!,
  environment: process.env.NODE_ENV,
  release: process.env.APP_VERSION,
});
// src/server.ts
import "./observability/nreactive";        // ← must be the first import

import express from "express";
import { requestHandler, errorHandler } from "@nreactive/express";

const app = express();

app.use(requestHandler());                 // FIRST — wraps each request in an async context
app.use(express.json());

app.get("/", (req, res) => {
  res.send("hello");
});

app.use(errorHandler());                   // LAST — captures anything that reaches the error chain

app.listen(3000);

Get your App ID from the nreactive dashboard.

How it works

  • requestHandler() runs first and opens a fresh AsyncLocalStorage frame for the request's async subtree. Any captureException call inside that subtree — including from awaited work — automatically picks up method, url, requestId, scrubbed headers, and user (from req.user, if your auth middleware populates it).
  • errorHandler() is an Express error middleware (4-arity) that catches every error passed to next(err) or thrown synchronously from a handler. It classifies severity (see @nreactive/core) and calls captureException. It always calls next(err) so your existing error handling still runs.

Request IDs are sourced in this order:

  1. X-Request-ID header
  2. X-Correlation-ID header
  3. Generated randomUUID()

API

requestHandler(options?)

interface RequestHandlerOptions {
  /** Header names to redact. Merged with @nreactive/core defaults. */
  scrubHeaders?: string[];
  /** Query param names to redact in the URL. Merged with core defaults. */
  scrubQueryParams?: string[];
  /** Emit an `http.server` breadcrumb for each request. Default: true. */
  breadcrumbs?: boolean;
}

Returns an Express handler (req, res, next) => void.

errorHandler(options?)

interface ErrorHandlerOptions {
  /** Decide whether to capture a given error. Default: always true. */
  shouldCapture?: (err: unknown, req: Request) => boolean;
}

Returns an Express error middleware (err, req, res, next) => void — must be registered last.

Attaching user context

If your auth middleware puts a user on req.user, the request handler will propagate it automatically. Expected shape:

req.user = {
  id: "u_42",                // string or number — required for any user context to attach
  email: "[email protected]", // optional
  username: "alice",          // optional
};

To attach user info yourself (e.g. after loading from a session), import addContext from @nreactive/core:

import { addContext } from "@nreactive/core";

app.use(async (req, res, next) => {
  const session = await getSession(req);
  if (session) addContext({ user: { id: session.userId, email: session.email } });
  next();
});

Full example

import "./observability/nreactive";

import express from "express";
import { requestHandler, errorHandler } from "@nreactive/express";
import { captureException } from "@nreactive/core";

const app = express();

app.use(requestHandler({
  scrubHeaders: ["authorization", "x-api-key", "x-session-token"],
  scrubQueryParams: ["token", "secret"],
}));

app.use(express.json());

app.get("/boom", () => {
  throw new Error("intentional test error");
});

app.get("/async-boom", async () => {
  await Promise.reject(new Error("async test"));
});

app.get("/manual", (req, res) => {
  try {
    doWork();
    res.json({ ok: true });
  } catch (err) {
    captureException(err, "error", { tags: { route: "/manual" } });
    res.status(500).json({ ok: false });
  }
});

app.use(errorHandler({
  shouldCapture: (err) => !(err as any).expose, // skip `http-errors` you intentionally throw
}));

app.listen(3000);

Links

License

PROPRIETARY. See LICENSE.