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

@heronsignal/node

v0.1.2

Published

HeronSignal server-side SDK for Node.js — capture backend errors, logs, and business events, correlated to real user sessions.

Readme

@heronsignal/node

Server-side SDK for HeronSignal. Capture backend errors, logs, and business events — correlated to the real user session that triggered them, so a server error or a server-confirmed conversion lines up with the browser journey and your funnels.

Mirrors the browser API (event / log / captureError), so the mental model is the same on the front and back end.

  • Zero runtime dependencies · Node 18+ (uses the built-in fetch)
  • Non-blocking: events are queued and flushed in batches
  • Safe by default: never throws into your app; sensitive attribute keys are scrubbed before they leave the process

Install

npm install @heronsignal/node

Quick start

Create a server ingest token in the dashboard (Developer → Tokens), then:

import { init, event, log, captureError } from "@heronsignal/node";

init({
  token: process.env.HERONSIGNAL_SERVER_TOKEN!,
  service: "checkout-api",
  environment: process.env.NODE_ENV,
  release: process.env.GIT_SHA,
});

// A business milestone — powers funnels & metrics. Correlate it to the user so
// it can complete a funnel that started in the browser.
event("order_paid", { amount: 4200, currency: "usd" }, {
  userId: "user_123",
  entity: { type: "order", id: "ord_789" },
});

// A diagnostic log line
log("warn", "Payment retried", { attempt: 2 });

// A handled exception
try {
  await charge();
} catch (err) {
  captureError(err, { orderId: "ord_789" });
}

Express

import express from "express";
import { init, heronExpressMiddleware, heronExpressErrorHandler } from "@heronsignal/node";

const client = init({ token: process.env.HERONSIGNAL_SERVER_TOKEN!, service: "web" });
const app = express();

// Records HTTP request events (5xx by default; pass captureAllRequests: true for all).
app.use(
  heronExpressMiddleware({
    client,
    correlate: (req: any) => ({
      userId: req.user?.id,
      sessionId: req.headers["x-hs-session"],
    }),
  }),
);

// ... your routes ...

// Captures thrown errors — mount last.
app.use(heronExpressErrorHandler({ client }));

Correlation

The whole point is tying backend telemetry to the visitor. Attach any of:

| Field | Use | | --- | --- | | userId | Your application user id — the most durable link. | | entity | A business object, e.g. { type: "order", id: "ord_789" }. Use the same key you tracked in the browser to complete a funnel server-side. | | sessionId | The browser session id (only valid while the session is live). | | trace | { traceId, spanId } for operation-level correlation. |

Example: a payment journey

The funnel starts in the browser (@heronsignal/web):

heronsignal.event("checkout_started", { plan: "pro" });

Forward the HeronSignal session id (and your user id) to the backend on the checkout request — e.g. an x-hs-session header — then reuse one correlation object so the server events line up with that exact visit and complete the funnel, and any error is tied to the session that hit it:

async function handlePayment({ userId, sessionId, orderId, amountCents }) {
  const who = { userId, sessionId, entity: { type: "order", id: orderId } };

  event("payment_attempted", { amountCents }, who);
  try {
    await chargeCard();
    event("order_paid", { amountCents }, who); // completes the browser funnel
  } catch (err) {
    captureError(err, { orderId, step: "charge" }, who); // error, on the session
    event("payment_failed", { reason: String(err) }, who);
    throw err;
  }
}

Full runnable versions: examples/payment-journey.ts and an Express route in examples/express-checkout.ts.

Configuration

init({
  token: "…",              // required — server ingest token
  endpoint: "https://api.heronsignal.com", // default
  service: "checkout-api",
  environment: "production", // default: process.env.NODE_ENV
  release: "2026.07.04",
  flushIntervalMs: 2000,     // batch flush cadence
  maxBatchSize: 50,          // flush early at this many queued (hard cap 100)
  maxQueueSize: 1000,        // drop oldest beyond this (never OOMs your app)
  disableScrubbing: false,   // client-side redaction of sensitive keys
  debug: false,
  onError: (err) => {},      // called if a batch fails to send
});

Graceful shutdown

init() flushes best-effort on beforeExit. For hard signals, flush explicitly:

process.on("SIGTERM", async () => {
  await shutdown(); // flush + stop the timer
  process.exit(0);
});

API

  • init(config)HeronSignalClient — configure the default client.
  • event(name, attributes?, correlation?) — business milestone.
  • log(level, message, attributes?, correlation?)"error" | "warn" | "info".
  • captureError(error, attributes?, correlation?) — handled exception.
  • captureHttp(http, correlation?, attributes?) — record a request manually.
  • flush() / shutdown() — send now / send and stop.
  • heronExpressMiddleware(opts) / heronExpressErrorHandler(opts).

You can also create isolated clients directly: new HeronSignalClient(config).


MIT © HeronSignal