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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@lattice.black/plugin-express

v0.3.0

Published

Lattice plugin for Express.js service discovery

Readme

@lattice.black/plugin-express

Express.js plugin for Lattice - automatic service discovery, error tracking, and metrics collection for microservices.

Features

  • Automatic Route Discovery - Discovers all Express routes and endpoints
  • Dependency Analysis - Analyzes package.json dependencies
  • Error Tracking - Captures and reports errors with stack traces
  • Request Metrics - Tracks response times and status codes
  • Privacy-First - No PII captured by default (following Sentry patterns)
  • Configurable Sampling - Reduce data volume with sampling rules
  • Event Batching - Efficient batched submissions
  • Graceful Shutdown - Proper cleanup with forceFlush() and shutdown()

Installation

npm install @lattice.black/plugin-express
# or
yarn add @lattice.black/plugin-express

Quick Start

import express from 'express';
import { LatticePlugin } from '@lattice.black/plugin-express';

const app = express();

// Initialize Lattice
const lattice = new LatticePlugin({
  serviceName: 'my-api',
  apiKey: process.env.LATTICE_API_KEY,
});

// Add metrics middleware BEFORE routes
app.use(lattice.createMetricsMiddleware());

// Your routes
app.get('/users', (req, res) => res.json({ users: [] }));
app.post('/users', (req, res) => res.json({ id: 1 }));

// Add error handler AFTER routes
app.use(lattice.errorHandler());

// Analyze and start
lattice.analyze(app).then(() => {
  app.listen(3000, () => console.log('Server running'));
});

// Graceful shutdown
process.on('SIGTERM', async () => {
  await lattice.shutdown();
  process.exit(0);
});

Configuration

Full Configuration Options

import { LatticePlugin } from '@lattice.black/plugin-express';

const lattice = new LatticePlugin({
  // Service Identity
  serviceName: 'my-api',              // Auto-detected if not provided
  environment: 'production',          // 'development' | 'staging' | 'production'

  // API Connection
  apiEndpoint: 'https://your-lattice-api.com/api/v1',
  apiKey: process.env.LATTICE_API_KEY,

  // Behavior
  enabled: true,                      // Enable/disable entirely
  autoSubmit: true,                   // Auto-submit metadata after analysis
  submitInterval: 300000,             // Auto-submit interval (5 minutes)
  debug: false,                       // Enable debug logging

  // Discovery
  discoverRoutes: true,               // Discover Express routes
  discoverDependencies: true,         // Analyze package.json
  packageJsonPath: './package.json',  // Custom package.json path

  // Privacy Settings (NEW in 0.2.0)
  privacy: {
    captureRequestBody: false,        // Don't capture request bodies
    captureRequestHeaders: false,     // Only capture safe headers
    captureQueryParams: false,        // Don't capture query params
    captureIpAddress: false,          // Don't capture IP addresses
    safeHeaders: ['content-type', 'accept', 'user-agent'],
    additionalPiiFields: ['customSecret'], // Extra fields to redact
  },

  // Sampling (NEW in 0.2.0)
  sampling: {
    errors: 1.0,                      // Capture 100% of errors
    metrics: 0.1,                     // Capture 10% of metrics
    rules: [
      { match: { path: '/health' }, rate: 0.01 },     // 1% for health checks
      { match: { path: '/api/**' }, rate: 0.5 },     // 50% for API routes
      { match: { errorType: 'ValidationError' }, rate: 0.1 },
    ],
  },

  // Batching (NEW in 0.2.0)
  batching: {
    maxBatchSize: 10,                 // Events per batch
    flushIntervalMs: 5000,            // Flush every 5 seconds
    maxQueueSize: 1000,               // Max queued events (backpressure)
  },

  // Hooks (NEW in 0.2.0)
  beforeSendError: (event) => {
    // Return null to drop the event
    if (event.message?.includes('ignore-this')) return null;
    // Or modify and return
    return event;
  },

  // Callbacks
  onAnalyzed: (metadata) => console.log('Analyzed:', metadata),
  onSubmitted: (response) => console.log('Submitted:', response),
  onError: (error) => console.error('Error:', error),
});

Environment Variables

LATTICE_API_ENDPOINT=https://your-lattice-api.com/api/v1
LATTICE_API_KEY=your-api-key
LATTICE_SERVICE_NAME=my-api
LATTICE_ENABLED=true
LATTICE_AUTO_SUBMIT=true
LATTICE_SUBMIT_INTERVAL=300000
LATTICE_DEBUG=false

Privacy-First Design

Following Sentry's privacy patterns, no PII is captured by default:

// Default: Privacy-first (no sensitive data captured)
const lattice = new LatticePlugin({
  serviceName: 'my-api',
});

// Opt-in to capture more data
const lattice = new LatticePlugin({
  serviceName: 'my-api',
  privacy: {
    captureRequestBody: true,    // Opt-in to capture bodies
    captureRequestHeaders: true, // Opt-in to capture all headers
    captureQueryParams: true,    // Opt-in to capture query params
  },
});

Automatic PII Scrubbing

Even when capturing data, sensitive fields are automatically redacted:

  • Passwords, secrets, tokens, API keys
  • Authorization headers, cookies, sessions
  • Credit card numbers, SSNs (pattern matching)
  • JWT tokens, Bearer tokens

Sampling

Reduce data volume with configurable sampling:

const lattice = new LatticePlugin({
  sampling: {
    errors: 1.0,    // Capture all errors (important!)
    metrics: 0.1,   // Only 10% of metrics

    // Rule-based sampling (first match wins)
    rules: [
      { match: { path: '/health' }, rate: 0.01 },
      { match: { path: '/api/v1/**' }, rate: 0.2 },
      { match: { errorType: 'ValidationError' }, rate: 0.5 },
    ],
  },
});

Event Batching

Events are batched for efficient network usage:

const lattice = new LatticePlugin({
  batching: {
    maxBatchSize: 20,       // Send when 20 events queued
    flushIntervalMs: 10000, // Or every 10 seconds
    maxQueueSize: 2000,     // Drop events if queue exceeds this
  },
});

Lifecycle Management

Graceful Shutdown

Always call shutdown() before process exit:

process.on('SIGTERM', async () => {
  await lattice.shutdown();  // Flushes pending events
  process.exit(0);
});

Manual Flush

Force send all pending events:

await lattice.forceFlush(5000); // 5 second timeout

beforeSend Hooks

Filter or modify events before sending:

const lattice = new LatticePlugin({
  beforeSendError: (event) => {
    // Drop internal errors
    if (event.message?.includes('INTERNAL')) return null;
    // Or modify
    delete event.context?.sensitiveField;
    return event;
  },
});

Manual Error Capture

try {
  await riskyOperation();
} catch (error) {
  await lattice.captureError(error, { userId: user.id });
}

Distributed Tracing

const http = lattice.getHttpClient();

// Wrapped fetch with tracing headers
const response = await http.fetch('http://other-service/api/users');

// Or get headers for axios
const headers = http.getTracingHeaders();
await axios.get('http://other-service/api', { headers });

API Reference

| Method | Description | |--------|-------------| | analyze(app) | Discover routes and dependencies | | submit(metadata?) | Submit metadata to API | | start() | Start auto-submit interval | | stop() | Stop auto-submit interval | | forceFlush(timeout?) | Force send all pending events | | shutdown(timeout?) | Graceful shutdown | | createMetricsMiddleware() | Create metrics middleware | | errorHandler() | Create error handler middleware | | captureError(error, context?) | Manually capture an error | | getHttpClient() | Get HTTP client with tracing | | getMetadata() | Get current service metadata | | getServiceName() | Get detected service name | | isEnabled() | Check if plugin is enabled | | getState() | Get SDK state | | getConfig() | Get resolved configuration |

Migration from 0.1.x

Breaking Changes

None! The 0.2.0 release is backwards compatible.

New Defaults (Privacy-First)

  • Request body, headers, and query params are no longer captured by default
  • Events are now batched (10 events or 5 seconds)

Recommended Updates

Add shutdown handling for graceful cleanup:

process.on('SIGTERM', () => lattice.shutdown());

License

MIT