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

@pawells/nestjs-shared

v2.0.2

Published

Shared NestJS infrastructure: filters, logging, metrics, and security

Readme

NestJS Shared Module

GitHub Release CI npm version Node License: MIT GitHub Sponsors

Foundational NestJS infrastructure library providing filters, guards, interceptors, logging, CSRF protection, error handling, configuration, metrics, and lazy loading utilities.

Installation

yarn add @pawells/nestjs-shared

Requirements

  • Node.js: >= 22.0.0
  • NestJS: >= 10.0.0

Peer Dependencies

{
  "@nestjs/common": ">=10.0.0",
  "@nestjs/config": ">=3.0.0",
  "@nestjs/core": ">=10.0.0",
  "@nestjs/throttler": ">=5.0.0",
  "@opentelemetry/api": ">=1.0.0",
  "class-transformer": ">=0.5.0",
  "class-validator": ">=0.14.0",
  "compression": ">=1.0.0",
  "csrf-csrf": ">=4.0.0",
  "express": ">=5.0.0",
  "helmet": ">=7.0.0",
  "joi": ">=18.0.0",
  "prom-client": ">=15.0.0",
  "rxjs": ">=7.0.0",
  "xss": ">=1.0.0"
}

Quick Start

1. Initialize ConfigModule (MUST come first)

import { Module } from '@nestjs/common';
import { ConfigModule } from '@pawells/nestjs-shared';

@Module({
  imports: [
    ConfigModule,  // Must be first
  ],
})
export class AppModule {}

2. Import CommonModule

import { Module } from '@nestjs/common';
import { CommonModule } from '@pawells/nestjs-shared';

@Module({
  imports: [
    ConfigModule,     // Must be first
    CommonModule,     // Depends on ConfigModule
  ],
})
export class AppModule {}

3. Use Global Filters and Interceptors

Global filters and interceptors are automatically registered by CommonModule:

  • GlobalExceptionFilter & HttpExceptionFilter: Standardized error responses
  • LoggingInterceptor: Request/response logging
  • HTTPMetricsInterceptor: HTTP metrics collection
  • ValidationPipe: Automatic DTO validation

All are applied globally and available for injection in services.

Features

Error Handling

Comprehensive error handling with structured responses, categorization, and sanitization.

import {
  BaseApplicationError,
  GlobalExceptionFilter,
  ErrorCategorizerService,
  ErrorSanitizerService,
} from '@pawells/nestjs-shared';

// Create custom error
export class UserNotFoundError extends BaseApplicationError {
  constructor(userId: string) {
    super(`User ${userId} not found`, {
      code: 'USER_NOT_FOUND',
      statusCode: 404,
      context: { userId }
    });
  }
}

// Throw it
throw new UserNotFoundError('123');

// Automatically caught by GlobalExceptionFilter
// Response includes code, message, timestamp, sanitized context, stack (dev only)

Error Categories: Errors are automatically categorized as transient (retryable) or permanent (fail-fast) with recommended recovery strategies.

Logging

Centralized, structured logging with automatic redaction of sensitive data.

import { AppLogger } from '@pawells/nestjs-shared';

constructor(private logger: AppLogger) {}

// Flexible logging methods
this.logger.info('User created', 'UserService', { userId: '123' });
this.logger.debug('Cache hit', { metadata: { key: 'users:123' } });
this.logger.error('Database error', error.stack, { query: '...' });
this.logger.warn('Rate limit approaching', { context: 'RateLimiter' });
this.logger.fatal('System shutdown', { context: 'ShutdownService' });

// Automatic redaction of sensitive fields: passwords, tokens, API keys, emails, IPs
this.logger.info('Login attempt', { password: 'secret' });
// Logs: { password: '[REDACTED]' }

// OpenTelemetry integration: traceId and spanId automatically included

Log Levels: Controlled by LOG_LEVEL environment variable (debug, info, warn, error, fatal, silent).

Metrics

Prometheus metrics for HTTP requests and custom metrics.

import { MetricsRegistryService } from '@pawells/nestjs-shared';

constructor(private metrics: MetricsRegistryService) {}

// Record custom metrics
const orderCounter = this.metrics.CreateCounter(
  'orders_total',
  'Total orders processed'
);
orderCounter.inc({ status: 'completed' });

// HTTP metrics are automatic (duration, count, size)
// Access at GET /metrics in Prometheus format
const registry = this.metrics.GetRegistry();
const prometheusMetrics = await registry.metrics();

Features:

  • Automatic HTTP request metrics (duration histogram, request counter, size histogram)
  • Dynamic path normalization (UUIDs, ObjectIDs, numeric IDs → :id) to prevent unbounded cardinality
  • Default Node.js metrics collection
  • Custom metric creation (counter, gauge, histogram)
  • Controlled by METRICS_ENABLED environment variable (default: true)

CSRF Protection

Double-Submit Cookie pattern with per-IP rate limiting.

import { CSRFGuard, CSRFService } from '@pawells/nestjs-shared';

// Globally applied by CommonModule
// Or manually on specific controller
@UseGuards(CSRFGuard)
@Controller('api')
export class ApiController {
  constructor(private csrf: CSRFService) {}

  @Post('/form')
  async submitForm(@Req() req: Request, @Res() res: Response) {
    // Generate token
    const token = await this.csrf.GenerateToken(req, res);
    res.render('form', { csrfToken: token });
  }

  @Post('/process')
  async processForm(@Req() req: Request) {
    // Validation done automatically by CSRFGuard
    // Safe methods (GET, HEAD, OPTIONS) bypass validation
  }
}

Features:

  • Token generation with rate limiting (10 per IP per 60s)
  • Session binding or IP-based fallback
  • Automatic pruning of stale timestamps
  • Capacity monitoring with safety margins
  • Configurable proxy trust for X-Forwarded-For header
  • CSRF_SECRET entropy validation at startup

Validation

Automatic DTO validation and transformation.

import { IsEmail, IsNotEmpty, MinLength } from 'class-validator';

export class CreateUserDto {
  @IsNotEmpty()
  @IsEmail()
  email: string;

  @IsNotEmpty()
  @MinLength(8)
  password: string;
}

@Post()
async createUser(@Body() dto: CreateUserDto) {
  // DTO automatically validated and transformed
  // Validation errors formatted as error array with field paths
}

Features:

  • Automatic DTO validation via ValidationPipe
  • Nested object support with path prefixes
  • Comprehensive error formatting
  • Class transformation with class-transformer

Health Checks

Kubernetes-ready health, readiness, and liveness probes.

import { HealthCheckService, HealthStatus } from '@pawells/nestjs-shared';

constructor(private health: HealthCheckService) {}

@Get('/health')
getHealth() {
  return this.health.GetHealth('my-service', '1.0.0');
}

@Get('/ready')
getReadiness() {
  return this.health.GetReadiness({
    database: HealthStatus.OK,
    cache: HealthStatus.OK,
  });
}

@Get('/live')
getLiveness() {
  return this.health.GetLiveness();
}

Configuration

Type-safe environment variable access with validation.

import { ConfigService } from '@pawells/nestjs-shared';

constructor(private config: ConfigService) {}

// Type-safe getters
const port = this.config.GetNumber('PORT') ?? 3000;
const nodeEnv = this.config.GetString('NODE_ENV') ?? 'development';
const dbUrl = this.config.GetOrThrow('DATABASE_URL');

// Validation
this.config.Validate({
  PORT: { required: true },
  DATABASE_URL: { required: true },
  LOG_LEVEL: { required: false },
});

Audit Logging

Security event logging for compliance and forensics.

import { AuditLoggerService } from '@pawells/nestjs-shared';

constructor(private audit: AuditLoggerService) {}

// Log authentication
this.audit.LogAuthenticationAttempt('[email protected]', true, '192.168.1.1');

// Log authorization failure
this.audit.LogAuthorizationFailure('user-123', 'documents', 'delete', '192.168.1.1');

// Log CSRF violations
this.audit.LogCsrfViolation('192.168.1.1', '/api/users');

// Log custom security events
this.audit.LogSecurityEvent({
  userId: 'user-123',
  action: 'password_change',
  resource: 'users/123',
  result: 'success',
  ipAddress: '192.168.1.1'
});

Lazy Loading

Defer dependency resolution to avoid circular dependencies.

import {
  TLazyGetter,
  ILazyModuleRefService,
  createMemoizedLazyGetter,
} from '@pawells/nestjs-shared';
import { ModuleRef } from '@nestjs/core';

@Injectable()
export class MyService implements ILazyModuleRefService {
  private readonly userService: TLazyGetter<UserService> = createMemoizedLazyGetter(
    () => this.Module.get(UserService, { strict: false }),
  );

  constructor(public readonly Module: ModuleRef) {}

  async getUser(id: string) {
    // UserService resolved lazily on first call
    return this.userService().getById(id);
  }
}

Alternatively, extend LazyModuleRefBase to eliminate constructor boilerplate:

import { LazyModuleRefBase } from '@pawells/nestjs-shared';

@Injectable()
export class MyService extends LazyModuleRefBase {
  protected get UserService(): UserService {
    return this.Module.get(UserService);
  }
}

Features:

  • TLazyGetter<T>: Type alias for a required dependency getter function
  • TOptionalLazyGetter<T>: Type alias for an optional dependency getter function
  • createMemoizedLazyGetter: Factory that caches the resolved dependency after first call
  • createOptionalLazyGetter: Safe resolution that returns undefined instead of throwing
  • isLazyModuleRefService: Type guard for pattern detection
  • LazyModuleRefBase: Abstract base class to avoid constructor boilerplate

HTTP Client

Robust HTTP client with timeout, SSL/TLS, and sensitive data redaction.

import { HttpClientService } from '@pawells/nestjs-shared';

constructor(private http: HttpClientService) {}

// GET request
const response = await this.http.Get<User>('https://api.example.com/users/123');

// POST request with custom timeout
const response = await this.http.Post<User>(
  'https://api.example.com/users',
  { name: 'John', email: '[email protected]' },
  { timeout: 5000, correlationId: 'req-123' }
);

// HTTPS with custom CA certificate
const cert = fs.readFileSync('/path/to/ca.pem');
const response = await this.http.Get(
  'https://internal-api.local/data',
  { ca: cert }
);

Features:

  • Configurable timeouts (default: HTTP_CLIENT_TIMEOUT)
  • SSL/TLS certificate validation (strict by default)
  • Custom CA certificate support
  • Payload size limit (10MB)
  • Automatic content-type parsing
  • Correlation ID support
  • Sensitive data redaction in logs
  • Duration tracking

Decorators

Request property extractors for cleaner controller methods.

import { Query, Params, Body, Headers, Cookies } from '@pawells/nestjs-shared';

@Controller('users')
export class UserController {
  @Get(':id')
  getUser(
    @Params('id') id: string,
    @Query('include') include?: string,
  ) {
    // Route params and query params extracted
  }

  @Post()
  createUser(
    @Body() dto: CreateUserDto,
    @Headers('authorization') auth?: string,
  ) {
    // Body and headers extracted
  }

  @Get()
  listUsers(@Cookies('sessionId') sessionId?: string) {
    // Cookies extracted
  }
}

Core Modules

CommonModule

Global module providing all shared infrastructure.

// Automatically applied globally
@Global()
@Module({
  providers: [
    // Filters (global)
    GlobalExceptionFilter,
    HttpExceptionFilter,

    // Interceptors (global)
    LoggingInterceptor,
    HTTPMetricsInterceptor,

    // Pipe (global)
    ValidationPipe,

    // Services (injectable)
    AppLogger,
    AuditLoggerService,
    CSRFService,
    ErrorCategorizerService,
    ErrorSanitizerService,
    HttpClientService,
    MetricsRegistryService,
    HealthCheckService,
  ],
  exports: [...],
})
export class CommonModule {}

ConfigModule

Configuration service with validation.

@Module({
  imports: [ConfigModule],
  // ConfigService and ValidationService automatically available
})
export class AppModule {}

MetricsModule

Optional module that exposes a Prometheus /metrics endpoint.

@Module({
  imports: [
    ConfigModule,
    CommonModule,
    MetricsModule.ForRoot(),   // Opt-in: adds GET /metrics endpoint
  ],
})
export class AppModule {}
// Provides:
// - MetricsRegistryService (injectable)
// - GET /metrics endpoint (Prometheus format)

API Reference

Services

AppLogger

Structured logging service with context support, metadata, and automatic sensitive data redaction.

Methods:

  • Debug(message, context?, metadata?): Debug level (primary PascalCase method)
  • debug(message, context?, metadata?): Lowercase alias for Debug
  • info(message, context?, metadata?): Info level
  • warn(message, context?, metadata?): Warning level
  • error(message, trace?, context?, metadata?): Error level with optional stack trace
  • fatal(message, trace?, context?, metadata?): Fatal level with optional stack trace
  • CreateContextualLogger(context): Create a child logger bound to a context string
  • createContextualLogger(context): Lowercase alias, satisfies the IContextualLogger interface

All methods accept either positional parameters or a single ILogOptions object { context?, trace?, metadata? } as the second argument.

NestLoggerAdapter

Adapts AppLogger to the NestJS LoggerService interface. Pass an instance to NestFactory.create() to route all NestJS framework logs through AppLogger.

import { NestLoggerAdapter } from '@pawells/nestjs-shared';

const app = await NestFactory.create(AppModule, {
  logger: new NestLoggerAdapter(),
});

The adapter provides both PascalCase methods (Log, Error, Warn, Debug, Verbose, Fatal) and the lowercase aliases (log, error, warn) required by the NestJS LoggerService interface.

ErrorCategorizerService

Classifies errors as transient/permanent and recommends recovery strategy.

Methods:

  • CategorizeError(error): Returns IErrorCategory with type, retryable, strategy, backoffMs
  • IsRetryable(error): Boolean check
  • LogRecoveryAttempt(error, attempt, maxAttempts): Log retry attempt
  • LogRecoverySuccess(error, attempts): Log successful recovery
  • LogRecoveryFailed(error, attempts): Log failed recovery

ErrorSanitizerService

Removes sensitive information from error responses before they are sent to clients.

Methods:

  • SanitizeErrorResponse(error, isDevelopment?): Sanitize error object for client response; strips stack traces in production and redacts sensitive field values

Redactions applied to messages: file paths, database URIs, API keys, Bearer tokens, email addresses, IP addresses. Redactions applied to context objects: field names matching sensitive patterns (password, token, secret, key, etc.).

CSRFService

CSRF token generation and validation with rate limiting.

Methods:

  • GenerateToken(req, res): Generate and set CSRF token; rate-limited to 10 per IP per 60 seconds
  • ValidateToken(req): Validate CSRF token; returns true if valid
  • RefreshToken(req, res): Generate a fresh token after sensitive operations (login, password change)
  • GetMiddleware(): Return the underlying doubleCsrf middleware function

MetricsRegistryService

Prometheus metrics management.

Methods:

  • RecordHttpRequest(method, route, statusCode, duration, size?): Record HTTP request metrics
  • CreateCounter(name, help, labelNames?): Create and register a counter metric
  • CreateGauge(name, help, labelNames?): Create and register a gauge metric
  • CreateHistogram(name, help, labelNames?, buckets?): Create and register a histogram metric
  • RecordCounter(name, value?, labels?): Increment a registered counter by name
  • RecordGauge(name, value, labels?): Set a registered gauge value by name
  • RecordHistogram(name, value, labels?): Observe a registered histogram value by name
  • GetRegistry(): Return the underlying Prometheus Registry instance

HealthCheckService

Kubernetes health probes.

Methods:

  • GetHealth(serviceName?, version?): General health check
  • GetReadiness(checks?): Readiness probe (can the service receive traffic)
  • GetLiveness(): Liveness probe (is the service alive)

HttpClientService

HTTP client with timeout and SSL/TLS support.

Methods:

  • Request<T>(options): Make an HTTP request with full options control
  • Get<T>(url, options?): GET request
  • Post<T>(url, data?, options?): POST request
  • Put<T>(url, data?, options?): PUT request
  • Delete<T>(url, options?): DELETE request

ConfigService

Type-safe environment variable access.

Methods:

  • Get<T>(propertyPath, defaultValue?): Return config value or default
  • GetOrThrow<T>(propertyPath): Return config value or throw if not set
  • GetString(propertyPath, defaultValue?): Return value coerced to string
  • GetNumber(propertyPath, defaultValue?): Return value coerced to number
  • Validate(schema): Validate required fields against schema; throws on missing required keys

AuditLoggerService

Security event logging.

Methods:

  • LogAuthenticationAttempt(email, success, ipAddress?, reason?)
  • LogAuthorizationFailure(userId, resource, action, ipAddress?)
  • LogTokenGeneration(userId, tokenType)
  • LogTokenRevocation(userId, reason)
  • LogRateLimitViolation(endpoint, ipAddress, limit)
  • LogCsrfViolation(ipAddress, endpoint)
  • LogConfigurationChange(userId, config, oldValue, newValue)
  • LogDataAccess(userId, resource, action)
  • LogSecurityEvent(entry)

Filters

GlobalExceptionFilter

Catches unhandled exceptions (except HttpException).

  • Standardizes response format
  • Sanitizes sensitive data
  • Categorizes errors
  • Logs with context

HttpExceptionFilter

Handles HTTP exceptions.

  • Formats NestJS built-in exceptions
  • Sanitizes responses
  • Categorizes for logging

Interceptors

LoggingInterceptor

Logs incoming requests and outgoing responses.

  • Uses DEBUG level for /health and /metrics
  • Uses INFO level for other requests
  • Includes method, URL, IP, duration

HTTPMetricsInterceptor

Collects HTTP request metrics.

  • Duration histogram
  • Request counter
  • Request size histogram
  • Automatic route normalization

Guards

CSRFGuard

Validates CSRF tokens on state-changing requests.

  • Bypasses safe methods (GET, HEAD, OPTIONS)
  • Enforces validation for POST/PUT/DELETE/PATCH
  • Throws 403 on validation failure
  • Logs violations to audit log

Pipes

ValidationPipe

Validates DTOs using class-validator.

  • Automatic transformation via class-transformer
  • Nested object support with path prefixes
  • Comprehensive error formatting

Interfaces & Types

ILogger

Basic logging interface without contextual logger creation.

IContextualLogger

Extended logging with contextual logger creation.

ILazyModuleRefService

Interface for services using the lazy ModuleRef pattern.

interface ILazyModuleRefService {
  Module: ModuleRef;
}

TLazyGetter

Function type for a getter that returns a required dependency.

type TLazyGetter<T> = () => T;

TOptionalLazyGetter

Function type for a getter that returns a dependency or undefined.

type TOptionalLazyGetter<T> = () => T | undefined;

IErrorCategory

Error classification result from ErrorCategorizerService.CategorizeError.

interface IErrorCategory {
  type: 'transient' | 'permanent';
  retryable: boolean;
  strategy: 'retry' | 'fail' | 'backoff';
  backoffMs?: number;
}

IHealthCheck

Health check response structure.

interface IHealthCheck {
  status: string;
  timestamp: string;
  service?: string;
  version?: string;
  checks?: Record<string, string>;
}

Conditional Exports

// Main exports (all major classes and utilities)
import { AppLogger, CSRFService } from '@pawells/nestjs-shared';

// Common-only exports (lower-level utilities)
import { CSRFService } from '@pawells/nestjs-shared/common';

// Lazy loader types only
import { TLazyGetter } from '@pawells/nestjs-shared/common/utils/lazy-getter.types';

// Testing helpers (AppLoggerMock, SharedTestingModule, etc.)
import { AppLoggerMock } from '@pawells/nestjs-shared/testing';

Configuration

Environment Variables

  • NODE_ENV: development, production, etc. (affects error details, logging)
  • LOG_LEVEL: debug, info, warn, error, fatal, silent (default: info)
  • PORT: Server port (default: 3000)
  • CSRF_SECRET: Required for CSRF protection (min 32 chars, high entropy)
  • METRICS_ENABLED: Enable metrics (default: true)
  • SERVICE_NAME: Service name for logging (default: unknown-service)

CSRF_SECRET Generation

# Generate secure CSRF_SECRET
openssl rand -hex 32

Security Defaults

  • Token Blacklist (when implemented): Fails closed — treats unavailable cache as blacklist
  • CSRF Token Generation: Per-IP rate limited (10 per 60s)
  • CSRF Validation: Signed tokens with session/IP binding
  • Error Sanitization: Stack traces only in development; sensitive fields redacted
  • CORS: Implemented via security bootstrap (if configured)
  • HTTP Client: Strict SSL/TLS certificate validation (rejectUnauthorized: true)
  • Metrics: Dynamic path normalization prevents unbounded cardinality
  • Logging: Automatic redaction of passwords, tokens, API keys, emails, IPs

Examples

Complete Application Setup

import { NestFactory } from '@nestjs/core';
import { ConfigModule, CommonModule, MetricsModule } from '@pawells/nestjs-shared';

@Module({
  imports: [
    ConfigModule,                  // MUST be first
    CommonModule,                  // Depends on ConfigModule
    MetricsModule.ForRoot(),       // Optional: Prometheus metrics
    // ... feature modules
  ],
})
export class AppModule {}

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

  // All filters, interceptors, pipes already registered globally

  const port = process.env['PORT'] ?? 3000;
  await app.listen(port);
}

bootstrap();

Custom Error Handling

import { BaseApplicationError, ErrorCategorizerService } from '@pawells/nestjs-shared';

export class InsufficientFundsError extends BaseApplicationError {
  constructor(required: number, available: number) {
    super(`Insufficient funds: need ${required}, have ${available}`, {
      code: 'INSUFFICIENT_FUNDS',
      statusCode: 402,
      context: { required, available }
    });
  }
}

// In service
@Catch(InsufficientFundsError)
export class PaymentService {
  constructor(private errorCategorizer: ErrorCategorizerService) {}

  async processPayment(amount: number) {
    if (amount > balance) {
      const error = new InsufficientFundsError(amount, balance);
      // Automatically caught by GlobalExceptionFilter
      // Categorized by ErrorCategorizerService (permanent/fail)
      // Sanitized by ErrorSanitizerService
      throw error;
    }
  }
}

Related Packages

License

MIT