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

@meet-sudo/sdk

v0.5.1

Published

Sudo Server SDK — change-aware observability for Node.js backends

Readme

@meet-sudo/sdk

Change-aware observability for Node.js backends. Auto-capture HTTP requests, then add first-class model_call and job instrumentation so Sudo can explain what changed and what regressed.

Install

npm install @meet-sudo/sdk

Use your server-side workspace key (sk_...) when creating the SDK client. The env var name is up to you; the examples below use SUDO_API_KEY.

Four integration paths

Tier 1 — Auto-capture middleware (zero effort)

Add one line and Sudo captures every HTTP request, response status, latency, and unhandled error.

Express

import express from "express";
import { SudoServer, sudoExpress } from "@meet-sudo/sdk";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });
const app = express();

const sudo = sudoExpress({ sudo: ms, service: "api" });
app.use(sudo.middleware);

// ... your routes ...

app.use(sudo.errorHandler);
app.listen(3000);

Fastify

import Fastify from "fastify";
import { SudoServer } from "@meet-sudo/sdk";
import { sudoFastify } from "@meet-sudo/sdk/middleware/fastify";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });
const app = Fastify();

app.register(sudoFastify, { sudo: ms, service: "api" });
app.listen({ port: 3000 });

Koa

import Koa from "koa";
import { SudoServer } from "@meet-sudo/sdk";
import { sudoKoa } from "@meet-sudo/sdk/middleware/koa";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });
const app = new Koa();

const sudo = sudoKoa({ sudo: ms, service: "api" });
app.use(sudo.middleware);

app.listen(3000);

Next.js (App Router)

Assume @/lib/meetsudo exports your initialized SudoServer instance.

// app/api/users/route.ts
import { ms } from "@/lib/meetsudo";
import { withSudo } from "@meet-sudo/sdk";
import { NextResponse } from "next/server";

export const GET = withSudo(ms, { service: "api" }, async (req) => {
  const users = await db.users.findMany();
  return NextResponse.json(users);
});

The middleware auto-captures: method, path, status, duration (ms), user agent, IP, and request ID. User ID is extracted from req.user or req.auth if present. Errors include message and stack trace. These logs are explicitly classified as event_class="http" so Sudo can reason about request health without inferring from raw props.

Tier 2 — Direct logging (manual instrumentation)

For business events, background jobs, cron tasks, and anything the middleware can't see.

await ms.error("Stripe returned 402", {
  service: "api",
  event: "checkout_failed",
  user_id: "user_123",
  props: { duration_ms: 742, amount: 99 },
});

await ms.warn("Worker retries increased", {
  service: "worker",
  event: "billing_sync_retry",
  event_class: "job",
  props: { retry_count: 3, queue_name: "critical" },
});
await ms.info("Deploy completed", { service: "deploy" });
await ms.debug("Cache miss", { service: "cache" });

For custom non-HTTP workloads, set event_class explicitly. Otherwise Sudo may store the log row but exclude it from Change Impact and SLO analysis.

Tier 3 — Native AI and job instrumentation

For the signal types that matter most to Sudo's regression engine, use the first-class helpers instead of generic logs.

await ms.modelCall({
  service: "assistant-api",
  model: "claude-sonnet-4-20250514",
  provider: "anthropic",
  operation: "messages",
  prompt_version: "support-v12",
  duration_ms: 842,
  ttft_ms: 220,
  tokens_in: 1240,
  tokens_out: 311,
  cost_usd: 0.0182,
  request_id: "req_123",
});

await ms.jobRun({
  service: "worker",
  job_name: "sync_customer_state",
  queue_name: "critical",
  duration_ms: 1934,
  retry_count: 1,
  status: "success",
});

You can also time work automatically:

const completion = await ms.withModelCall({
  service: "assistant-api",
  model: "claude-sonnet-4-20250514",
  provider: "anthropic",
  operation: "chat_completion",
  prompt_version: "onboarding-v8",
  request_id: "req_123",
}, async () => {
  return anthropic.messages.create({ /* ... */ });
});

await ms.withJobRun({
  service: "worker",
  job_name: "rebuild_embeddings",
  queue_name: "embeddings",
}, async () => {
  await rebuildEmbeddingsForWorkspace(workspaceId);
});

For the common providers, you can let Sudo extract usage fields from the response automatically. Anthropic is shown first because that is the best-supported path for Sudo today; OpenAI remains available as an optional wrapper.

const message = await ms.withAnthropicModelCall({
  service: "assistant-api",
  prompt_version: "support-v12",
  model: "claude-sonnet-4-20250514", // optional on success, useful for error cases
}, async () => {
  return anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 400,
    messages: [{ role: "user", content: "Summarize the latest checkout failures" }],
  });
});

const response = await ms.withOpenAIModelCall({
  service: "assistant-api",
  prompt_version: "onboarding-v8",
  model: "gpt-5.4-mini",
}, async () => {
  return openai.responses.create({
    model: "gpt-5.4-mini",
    input: "Explain the regression",
  });
});

Those wrappers time the call and, on success, auto-fill:

  • provider
  • model
  • tokens_in
  • tokens_out
  • common provider metadata like response_id or stop_reason

For job runtimes, you can wrap the processor instead of hand-writing jobRun(...) calls:

BullMQ

import { Worker } from "bullmq";
import { SudoServer, instrumentBullMQProcessor } from "@meet-sudo/sdk";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });

new Worker(
  "critical",
  instrumentBullMQProcessor(
    { sudo: ms, service: "worker", worker: "billing-worker" },
    async (job) => {
      await syncCustomerState(job.data);
    }
  )
);

Trigger.dev

import { task } from "@trigger.dev/sdk/v3";
import { SudoServer, instrumentTriggerRun } from "@meet-sudo/sdk";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });

export const rebuildEmbeddings = task({
  id: "rebuild-embeddings",
  run: instrumentTriggerRun(
    { sudo: ms, service: "worker" },
    async (payload, ctx) => {
      await rebuildEmbeddingsForWorkspace(payload.workspaceId);
    }
  ),
});

Those adapters automatically capture:

  • job or task name
  • queue name when available
  • attempt number
  • duration
  • success vs failure
  • run or job ID when available

Tier 4 — Logger transports (existing logger integration)

Already using Pino or Winston? Add Sudo as a transport — zero changes to your existing logging code.

Pino

import pino from "pino";
import { SudoServer, createPinoTransport } from "@meet-sudo/sdk";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });

const logger = pino({ level: "info" }, pino.multistream([
  { stream: process.stdout },
  { stream: createPinoTransport({ sudo: ms, service: "api" }) },
]));

Winston

import winston from "winston";
import { SudoServer, createWinstonTransport } from "@meet-sudo/sdk";

const ms = new SudoServer({ apiKey: process.env.SUDO_API_KEY! });

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console(),
    new winston.transports.Stream({
      stream: createWinstonTransport({ sudo: ms, service: "api" }),
    }),
  ],
});

Change markers

// Mark a deploy
await ms.markDeploy({
  version: "2026.04.03.1",
  scope: "assistant-api",
  metadata: { commit: "4b72f0a" },
});

You can also record prompt and model changes:

await ms.markPromptVersion({
  version: "support-v12",
  scope: "assistant-api",
});

await ms.markModelVersion({
  version: "claude-sonnet-4-20250514",
  scope: "assistant-api",
});

Middleware configuration

All middleware accepts these options:

| Option | Default | Description | |--------|---------|-------------| | sudo | required | MeetSudoServer instance | | service | undefined | Service name for logs (e.g. "api") | | ignorePaths | ["/health", "/healthz", ...] | Paths to skip | | extractUserId | Auto-detect from req.user/req.auth | Custom user ID extractor | | errorStatusThreshold | 500 | Min status code logged as error | | batchSize | 25 | Logs buffered before flush | | flushInterval | 5000 | Max ms before flushing |

License

MIT