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

v3.0.5

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 Pipes

Global filters and pipes are automatically registered by CommonModule:

  • GlobalExceptionFilter & HttpExceptionFilter: Standardized error responses
  • ValidationPipe: Automatic DTO validation

All are applied globally. For HTTP metrics collection, also import MetricsModule.ForRoot().

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

Structured logging with OpenTelemetry trace context injection, backed by @pawells/logger.

NestJSLogger (DI pattern — for services, controllers, guards)

Use constructor injection for any component registered in the NestJS DI container:

import { Injectable } from '@nestjs/common';
import { NestJSLogger } from '@pawells/nestjs-shared';

@Injectable()
export class UserService {
	private readonly Logger: NestJSLogger;

	constructor(logger: NestJSLogger) {
		this.Logger = logger;
	}

	public CreateUser(): void {
		this.Logger.log('User created', 'UserService');
		this.Logger.error('Database error', error.stack, 'UserService');
		this.Logger.warn('Rate limit approaching', 'UserService');
		this.Logger.debug('Cache hit', 'UserService');
	}
}

Static Logger pattern (for utility classes and standalone functions)

Use @pawells/logger directly for classes that are not part of the DI container:

import { Logger } from '@pawells/logger';

export class UtilityClass {
	private static readonly Logger = new Logger('UtilityClass');

	public static DoSomething(): void {
		UtilityClass.Logger.info('Doing something');
		UtilityClass.Logger.error('Error', { context: 'processing' });
	}
}

Bootstrap setup

Configure NestJS to use NestJSLogger as the application logger in main.ts:

import { NestFactory } from '@nestjs/core';
import { NestJSLogger } from '@pawells/nestjs-shared';

async function bootstrap() {
	const app = await NestFactory.create(AppModule, {
		bufferLogs: true,
	});

	app.useLogger(new NestJSLogger());

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

bootstrap();

Logging methods

All methods accept message + optional context (last parameter):

  • logger.log(message, context?) — Info level
  • logger.debug(message, context?) — Debug level
  • logger.warn(message, context?) — Warning level
  • logger.error(message, stack?, context?) — Error level (special stack param)
  • logger.verbose(message, context?) — Verbose level (mapped to debug)
  • logger.fatal(message, context?) — Fatal level

See AGENTS.md for the complete logging pattern reference including LogManager coordination.

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

Metrics

Metrics collection via InstrumentationRegistry. HTTP metrics and the @Instrument() decorator require MetricsModule.ForRoot() — they are not part of CommonModule.

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

@Module({
	imports: [
		CommonModule,
		MetricsModule.ForRoot(),  // Required for HTTP metrics and @Instrument() support
	],
})
export class AppModule {}

InstrumentationRegistry is the central registry for metric collection and export. It is provided by MetricsModule and injectable once that module is imported:

import { Injectable } from '@nestjs/common';
import { InstrumentationRegistry } from '@pawells/nestjs-shared';

@Injectable()
export class OrderService {
	private readonly Registry: InstrumentationRegistry;

	constructor(registry: InstrumentationRegistry) {
		this.Registry = registry;
	}

	public Initialize(): void {
		this.Registry.RegisterDescriptor({
			name: 'orders_total',
			type: 'counter',
			help: 'Total orders processed',
			labelNames: ['status'],
		});
	}

	public RecordOrder(status: string): void {
		this.Registry.RecordMetric('orders_total', 1, { status });
	}
}

Features:

  • Automatic HTTP request metrics (duration histogram, request counter, size histogram) via HTTPMetricsInterceptor in MetricsModule
  • Dynamic path normalization (UUIDs, ObjectIDs, numeric IDs → :id) to prevent unbounded cardinality
  • @Instrument() decorator for automatic method timing, counters, and error tracking
  • Event-based and pull-based exporter support
  • Prometheus export via @pawells/nestjs-prometheus

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 },
});

Lazy Loading

Defer dependency resolution to avoid circular dependencies.

Factory functions follow PascalCase naming per project conventions.

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

@Injectable()
export class MyService implements ILazyModuleRefService {
  private readonly UserServiceGetter: TLazyGetter<UserService>;

  public readonly Module: ModuleRef;

  constructor(module: ModuleRef) {
    this.Module = module;
    this.UserServiceGetter = CreateMemoizedLazyGetter(
      () => this.Module.get(UserService, { strict: false }),
    );
  }

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

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
  • ILazyModuleRefService: Interface requiring a public Module: ModuleRef property

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 foundational infrastructure. Does NOT include metrics — import MetricsModule.ForRoot() separately for HTTP metrics and @Instrument() decorator support.

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

    // Pipe (global)
    ValidationPipe,

    // Services (injectable)
    NestJSLogger,
    CSRFService,
    CSRFGuard,
    ErrorCategorizerService,
    ErrorSanitizerService,
    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 enables HTTP metrics collection and the @Instrument() decorator. Import it explicitly in any application that needs metrics.

@Module({
  imports: [
    CommonModule,
    MetricsModule.ForRoot(),   // Opt-in: HTTP metrics + @Instrument() support
  ],
})
export class AppModule {}
// Provides:
// - InstrumentationRegistry (injectable)
// - HTTPMetricsInterceptor (registered as global APP_INTERCEPTOR)
// - @Instrument() decorator support

API Reference

Services

NestJSLogger

NestJS-compatible logger that extends ConsoleLogger and feeds entries into @pawells/logger LogManager. Provided by CommonModule and injectable via constructor injection.

Methods:

  • log(message, context?): Info level
  • debug(message, context?): Debug level
  • warn(message, context?): Warning level
  • error(message, stack?, context?): Error level with optional stack trace
  • verbose(message, context?): Verbose level (mapped to debug)
  • fatal(message, context?): Fatal level
  • CreateContextualLogger(context): Create a new NestJSLogger instance bound to a specific context string

Pass new NestJSLogger() to app.useLogger() in main.ts to route all NestJS framework logs through @pawells/logger. See the Logging section above for the full bootstrap and DI patterns.

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

InstrumentationRegistry

Central registry for metrics collection and export. Provided by MetricsModule — requires MetricsModule.ForRoot() to be imported.

Methods:

  • RegisterDescriptor(descriptor): Register a metric descriptor (name, type, help, labelNames, buckets, unit); idempotent on exact match, throws on conflict
  • RecordMetric(name, value, labels?): Record a numeric value for a registered metric; emits to all exporters and named listeners
  • GetAllMetrics(): Return a copy of all recorded metric values as a Map<string, IMetricValue[]>
  • GetMetric(name): Return recorded values for a single metric by name
  • On(metricName, handler): Subscribe to a metric by name; returns an unsubscribe function
  • RegisterExporter(exporter): Register a metrics exporter (e.g., Prometheus, OpenTelemetry)
  • Shutdown(): Flush and shut down all registered exporters

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

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 { NestJSLogger, 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 utilities
import { AppLoggerMock, SharedTestingModule } from '@pawells/nestjs-shared/testing';

AppLoggerMock is a no-op logger available from the /testing subpath. It provides silent implementations of all NestJSLogger-compatible methods and can be used as a provider substitute in unit tests. For full spy behaviour, wrap individual methods with vi.fn() after obtaining the instance, or use vi.mock() to mock NestJSLogger directly.

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

  • 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