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/nestjs

v0.2.0

Published

NestJS module + interceptor + exception filter for @nreactive/core — automatic request-context propagation and error capture, works against the Express or Fastify HTTP adapter

Readme

@nreactive/nestjs

NestJS module + interceptor + exception filter for @nreactive/core — automatic request-context propagation and error capture for the nreactive AI error-fix pipeline.

  • One-line install via NreactiveModule.forRoot() — registers both pieces globally via APP_INTERCEPTOR + APP_FILTER.
  • Wraps every request in an AsyncLocalStorage context — method, url, request ID, scrubbed headers, route handler name, and req.user are attached to any error captured during handling.
  • Captures every error a controller can throw — synchronous throws, rejected Promises, errored Observables — by extending NestJS's own BaseExceptionFilter (so the HTTP response shape stays identical to what NestJS would have sent).
  • Works against the Express and Fastify HTTP adapters NestJS supports out of the box, with no per-adapter branching.
  • Zero runtime dependencies of its own — just @nreactive/core, @nestjs/common, @nestjs/core, and rxjs (all peers).
  • Works with NestJS 10 and 11. Node ≥ 20.

Install

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

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/nestjs SDKs to this NestJS 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/nestjs with that package manager.
  3. Create a file src/observability/nreactive.ts 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 src/main.ts, add import "./observability/nreactive"; as the very first import, before import { NestFactory } from "@nestjs/core"; and before any other framework or app import.
  5. In src/app.module.ts, import NreactiveModule from @nreactive/nestjs and add NreactiveModule.forRoot() to the imports array of AppModule. The module wires both the global interceptor (request context) and the global exception filter (error capture) via APP_INTERCEPTOR and APP_FILTER provider tokens — no further wiring in main.ts is needed.
  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 controller (e.g. @Get("boom") boom() { throw new Error("nreactive test"); }) 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 NestJS, or if it uses a custom HTTP adapter other than Express or Fastify).

Quick start

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

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

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();
// src/app.module.ts
import { Module } from "@nestjs/common";
import { NreactiveModule } from "@nreactive/nestjs";
import { AppController } from "./app.controller";

@Module({
  imports: [NreactiveModule.forRoot()],
  controllers: [AppController],
})
export class AppModule {}

Get your App ID from the nreactive dashboard.

How it works

  • NreactiveInterceptor is registered globally via the APP_INTERCEPTOR provider. For every incoming HTTP request it pulls the underlying request from ExecutionContext.switchToHttp().getRequest(), extracts method/url/requestId/scrubbed headers/user, and opens a fresh AsyncLocalStorage frame around the handler's Observable subscription. Any captureException call inside that subtree — including from awaited work and downstream operators — automatically picks up the request context. Microservice / WebSocket / GraphQL contexts (no HTTP request) are passed through unchanged.

  • NreactiveExceptionFilter is registered globally via the APP_FILTER provider. It extends NestJS's own BaseExceptionFilter, captures the exception via getClient().captureException(err, classify(err)), then calls super.catch(err, host) so the HTTP response shape (status code, body) is exactly what NestJS would have sent without the filter. Works for HttpException and any Error subclass.

  • NreactiveModule.forRoot() is a one-line installation — both pieces are wired with the supplied options bag via the NREACTIVE_OPTIONS injection token. No call to app.useGlobalInterceptors(...) or app.useGlobalFilters(...) from main.ts is required.

Request IDs are sourced in this order:

  1. req.id (Fastify provides this; some Express middleware sets it too)
  2. X-Request-ID header
  3. X-Correlation-ID header
  4. Generated randomUUID()

API

NreactiveModule.forRoot(options?)

interface NreactiveModuleOptions {
  /** 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;
  /**
   * Decide whether to capture a given exception. Default: always true.
   * Useful for filtering out HttpException with sub-500 status codes.
   */
  shouldCapture?: (err: unknown) => boolean;
}

Returns a DynamicModule you add to the imports array of your root AppModule.

NreactiveInterceptor

A standalone NestInterceptor exported for users who want to register the interceptor manually:

import { NestFactory } from "@nestjs/core";
import { NreactiveInterceptor } from "@nreactive/nestjs";
import { AppModule } from "./app.module";

const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new NreactiveInterceptor({ breadcrumbs: false }));

NreactiveExceptionFilter

A standalone ExceptionFilter exported for the same reason. Standalone use needs the HttpAdapterHost to construct the underlying BaseExceptionFilter:

import { HttpAdapterHost } from "@nestjs/core";
import { NreactiveExceptionFilter } from "@nreactive/nestjs";

const httpAdapterHost = app.get(HttpAdapterHost);
app.useGlobalFilters(new NreactiveExceptionFilter(httpAdapterHost));

Attaching user context

If your auth guard/middleware attaches req.user = { id, email, username }, the interceptor picks it up automatically and tags every error with that user.

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

import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { addContext } from "@nreactive/core";

@Injectable()
export class SessionGuard implements CanActivate {
  async canActivate(ctx: ExecutionContext): Promise<boolean> {
    const req = ctx.switchToHttp().getRequest();
    const session = await loadSession(req);
    if (session) addContext({ user: { id: session.userId, email: session.email } });
    return Boolean(session);
  }
}

Because the interceptor opens the AsyncLocalStorage frame before the guard chain runs (interceptors wrap guards in NestJS), addContext from inside a guard merges into the active request context and propagates to any error captured later in the request.

Full example

// src/main.ts
import "./observability/nreactive";

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();
// src/app.module.ts
import { HttpException } from "@nestjs/common";
import { Module } from "@nestjs/common";
import { NreactiveModule } from "@nreactive/nestjs";
import { AppController } from "./app.controller";

@Module({
  imports: [
    NreactiveModule.forRoot({
      scrubHeaders: ["authorization", "x-api-key", "x-session-token"],
      scrubQueryParams: ["token", "secret"],
      // Don't capture client errors (4xx) — only server faults (5xx).
      shouldCapture: (err) =>
        !(err instanceof HttpException && err.getStatus() < 500),
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}
// src/app.controller.ts
import { Controller, Get } from "@nestjs/common";
import { captureException } from "@nreactive/core";

@Controller()
export class AppController {
  @Get("/")
  hello() {
    return { hello: "world" };
  }

  @Get("/boom")
  boom() {
    throw new Error("intentional test error");
  }

  @Get("/async-boom")
  async asyncBoom() {
    await Promise.reject(new Error("async test"));
  }

  @Get("/manual")
  manual() {
    try {
      doWork();
      return { ok: true };
    } catch (err) {
      captureException(err, "error", { tags: { route: "/manual" } });
      throw err;
    }
  }
}

Links

License

PROPRIETARY. See LICENSE.