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

v0.2.0

Published

Next.js integration for @nreactive/core — App Router & Pages Router request context, server actions, and a React provider that catches client errors

Readme

@nreactive/next

Next.js integration for @nreactive/core — App Router & Pages Router request context, server actions, and a React provider that catches client errors for the nreactive AI error-fix pipeline.

  • Server: three small wrappers (withNreactive, withNreactiveAction, withNreactivePagesApi) that open an AsyncLocalStorage context for the request and capture-and-rethrow on error. Method, URL, request ID, and scrubbed headers are attached to every event.
  • Client: a single <NreactiveProvider> that's a strict superset of the standalone browser script — runtime exceptions, unhandled rejections, fetch + XHR failures, console.error / console.warn, resource load errors, CSP violations, and long tasks — plus a React Error Boundary so render-time errors reach the dashboard too.
  • Works with Next.js 14, 15, and 16 on Node ≥ 20. React 18 or 19.

Install

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

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 — instrumentation.ts, the route wrappers, the server-action wrappers, and the React provider — with no manual wiring.

You are adding the @nreactive/core + @nreactive/next SDKs to this Next.js 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) and install @nreactive/core and @nreactive/next.
  2. Create or update instrumentation.ts at the project root (or src/instrumentation.ts if the project uses a src/ layout). Its register function should call init from @nreactive/core only when NEXT_RUNTIME === "nodejs".
  3. Wrap every App Router route handler under app/api/** with withNreactive from @nreactive/next.
  4. Wrap every server action that throws on user input with withNreactiveAction from @nreactive/next.
  5. Wrap every Pages Router API handler under pages/api/** with withNreactivePagesApi from @nreactive/next.
  6. In app/layout.tsx (or pages/_app.tsx), wrap {children} with <NreactiveProvider appId={process.env.NEXT_PUBLIC_NREACTIVE_APP_ID!}> imported from @nreactive/next/client. If the project already includes <script src="https://nreactive.com/integration.js">, REMOVE it — running both would double-fire events.
  7. Add NREACTIVE_APP_ID= and NEXT_PUBLIC_NREACTIVE_APP_ID= to .env.example. The user obtains their App ID from https://nreactive.com/dashboard/apps.
  8. Restart the dev server and confirm both server and client events appear in the dashboard.

Do not invent additional configuration. If the project uses Edge Runtime for some routes, leave those routes unwrapped — withNreactive depends on Node's async_hooks. Stop and ask if the project structure doesn't match these assumptions.

Quick start

instrumentation.ts

Next runs this once per process at startup. Calling init here is the cheapest way to get uncaughtException / unhandledRejection capture and outbound HTTP failure capture.

// instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME !== "nodejs") return;
  const { init } = await import("@nreactive/core");
  init({
    appId: process.env.NREACTIVE_APP_ID!,
    environment: process.env.NODE_ENV,
    release: process.env.APP_VERSION,
  });
}

App Router route handler

// app/api/users/route.ts
import { withNreactive } from "@nreactive/next";

export const GET = withNreactive(async (request) => {
  const users = await db.users.findAll();
  return Response.json(users);
});

export const POST = withNreactive(async (request) => {
  const body = await request.json();
  const user = await db.users.create(body);
  return Response.json(user, { status: 201 });
});

Server action

// app/actions.ts
"use server";

import { withNreactiveAction } from "@nreactive/next";

export const submitContact = withNreactiveAction(async (formData: FormData) => {
  const email = String(formData.get("email") ?? "");
  if (!email) throw new Error("email required");
  await db.contacts.insert({ email });
});

Pages Router API route

// pages/api/echo.ts
import { withNreactivePagesApi } from "@nreactive/next";

export default withNreactivePagesApi(async (req, res) => {
  res.status(200).json({ method: req.method });
});

Client provider

// app/layout.tsx
import { NreactiveProvider } from "@nreactive/next/client";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <NreactiveProvider appId={process.env.NEXT_PUBLIC_NREACTIVE_APP_ID!}>
          {children}
        </NreactiveProvider>
      </body>
    </html>
  );
}

The provider is a strict superset of the standalone <script src="https://nreactive.com/integration.js"> tag — if your app already includes that script, remove it when you switch to the provider. Running both would double-fire every event.

Get your App ID from the nreactive dashboard.

How it works

  • withNreactive wraps an App Router route handler. It opens a fresh AsyncLocalStorage frame, populates it with { method, url, requestId, headers }, and runs the handler inside. Any captureException during the handler's async subtree picks up the request context. Errors thrown from the handler are captured and rethrown so Next still returns its 500.
  • withNreactiveAction wraps a server action. Server actions don't get a Request, so we read the request-time next/headers instead — wrapped in a try/catch so the wrapper still works in tests where next/headers isn't available. Captured events get a kind: "server-action" tag for dashboard filtering.
  • withNreactivePagesApi wraps a Pages Router API handler. Same context shape as the App Router wrapper, just driven from the Node-style req / res pair.
  • <NreactiveProvider> is a "use client" island that installs the eight standard browser capture surfaces and wraps children in a React Error Boundary. Render-time errors that React catches are shipped to the dashboard with errorType: "ReactRenderError".
  • Request IDs are sourced in this order:
    1. X-Request-ID header
    2. X-Correlation-ID header
    3. Generated randomUUID()

API

withNreactive(handler, options?)

Wraps an App Router route handler (request: Request, ctx?) => Response | Promise<Response>.

interface NreactiveOptions {
  /** Header names to redact. Merged with @nreactive/core defaults. */
  scrubHeaders?: string[];
  /** Query param names to redact. Merged with @nreactive/core defaults. */
  scrubQueryParams?: string[];
  /** Emit a breadcrumb per invocation. Default: true. */
  breadcrumbs?: boolean;
  /** Decide whether to capture a given thrown error. Default: always true. */
  shouldCapture?: (err: unknown) => boolean;
}

withNreactiveAction(action, options?)

Wraps a server action (...args) => R | Promise<R>. Same options as withNreactive.

withNreactivePagesApi(handler, options?)

Wraps a Pages Router API handler (req, res) => void | Promise<void>. Same options as withNreactive.

<NreactiveProvider>

interface NreactiveProviderProps {
  appId: string;
  endpoint?: string;                  // default "https://nreactive.com"
  release?: string;
  fallback?: (err: Error) => ReactNode;
  disable?: Partial<{
    onerror: boolean;
    unhandledrejection: boolean;
    resourceErrors: boolean;
    cspViolations: boolean;
    consoleError: boolean;
    consoleWarn: boolean;
    fetch: boolean;
    xhr: boolean;
    longTasks: boolean;
  }>;
  children: ReactNode;
}

useNreactive()

interface ManualCaptureApi {
  captureException(err: unknown, severity?: "critical" | "error" | "warn"): void;
  captureMessage(msg: string, severity?: "critical" | "error" | "warn"): void;
  /** Accepted for forward compatibility — currently a no-op. */
  addBreadcrumb(b: { category: string; message: string; level?: "debug" | "info" | "warn" | "error" }): void;
}
"use client";
import { useNreactive } from "@nreactive/next/client";

export default function ContactButton() {
  const { captureException } = useNreactive();
  return (
    <button onClick={async () => {
      try {
        await fetch("/api/contact", { method: "POST" });
      } catch (err) {
        captureException(err);
      }
    }}>
      Contact
    </button>
  );
}

Interaction with Next's error.tsx

Next renders a route-segment error.tsx whenever a render error escapes a Server Component. The provider's error boundary sits above every route segment, so:

  • A render error inside a route segment is first caught by that segment's error.tsx (if present). The user sees your fallback UI.
  • A render error that bubbles past every error.tsx (e.g. an error in app/layout.tsx) is caught by the provider's boundary. The user sees the provider's fallback (or null, by default).
  • In both cases, the provider's boundary records the event because componentDidCatch runs on every ancestor boundary, not just the topmost. So you don't need to instrument error.tsx separately.

Edge runtime

The server wrappers depend on node:async_hooks, which isn't available on Edge Runtime. If a route uses export const runtime = "edge", leave it unwrappedinit() from instrumentation.ts plus the provider on the client will still capture errors there, you just won't get per-request server context. Mix-and-match is fine.

Why the provider is a superset of the script tag

Three reasons:

  1. One source of capture per page. If you use both <script src="…/integration.js"> and <NreactiveProvider>, every event fires twice. Picking one is the cleaner mental model.
  2. The script tag can't catch render errors. React render errors don't bubble to window.onerror; only an Error Boundary sees them. The provider has one built in.
  3. The provider unmounts cleanly. HMR, tests, and the React StrictMode double-mount all need a deterministic teardown — the singleton client is reference-counted and restores window.fetch, XMLHttpRequest, console.error/warn, and window.onerror to their originals when the last provider unmounts.

If you currently include the script tag, remove it when you adopt this package.

Links

License

PROPRIETARY. See LICENSE.