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

sentinel-node-sdk

v1.0.0

Published

Sentinel AI exception monitoring SDK for Node.js / TypeScript applications

Readme

sentinel-node-sdk

A Node.js/TypeScript SDK for capturing, PII-scrubbing, and reporting runtime exceptions to the Sentinel AI gateway for automated analysis.

Requirements

  • Node.js ≥ 18.3.0 (uses native fetch — no HTTP library dependency)
  • TypeScript ≥ 5.4 (if using TypeScript)

Installation

npm install sentinel-node-sdk

Framework integrations are optional — install only what you use:

# Express
npm install express

# Next.js
npm install next

Quick Start

Call configure() once at application startup, before any other SDK function:

import { configure, installHook, sentinelMiddleware, withSentinel } from "sentinel-node-sdk";

configure({
  apiKey:     process.env.SENTINEL_API_KEY!,
  githubRepo: "acme/payment-service",   // must be registered in the Sentinel portal
});

Then choose one or more integrations depending on your stack.


Integrations

Global process hook

Catches uncaughtException and unhandledRejection at the process level. Call this once, after configure().

installHook();

Caveat: Because Node.js may exit the process immediately after an uncaughtException listener returns, delivery is best-effort. The dispatch is fire-and-forget and begins executing before process exit, but a very fast shutdown can prevent the network request from completing.

Express

Register sentinelMiddleware as an error-handling middleware — after all routes, before any other error handlers:

import express from "express";

const app = express();

app.get("/orders/:id", handler);

// Register Sentinel last
app.use(sentinelMiddleware);

// Your own error handler still runs — Sentinel calls next(err)
app.use((err, req, res, next) => { res.status(500).json({ error: "Internal error" }); });

Sentinel never swallows errors. It calls next(err) unconditionally, so all downstream handlers run unchanged.

Next.js (App Router)

Wrap individual route handlers with withSentinel:

// app/api/orders/[id]/route.ts
import { withSentinel } from "sentinel-node-sdk";

export const GET = withSentinel(async (req) => {
  const order = await fetchOrder(req);
  return Response.json(order);
});

export const POST = withSentinel(async (req) => {
  // ...
});

withSentinel captures any exception, dispatches it to the gateway, then re-throws — Next.js's own error.tsx / global-error.tsx boundaries run normally.


Configuration

configure({
  // Required
  apiKey:           "your-api-key",          // Bearer token from the Sentinel portal
  githubRepo:       "owner/repo",            // Must match the gateway allowlist

  // Optional
  gatewayUrl:       "https://nexuspartner.dev",  // Override for staging / self-hosted
  timeoutMs:        5000,                    // Per-attempt HTTP timeout (ms)
  maxRetries:       3,                       // Max send attempts (4xx errors are not retried)
  retryBackoffBase: 500,                     // Exponential backoff base (ms), full jitter
  endpointLabel:    "<unknown>",             // Fallback label for hook-captured exceptions
  enabled:          true,                    // Set false to silence all network I/O
});

Disabling via environment variable

SENTINEL_ENABLED=false node server.js

Accepted values: false, 0, no, off (case-insensitive). Useful in test environments and CI without changing application code.


PII Scrubbing

Before any data leaves the process, errorMessage and stackTrace are scrubbed for:

| Category | Example input | Redacted output | |---|---|---| | Email addresses | [email protected] | [EMAIL] | | Credit card numbers | 4111 1111 1111 1111 | [CREDIT_CARD] | | IPv4 addresses | 192.168.1.1 | [IP_ADDRESS] | | IPv6 addresses | 2001:db8::1, ::1 | [IP_ADDRESS] | | Bearer tokens | Bearer eyJhbGc... | Bearer [REDACTED_TOKEN] | | Vendor API keys | sk-abc123, ghp_xyz | sk-[REDACTED_TOKEN] | | Key=value secrets | password=hunter2 | password=[REDACTED_SECRET] |

Structural fields (exceptionType, endpoint, githubRepo, timestamp) are never scrubbed — they cannot contain free-text PII by design.


Gateway payload

Each captured exception is sent as a POST /api/v1/exceptions request with this JSON body:

interface ExceptionRequest {
  exceptionType: string;      // e.g. "TypeError", "PaymentError"
  errorMessage:  string;      // PII-scrubbed error.message
  stackTrace:    string;      // PII-scrubbed error.stack, full depth
  endpoint:      string;      // Route path or endpointLabel
  timestamp:     string;      // ISO 8601 UTC
  githubRepo:    string;      // "owner/repo"
  language:      "typescript";
}

The language field is hard-coded to "typescript" and cannot be overridden. If you are running plain JavaScript, the gateway still processes the event but uses the TypeScript-oriented AI workflow (V8 frame parser, Jest test generation).


Retry behaviour

Failed dispatches are retried up to maxRetries times using full-jitter exponential backoff:

delay = random(0, retryBackoffBase × 2^attempt)
  • 4xx responses (auth failure, quota exceeded, unregistered repo) are not retried — they are terminal.
  • 5xx responses and network/timeout errors are retried.
  • All errors are reported via console.warn; they never propagate to the application.

Development

# Type-check without emitting
npm run typecheck

# Compile all output formats (CJS + ESM + type declarations)
npm run build

There is currently no test suite. The npm test step in CI is a placeholder.

Output formats

The build produces three output directories under dist/:

| Directory | Format | Use case | |---|---|---| | dist/cjs/ | CommonJS | require() in Node.js | | dist/esm/ | ES modules | import in Node.js / bundlers | | dist/types/ | Type declarations | TypeScript IDE support |

Publishing

Releases are published automatically by GitHub Actions when a v* tag is pushed. The workflow verifies that package.json's version field matches the git tag and attaches Sigstore provenance to the published tarball.


Known limitations

  • No test suite. The project ships without automated tests. Any contribution that adds behaviour should include tests.
  • language is always "typescript". Plain JavaScript consumers get the TypeScript AI workflow, which may produce less accurate results.
  • installHook() delivery is not guaranteed on process crash. The fire-and-forget Promise starts executing, but a very short-lived process may exit before the HTTP request completes.
  • configure() is silently replaceable. Calling it a second time replaces the active config with no warning. In an application that initialises multiple times (e.g. hot reload in development), this can produce unexpected behaviour.
  • githubRepo must be on the gateway allowlist. The gateway will reject payloads for unregistered repositories with a 4xx response; there is no local validation at configure() time.