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

@vibemonitor/node

v0.1.0

Published

Vibemonitor Node.js SDK — capture and send logs from server-side JS/TS apps (Express, Fastify, NestJS, Next.js server).

Downloads

78

Readme

@vibemonitor/node

Vibemonitor SDK for Node.js backends — Express, Fastify, NestJS, Koa, plain Node, or any server-side JS/TS runtime.

For Next.js (which has a Node runtime but also browser + edge), use @vibemonitor/nextjs — it handles all three.


Installation

npm install @vibemonitor/node

Pulls in @vibemonitor/core transitively.

Node requirement: 18+ (for native fetch).


Environment variable

# .env
VIBEMONITOR_API_KEY=vmsdk_server_token_here

# Optional
VIBEMONITOR_ENABLED=true         # set "false" or "0" to disable without code changes
VIBEMONITOR_DEBUG=false          # set "1" for SDK diagnostic stderr output
VIBEMONITOR_SERVICE=my-api        # or pass via init({ service })
VIBEMONITOR_ENV=production
VIBEMONITOR_VERSION=1.2.3

Get your token from the Vibemonitor dashboard → Settings → API Keys.


Setup — single init at server startup

Express

// server.ts
import vibemonitor from "@vibemonitor/node";

vibemonitor.init({
  apiKey: process.env.VIBEMONITOR_API_KEY,
  service: "my-api",
  environment: process.env.NODE_ENV,
});

// ─── Your app — unchanged ─────────────────────────
import express from "express";
const app = express();

app.get("/users", async (req, res) => {
  console.log("Fetching users");          // ← captured
  const users = await db.query();
  res.json(users);
});

app.listen(3000);

Fastify

// server.ts
import vibemonitor from "@vibemonitor/node";
vibemonitor.init({ apiKey: process.env.VIBEMONITOR_API_KEY, service: "my-api" });

import Fastify from "fastify";
const fastify = Fastify({ logger: true });

fastify.get("/users", async () => {
  console.log("Fetching users");          // ← captured
  return await db.query();
});

fastify.listen({ port: 3000 });

NestJS

// main.ts — first line, before any other imports
import vibemonitor from "@vibemonitor/node";
vibemonitor.init({ apiKey: process.env.VIBEMONITOR_API_KEY, service: "my-api" });

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

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

Koa

import vibemonitor from "@vibemonitor/node";
vibemonitor.init({ apiKey: process.env.VIBEMONITOR_API_KEY, service: "my-api" });

import Koa from "koa";
const app = new Koa();
// ...
app.listen(3000);

Plain Node HTTP server

import vibemonitor from "@vibemonitor/node";
vibemonitor.init({ apiKey: process.env.VIBEMONITOR_API_KEY, service: "my-api" });

import http from "node:http";
const server = http.createServer((req, res) => {
  console.log(`${req.method} ${req.url}`);   // ← captured
  res.end("ok");
});
server.listen(3000);

Next.js server runtime (SSR + API routes)

For Next.js, prefer @vibemonitor/nextjs which handles all three runtimes. If you want only the server piece, here's how:

// vibemonitor.server.config.ts
import vibemonitor from "@vibemonitor/node";
vibemonitor.init({
  apiKey: process.env.VIBEMONITOR_API_KEY,
  service: "my-app-server",
});
// src/instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("../vibemonitor.server.config");
  }
}

What gets captured

Three layers run automatically after init():

  1. Explicit APIvibemonitor.log("INFO", "message", { attrs }) from anywhere
  2. Console wrapconsole.log/info/warn/error/debug calls (your code, most libraries)
  3. Process handlersprocess.on('uncaughtException' / 'unhandledRejection')

Plus graceful shutdown flush on beforeExit, SIGTERM, SIGINT (Docker/K8s-friendly).

Manual structured logging

import { log } from "@vibemonitor/node";

log("INFO", "Payment charged", {
  userId: user.id,
  amount: 49.99,
  gateway: "stripe",
});

Configuration reference

vibemonitor.init({
  // Required
  apiKey: process.env.VIBEMONITOR_API_KEY,

  // Identification
  service: "my-api",                      // defaults to package.json name or script name
  environment: process.env.NODE_ENV,
  version: process.env.npm_package_version,

  // Endpoint — default is production; override for local vm-api
  endpoint: "http://localhost:8000/api/v1/ingest/logs",

  // Master switches
  enabled: true,                          // env: VIBEMONITOR_ENABLED
  debug: false,                           // env: VIBEMONITOR_DEBUG

  // Transport tuning
  flushIntervalMs: 2000,
  maxQueueSize: 1000,
  batchSize: 50,

  // Capture layers
  captureConsole: true,                   // wrap console.*
  captureGlobalErrors: true,              // listen to process.on('uncaughtException' / 'unhandledRejection')

  // PII scrubbing (default-on — redact before send)
  scrubPatterns: ["email", "jwt", "aws_key", ...],
  customScrubPatterns: { customerId: /CUST-\d+/g },

  // Hook to mutate or drop entries
  beforeSend: (entry) => entry,
});

Known gap — pino / winston / bunyan

Structured loggers like pino, winston, and bunyan write directly to process.stdout or their own transports — they bypass console.* entirely. Our console wrapping doesn't catch them.

Workarounds (today)

Option A — mirror important logs via the explicit API:

import vibemonitor from "@vibemonitor/node";
import pino from "pino";

const logger = pino();

function logError(msg, data) {
  logger.error(data, msg);
  vibemonitor.log("ERROR", msg, data);   // ← mirror to Vibemonitor
}

Option B — attach a pino transport that does both:

const logger = pino({
  transport: {
    targets: [
      { target: "pino-pretty" },            // console output
      { target: "./vibemonitor-transport" }, // forward to Vibemonitor
    ],
  },
});

Coming soon

@vibemonitor/node/pino and @vibemonitor/node/winston adapters are on the roadmap. They'll let you do:

import pino from "pino";
import { pinoTransport } from "@vibemonitor/node/pino";

const logger = pino({ transport: pinoTransport });

Best practices

Disable in tests / CI

vibemonitor.init({
  apiKey: process.env.VIBEMONITOR_API_KEY,
  enabled: process.env.NODE_ENV !== "test",
});

Or via env:

VIBEMONITOR_ENABLED=false npm test

Wrap in your own logger

// src/lib/logger.ts
import vibemonitor from "@vibemonitor/node";

export function createLogger(module: string) {
  return {
    info: (msg: string, data?: Record<string, unknown>) =>
      vibemonitor.log("INFO", msg, { module, ...data }),
    error: (msg: string, data?: Record<string, unknown>) =>
      vibemonitor.log("ERROR", msg, { module, ...data }),
  };
}

// Usage
import { createLogger } from "./lib/logger";
const log = createLogger("payments");
log.info("Charge succeeded", { userId, amount });

AWS Lambda / Cloud Functions

The SDK works in serverless as long as process.on('beforeExit') fires (it does by default). For very-short-lived invocations, consider calling await vibemonitor.shutdown() at the end of your handler to force a flush:

export async function handler(event) {
  try {
    const result = await doWork(event);
    return result;
  } finally {
    await vibemonitor.shutdown();        // flush before Lambda freezes
  }
}

Kubernetes / Docker graceful shutdown

SIGTERM handling is automatic — when your pod receives SIGTERM, the SDK flushes pending logs before the process exits. No extra setup needed.


Compatibility

  • Node.js 18+ — required (native fetch)
  • Bun — mostly compatible (uses web-standard fetch, zlib polyfilled)
  • Deno — works with a compat shim for process.on

Shutdown

await vibemonitor.shutdown();

Called automatically on beforeExit, SIGTERM, SIGINT. Call explicitly for:

  • Short-lived serverless functions (flush before freeze)
  • Graceful teardown in tests
  • Custom shutdown signals

FAQ

Q: Can I use this with TypeScript that isn't Node runtime (e.g., Deno)? Mostly yes. Deno supports process via a compat layer. Test in your environment.

Q: Does this work in Bun? Yes — Bun implements fetch, zlib, and process.on. Behavior is identical.

Q: My SIGTERM handler doesn't flush in time. Increase Docker/K8s terminationGracePeriodSeconds to at least 5s (default 30s is plenty). The SDK has a 5-second flush timeout by default.

Q: How do I see what's actually being sent? Set debug: true or VIBEMONITOR_DEBUG=1. The SDK will print [vibemonitor] lines to stderr showing init config, flush attempts, 429 backoff, and circuit-breaker events.


License

Proprietary. See LICENSE.