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

@edsis/nest

v11.7.0

Published

NestJS Core Library with utilities and validators

Downloads

130

Readme

@edsis/nest

Enterprise-grade NestJS utilities library with Plain SQL support (no ORM)

Version: 11.3.0
Status: Production Ready
Architecture: Plain SQL with native drivers (pg/mysql2)

🆕 What's New in v11.3.0

DatabaseModule Feature (December 1, 2025)

  • DatabaseModule - Global module for database connection pooling
  • DATABASE_POOL Provider - Automatic injection for repositories
  • DatabaseHealthIndicator - Built-in health checks
  • PostgreSQL & MySQL Support - Native drivers (pg/mysql2)
  • Environment Configuration - Auto-reads from DB_* environment variables
  • Async Configuration - Factory pattern with dependency injection

Previous Features (v11.0.0)

New Security Features (November 29, 2025)

  • Database Unique Validator - Real database uniqueness validation with PostgreSQL/MySQL support
  • CSRF Protection Guard - Token-based CSRF protection with timing attack prevention
  • Performance Monitoring Interceptor - APM-ready metrics collection with auto-cleanup
  • Security Enhancements - OWASP-compliant guards and validators
  • Full Test Coverage - 13/13 tests passing for new features

Previous Features (v10.2.0)

  • ✅ Rate Limiting with Redis
  • ✅ Health Checks for Kubernetes
  • ✅ Circuit Breaker pattern
  • ✅ Audit Module with Plain SQL

✨ Features

| Feature Category | Status | Description | Import From | | ---------------------------------- | ------ | ------------------------------------------ | ------------------------ | | Authentication & Authorization | ✅ | JWT guards, RBAC decorators, @Auth() | @edsis/nest/decorators | | Database Module 🆕 | ✅ | Connection pooling, DATABASE_POOL provider | @edsis/nest/database | | Database Health Check 🆕 | ✅ | DatabaseHealthIndicator, ping checks | @edsis/nest/database | | CSRF Protection | ✅ | CsrfGuard, @SkipCsrf, token validation | @edsis/nest/guards | | Database Validation | ✅ | @IsUnique validator, PostgreSQL/MySQL | @edsis/nest/validators | | Performance Monitoring | ✅ | PerformanceInterceptor, APM integration | @edsis/nest/interceptors | | Rate Limiting | ✅ | RateLimitGuard, @RateLimit, Redis storage | @edsis/nest/guards | | Health Checks | ✅ | K8s probes, DB/Cache monitoring | @edsis/nest/health | | Circuit Breaker | ✅ | Resilience pattern, @UseCircuitBreaker | @edsis/nest/utils | | Data Validation | ✅ | DTOs, Pipes, Custom Validators | @edsis/nest/validators | | API Response | ✅ | Standardized response format | @edsis/nest/common | | Audit Trail | ✅ | @AuditLog, AuditModule, AuditLogService | @edsis/nest/audit | | Logging | ✅ | LoggingInterceptor | @edsis/nest/interceptors | | Caching | ✅ | @InvalidateCache, Cache Interceptor | @edsis/nest/decorators | | Error Handling | ✅ | AllExceptionsFilter, HttpExceptionFilter | @edsis/nest/filters | | String Utilities | ✅ | Case conversion, pluralization, validation | @edsis/nest/utils | | Guards | ✅ | JwtAuthGuard, RolesGuard, RateLimitGuard | @edsis/nest/guards | | Pipes | ✅ | ValidationPipe, SanitizePipe | @edsis/nest/pipes |

📦 Installation

npm install @edsis/nest

Peer Dependencies

npm install @nestjs/common@^11.0.0 @nestjs/core@^11.0.0 @nestjs/swagger@^8.0.0 class-validator@^0.14.0 class-transformer@^0.5.0

🚨 Import Patterns (v10.1.x Breaking Change)

Always use specific subpaths for tree-shaking optimization:

// ❌ WRONG - Don't import from root
import { Auth, AuditLogService, toPascalCase } from '@edsis/nest';

// ✅ CORRECT - Use specific subpaths
import { Auth, Public } from '@edsis/nest/decorators';
import { AuditLogService } from '@edsis/nest/audit';
import { toPascalCase } from '@edsis/nest/utils';

📊 Subpath Exports Guide

Each subpath contains related functionality for specific use cases:

Module/Service Setup (for app configuration)

| Subpath | Exports | Use Case | Example | | -------------------- | ---------------------------------------- | -------------------------------- | ----------------------------------------------------- | | @edsis/nest/auth | AuthModule, JwtStrategy | Setup JWT authentication | imports: [AuthModule.register({ secret: 'xxx' })] | | @edsis/nest/audit | AuditModule, AuditLogService, @AuditLog | Audit trail & compliance logging | await this.auditLog.log('user.create', userId, dto) | | @edsis/nest/cache | RedisCacheService, CacheModule | Redis caching layer | this.cache.set('key', value, ttl) | | @edsis/nest/health | HealthModule, HealthService | K8s health checks | imports: [HealthModule] | | @edsis/nest/search | SearchModule, SearchService, @Searchable | Full-text search | @Searchable(['title', 'description']) |

NestJS Building Blocks (for controllers/services)

| Subpath | Exports | Use Case | Example | | -------------------------- | ------------------------------------------------------------------------ | --------------------------- | ------------------------------------------------- | | @edsis/nest/decorators | @Auth, @Public, @CurrentUser, @InvalidateCache, @RateLimit | Route protection & metadata | @Auth('admin') or @Public() | | @edsis/nest/guards | JwtAuthGuard, RolesGuard, RateLimitGuard, CsrfGuard | Request validation | @UseGuards(JwtAuthGuard) | | @edsis/nest/interceptors | LoggingInterceptor, PerformanceInterceptor, CacheInvalidationInterceptor | Request/response processing | @UseInterceptors(LoggingInterceptor) | | @edsis/nest/filters | HttpExceptionFilter, AllExceptionsFilter | Error handling | app.useGlobalFilters(new HttpExceptionFilter()) | | @edsis/nest/pipes | ValidationPipe, SanitizePipe, ParseIntPipe | Data transformation | @Body(new ValidationPipe()) dto |

Utilities & Helpers (for business logic)

| Subpath | Exports | Use Case | Example | | ------------------------ | ------------------------------------------------------ | -------------------------------- | ------------------------------------------------ | | @edsis/nest/utils | toPascalCase, toCamelCase, toSnakeCase, CircuitBreaker | String manipulation & resilience | toPascalCase('user_profile')'UserProfile' | | @edsis/nest/validators | @IsUnique, @IsStrongPassword, SecurityValidator | Input validation | @IsUnique({ table: 'users', column: 'email' }) | | @edsis/nest/common | PaginationDto, ResponseDto, FilterDto | DTOs & response wrappers | ResponseDto.success(data, 'User created') | | @edsis/nest/interfaces | ApiResponse, PaginatedResult, JwtPayload | TypeScript types | const response: ApiResponse<User> = ... |

🎯 When to Use Each Subpath

Setup Phase (main.ts or module imports):

import { AuthModule } from '@edsis/nest/auth';
import { AuditModule } from '@edsis/nest/audit';
import { HealthModule } from '@edsis/nest/health';

@Module({
  imports: [
    AuthModule.register({ secret: process.env.JWT_SECRET }),
    AuditModule.forRoot({ database: 'postgres' }),
    HealthModule,
  ]
})

Controller Phase (route handlers):

import { Auth, Public, CurrentUser } from '@edsis/nest/decorators';
import { JwtAuthGuard, RolesGuard } from '@edsis/nest/guards';
import { LoggingInterceptor } from '@edsis/nest/interceptors';
import { PaginationDto, ResponseDto } from '@edsis/nest/common';

@Controller('users')
@UseInterceptors(LoggingInterceptor)
export class UsersController {
  @Auth('admin') // Only admin can access
  @Get()
  async findAll(@Query() pagination: PaginationDto) {
    const users = await this.service.findAll(pagination);
    return ResponseDto.paginated(users, meta, links);
  }

  @Public() // No authentication required
  @Post('register')
  async register(@Body() dto: CreateUserDto) {
    const user = await this.service.create(dto);
    return ResponseDto.created(user, 'User registered successfully');
  }

  @Auth() // Any authenticated user
  @Get('me')
  async getProfile(@CurrentUser() user: JwtPayload) {
    return ResponseDto.success(user, 'Profile retrieved');
  }
}

Service Phase (business logic):

import { AuditLogService } from '@edsis/nest/audit';
import { RedisCacheService } from '@edsis/nest/cache';
import { toPascalCase, toCamelCase } from '@edsis/nest/utils';
import { CircuitBreaker } from '@edsis/nest/utils';

@Injectable()
export class UsersService {
  private readonly circuitBreaker = new CircuitBreaker({
    threshold: 5,
    timeout: 60000,
  });

  constructor(
    private readonly auditLog: AuditLogService,
    private readonly cache: RedisCacheService,
  ) {}

  async create(dto: CreateUserDto, userId: number) {
    // Transform data
    const entityName = toPascalCase(dto.firstName);

    // Business logic
    const user = await this.repository.create(dto);

    // Audit trail
    await this.auditLog.log('user.create', userId, {
      action: 'CREATE',
      entity: 'User',
      entityId: user.id,
      newValue: user,
    });

    // Cache invalidation
    await this.cache.del(`users:${user.id}`);

    return user;
  }

  async externalApiCall() {
    return this.circuitBreaker.execute(() => this.httpService.get('https://api.example.com/data'));
  }
}

Validation Phase (DTOs):

import { IsUnique } from '@edsis/nest/validators';
import { PaginationDto } from '@edsis/nest/common';

export class CreateUserDto {
  @IsUnique({ table: 'users', column: 'email' })
  @IsEmail()
  email: string;

  @IsUnique({ table: 'users', column: 'username' })
  @MinLength(3)
  username: string;
}

export class GetUsersDto extends PaginationDto {
  @IsOptional()
  search?: string;
}

💡 Best Practices

✅ DO:

  • Use specific subpaths for smaller bundle size
  • Group imports by subpath for readability
  • Import types from /interfaces when needed
  • Use /common for shared DTOs across modules

❌ DON'T:

  • Import from root @edsis/nest (except for backward compatibility)
  • Mix subpath and root imports in same file
  • Import entire module when you only need one function

Example: Clean Import Organization

// Group 1: NestJS core
import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common';

// Group 2: @edsis/nest decorators
import { Auth, Public, CurrentUser } from '@edsis/nest/decorators';

// Group 3: @edsis/nest guards
import { JwtAuthGuard } from '@edsis/nest/guards';

// Group 4: @edsis/nest common (DTOs)
import { PaginationDto, ResponseDto } from '@edsis/nest/common';

// Group 5: @edsis/nest interfaces
import { JwtPayload } from '@edsis/nest/interfaces';

// Group 6: Local imports
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';

📈 Bundle Size Impact

| Import Method | Bundle Size | Tree-Shaking | Load Time | | --------------------------- | ---------------- | ------------ | --------- | | Root import (@edsis/nest) | ~150 KB | ❌ Difficult | Slower | | Subpath imports | ~50-80 KB | ✅ Optimal | Faster | | Improvement | -50% to -70% | +90% | -30% |

🎯 Features Documentation

1. Authentication & Authorization (JWT + RBAC)

Decorators

@Auth(...roles) - Simplified authentication with optional role-based access

import { Auth } from '@edsis/nest/decorators';

@Controller('users')
export class UserController {
  // Require authentication (any authenticated user)
  @Auth()
  @Get('profile')
  getProfile(@CurrentUser() user: UserContext) {
    return user;
  }

  // Require specific role (OR logic - user needs ONE of these roles)
  @Auth('admin', 'manager')
  @Delete(':id')
  deleteUser(@Param('id') id: string) {
    // Only admin OR manager can access
  }
}

@Public() - Mark routes as public (bypass authentication)

import { Auth, Public } from '@edsis/nest/decorators';

@Auth() // Controller-level auth
@Controller('posts')
export class PostsController {
  @Public() // This route is public
  @Get()
  findAll() {
    return this.postsService.findAll();
  }

  @Post() // This route requires auth
  create(@Body() dto: CreatePostDto) {
    return this.postsService.create(dto);
  }
}

@CurrentUser() - Extract authenticated user from request

import { CurrentUser, UserContext } from '@edsis/nest/decorators';

@Auth()
@Get('me')
getMe(@CurrentUser() user: UserContext) {
  // user contains: { id, email, roles, ... }
  return user;
}

Guards

JwtAuthGuard - Validates JWT tokens

import { JwtAuthGuard } from '@edsis/nest/guards';

@UseGuards(JwtAuthGuard)
@Get('protected')
protectedRoute() {
  return 'Protected data';
}

RolesGuard - Role-based access control (OR logic)

import { JwtAuthGuard, RolesGuard } from '@edsis/nest/guards';

@UseGuards(JwtAuthGuard, RolesGuard)
@SetMetadata('roles', ['admin', 'moderator'])
@Delete(':id')
deleteItem(@Param('id') id: string) {
  // User must have 'admin' OR 'moderator' role
}

JwtAuthStrategy - Passport JWT strategy

import { JwtAuthStrategy } from '@edsis/nest/auth';

// Automatically configured when using @Auth() decorator
// Validates JWT and loads user context

2. Data Validation (DTOs, Validators, Pipes)

DTOs

PaginationDto - Validated pagination parameters

import { PaginationDto } from '@edsis/nest/common';

@Get()
findAll(@Query() pagination: PaginationDto) {
  // pagination: { page: 1, limit: 10, offset: 0, skip: 0 }
  // Computed properties: offset, skip
  // Validation: page >= 1, limit 1-100
}

ResponseDto - Standardized API response format

import { ResponseDto } from '@edsis/nest/common';

@Get(':id')
async findOne(@Param('id') id: string): Promise<ResponseDto<User>> {
  const user = await this.service.findOne(id);
  return new ResponseDto(user, 'User retrieved successfully');
}

// Response format:
// {
//   "success": true,
//   "message": "User retrieved successfully",
//   "data": { ... },
//   "timestamp": "2025-11-28T12:00:00.000Z"
// }

FilterDto - Advanced filtering, sorting, field selection

import { FilterDto } from '@edsis/nest/common';

@Get()
findAll(@Query() filter: FilterDto) {
  // filter.search - Full-text search
  // filter.sort - Sort field (e.g., "name,-createdAt")
  // filter.fields - Field selection (e.g., "id,name,email")
}

Pipes

ParseIntPipe - Safe integer parsing with defaults

import { ParseIntPipe } from '@edsis/nest/pipes';

@Get(':id')
findOne(@Param('id', new ParseIntPipe()) id: number) {
  // Safely parses string to number with error handling
}

TrimPipe - Remove leading/trailing whitespace

import { TrimPipe } from '@edsis/nest/pipes';

@Post()
create(@Body('name', TrimPipe) name: string) {
  // " John Doe " → "John Doe"
}

SanitizePipe - XSS prevention (HTML entity encoding)

import { SanitizePipe } from '@edsis/nest/pipes';

@Post()
create(@Body('content', SanitizePipe) content: string) {
  // "<script>alert('xss')</script>" → "&lt;script&gt;alert('xss')&lt;/script&gt;"
}

Validators

SecurityValidator - SQL injection & XSS detection

import { SecurityValidator } from '@edsis/nest/validators';

const isSafe = SecurityValidator.isSafeString('SELECT * FROM users');
// Returns: false (SQL injection detected)

const isClean = SecurityValidator.isSafeString('John Doe');
// Returns: true

Custom Validators - class-validator decorators

import { IsSafeString, IsStrongPassword } from '@edsis/nest/validators';

export class CreateUserDto {
  @IsSafeString({ message: 'Username contains unsafe characters' })
  username: string;

  @IsStrongPassword({
    minLength: 8,
    requireUppercase: true,
    requireNumbers: true,
  })
  password: string;
}

3. API Response (Standardized Format)

Interfaces

ApiResponse - Generic API response structure

import { ApiResponse } from '@edsis/nest/common';

interface ApiResponse<T> {
  success: boolean;
  message: string;
  data?: T;
  error?: string;
  timestamp: string;
}

PaginatedResult - Paginated data structure

import { PaginatedResult } from '@edsis/nest/common';

interface PaginatedResult<T> {
  data: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
}

UserContext - Authenticated user data

import { UserContext } from '@edsis/nest/decorators';

interface UserContext {
  id: string | number;
  email: string;
  roles?: string[];
  [key: string]: any;
}

JwtPayload - JWT token payload structure

import { JwtPayload } from '@edsis/nest/auth';

interface JwtPayload {
  sub: string | number;
  email: string;
  roles?: string[];
  iat?: number;
  exp?: number;
}

4. Database Module (NEW in v11.3.0)

Global module that provides DATABASE_POOL for dependency injection. Supports PostgreSQL and MySQL with connection pooling and lifecycle management.

Simple Usage (Environment Variables)

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule } from '@edsis/nest/database';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    DatabaseModule.forRoot(), // ← Auto-reads from environment
    UsersModule,
  ],
})
export class AppModule {}

Environment Variables:

DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=mydb
DB_USERNAME=postgres
DB_PASSWORD=secret
DB_POOL_MAX=10
DB_POOL_MIN=2
DB_SSL=false

Custom Configuration

import { DatabaseModule } from '@edsis/nest/database';

@Module({
  imports: [
    DatabaseModule.forRoot({
      type: 'postgresql', // or 'mysql', 'mariadb'
      host: 'localhost',
      port: 5432,
      database: 'mydb',
      username: 'postgres',
      password: 'secret',
      pool: {
        min: 2,
        max: 10,
        idleTimeoutMillis: 30000,
        connectionTimeoutMillis: 2000,
      },
      ssl: false,
      logging: true,
    }),
  ],
})
export class AppModule {}

Async Configuration

import { DatabaseModule } from '@edsis/nest/database';
import { ConfigService } from '@nestjs/config';

@Module({
  imports: [
    DatabaseModule.forRootAsync({
      useFactory: (config: ConfigService) => ({
        type: 'postgresql' as const,
        host: config.get('DB_HOST'),
        port: config.get('DB_PORT'),
        database: config.get('DB_DATABASE'),
        username: config.get('DB_USERNAME'),
        password: config.get('DB_PASSWORD'),
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Using DATABASE_POOL in Repositories

import { Injectable, Inject } from '@nestjs/common';
import { Pool } from 'pg';

@Injectable()
export class UsersRepository {
  constructor(@Inject('DATABASE_POOL') private readonly pool: Pool) {}

  async findAll(): Promise<User[]> {
    const result = await this.pool.query('SELECT * FROM users');
    return result.rows;
  }

  async create(dto: CreateUserDto): Promise<User> {
    const query = `
      INSERT INTO users (name, email)
      VALUES ($1, $2)
      RETURNING *
    `;
    const result = await this.pool.query(query, [dto.name, dto.email]);
    return result.rows[0];
  }
}

Health Check Integration

import { Controller, Get } from '@nestjs/common';
import { DatabaseHealthIndicator } from '@edsis/nest/database';

@Controller('health')
export class HealthController {
  constructor(private db: DatabaseHealthIndicator) {}

  @Get('db')
  async checkDatabase() {
    return this.db.check(); // Returns: { status: 'up', responseTime: 5, type: 'postgresql' }
  }

  @Get('db/ping')
  async pingDatabase() {
    return this.db.ping(1000); // Timeout after 1000ms
  }
}

Key Benefits:

  • ✅ No manual DATABASE_POOL provider in every module
  • ✅ Consistent configuration across all modules
  • ✅ Works seamlessly with @edsis/generator generated repositories
  • ✅ Graceful shutdown on application close
  • ✅ Built-in health checks

5. Audit Trail

Complete audit logging system moved from @edsis/generator. Tracks all entity changes (CREATE, UPDATE, DELETE) with before/after snapshots.

AuditModule Setup

import { Module } from '@nestjs/common';
import { AuditModule } from '@edsis/nest/audit';

@Module({
  imports: [
    AuditModule.forRoot({
      tableName: 'audit_logs',
      database: 'postgresql', // or 'mysql'
      pool: databasePool, // pg.Pool or mysql2.Pool
    }),
  ],
})
export class AppModule {}

Using AuditLogService

import { Injectable } from '@nestjs/common';
import { AuditLogService } from '@edsis/nest/audit';

@Injectable()
export class UsersService {
  constructor(private readonly auditLog: AuditLogService) {}

  async create(dto: CreateUserDto, userId: string) {
    const user = await this.repository.create(dto);

    // Log the creation
    await this.auditLog.log('user.create', userId, {
      entityName: 'users',
      entityId: user.id,
      after: user,
    });

    return user;
  }

  async update(id: string, dto: UpdateUserDto, userId: string) {
    const before = await this.repository.findOne(id);
    const after = await this.repository.update(id, dto);

    // Log the update with before/after
    await this.auditLog.log('user.update', userId, {
      entityName: 'users',
      entityId: id,
      before,
      after,
    });

    return after;
  }
}

@AuditLog Decorator

@AuditLog(action) - Automatic audit trail logging

import { AuditLog } from '@edsis/nest/audit';
import { Auth } from '@edsis/nest/decorators';

@Controller('users')
export class UsersController {
  @Auth()
  @AuditLog('user.create')
  @Post()
  async create(@Body() dto: CreateUserDto, @CurrentUser() user: UserContext) {
    // Automatically logs: action, user, timestamp, request data
    return this.usersService.create(dto);
  }

  @Auth()
  @AuditLog('user.update')
  @Put(':id')
  async update(@Param('id') id: string, @Body() dto: UpdateUserDto) {
    // Audit log created with action, user, before/after data
    return this.usersService.update(id, dto);
  }

  @AuditLog('user.delete')
  @Delete(':id')
  async delete(@Param('id') id: string) {
    // Tracks deletion with audit trail
    return this.usersService.delete(id);
  }
}

AuditInterceptor - Global audit logging

import { AuditInterceptor } from '@edsis/nest';

// In main.ts or module
app.useGlobalInterceptors(new AuditInterceptor());

// Automatically logs all requests with:
// - HTTP method, URL, status code
// - Request/response payload
// - User information (if authenticated)
// - Execution time

LoggingInterceptor - Request/response logging

import { LoggingInterceptor } from '@edsis/nest';

@Controller('posts')
@UseInterceptors(LoggingInterceptor)
export class PostsController {
  @Get()
  findAll() {
    // Logs: Request received, response time, status
    return this.postsService.findAll();
  }
}

// Global usage in main.ts:
app.useGlobalInterceptors(new LoggingInterceptor());

5. Caching

@InvalidateCache(...keys) - Cache invalidation on mutations

import { InvalidateCache } from '@edsis/nest';

@Controller('products')
export class ProductsController {
  @Get()
  @CacheTTL(300) // Cache for 5 minutes
  async findAll() {
    return this.productsService.findAll();
  }

  @InvalidateCache('products') // Clear products cache
  @Post()
  async create(@Body() dto: CreateProductDto) {
    return this.productsService.create(dto);
  }

  @InvalidateCache('products', 'product:${id}') // Clear list + specific item
  @Put(':id')
  async update(@Param('id') id: string, @Body() dto: UpdateProductDto) {
    return this.productsService.update(id, dto);
  }

  @InvalidateCache('products') // Clear all products cache
  @Delete(':id')
  async delete(@Param('id') id: string) {
    return this.productsService.delete(id);
  }
}

CacheInvalidationInterceptor - Automatic cache invalidation

import { CacheInvalidationInterceptor } from '@edsis/nest';

// Global usage
app.useGlobalInterceptors(new CacheInvalidationInterceptor(cacheManager));

// Automatically invalidates cache based on @InvalidateCache decorators
// Supports pattern matching: 'user:*', 'products', etc.

6. Error Handling

AllExceptionsFilter - Global error handling

import { AllExceptionsFilter } from '@edsis/nest';

// In main.ts
app.useGlobalFilters(new AllExceptionsFilter());

// Handles ALL exceptions with standardized response:
// {
//   "success": false,
//   "error": "Error message",
//   "statusCode": 500,
//   "timestamp": "2025-11-28T12:00:00.000Z",
//   "path": "/api/users"
// }

HttpExceptionFilter - HTTP-specific error handling

import { HttpExceptionFilter } from '@edsis/nest';

// In main.ts
app.useGlobalFilters(new HttpExceptionFilter());

// Handles HttpException with detailed response:
// - Validation errors (400)
// - Unauthorized (401)
// - Forbidden (403)
// - Not Found (404)
// - Internal Server Error (500)

// Example response for validation error:
// {
//   "success": false,
//   "message": "Validation failed",
//   "errors": [
//     { "field": "email", "message": "Email is required" }
//   ],
//   "statusCode": 400,
//   "timestamp": "2025-11-28T12:00:00.000Z"
// }

7. String Utilities

Case Conversion

import { toPascalCase, toCamelCase, toSnakeCase, toKebabCase } from '@edsis/nest';

// PascalCase (class names)
toPascalCase('user_profile'); // 'UserProfile'
toPascalCase('user-profile'); // 'UserProfile'

// camelCase (variable names)
toCamelCase('user_profile'); // 'userProfile'
toCamelCase('user-profile'); // 'userProfile'

// snake_case (database columns)
toSnakeCase('UserProfile'); // 'user_profile'
toSnakeCase('userProfile'); // 'user_profile'

// kebab-case (URLs)
toKebabCase('UserProfile'); // 'user-profile'
toKebabCase('userProfile'); // 'user-profile'

Pluralization

import { pluralize, singularize } from '@edsis/nest';

// Pluralize
pluralize('user'); // 'users'
pluralize('person'); // 'people'
pluralize('child'); // 'children'
pluralize('category'); // 'categories'

// Singularize
singularize('users'); // 'user'
singularize('people'); // 'person'
singularize('children'); // 'child'
singularize('categories'); // 'category'

Validation

import { isUUID, isValidIdentifier } from '@edsis/nest';

// UUID validation
isUUID('123e4567-e89b-12d3-a456-426614174000'); // true
isUUID('invalid-uuid'); // false

// Valid identifier (variable/class names)
isValidIdentifier('myVariable'); // true
isValidIdentifier('MyClass'); // true
isValidIdentifier('123invalid'); // false (starts with number)
isValidIdentifier('my-variable'); // false (contains hyphen)

Path Utilities

import { ensureTrailingSlash, removeTrailingSlash } from '@edsis/nest';

// Ensure trailing slash
ensureTrailingSlash('/api/users'); // '/api/users/'
ensureTrailingSlash('/api/users/'); // '/api/users/'

// Remove trailing slash
removeTrailingSlash('/api/users/'); // '/api/users'
removeTrailingSlash('/api/users'); // '/api/users'

Other Utilities

import { calculateChecksum, escapeRegex, deepClone, sleep } from '@edsis/nest';

// SHA-256 checksum
const hash = calculateChecksum('hello world');
// 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'

// Escape regex special characters
escapeRegex('hello.world?'); // 'hello\\.world\\?'

// Deep clone objects
const original = { user: { name: 'John', roles: ['admin'] } };
const cloned = deepClone(original);

// Sleep/delay
await sleep(1000); // Wait 1 second

📚 Complete API

Exports

// DTOs
export { PaginationDto, ResponseDto, FilterDto } from '@edsis/nest';

// Interfaces
export { ApiResponse, PaginatedResult, UserContext, JwtPayload } from '@edsis/nest';

// Decorators
export { Auth, Public, CurrentUser, AuditLog, InvalidateCache } from '@edsis/nest';

// Guards
export { JwtAuthGuard, RolesGuard, JwtAuthStrategy } from '@edsis/nest';

// Pipes
export { ParseIntPipe, TrimPipe, SanitizePipe } from '@edsis/nest';

// Validators
export { SecurityValidator, IsSafeString, IsStrongPassword } from '@edsis/nest';

// Interceptors
export { AuditInterceptor, CacheInvalidationInterceptor, LoggingInterceptor } from '@edsis/nest';

// Filters
export { AllExceptionsFilter, HttpExceptionFilter } from '@edsis/nest';

// String Utilities
export {
  toPascalCase,
  toCamelCase,
  toSnakeCase,
  toKebabCase,
  pluralize,
  singularize,
  isUUID,
  isValidIdentifier,
  ensureTrailingSlash,
  removeTrailingSlash,
  calculateChecksum,
  escapeRegex,
  deepClone,
  sleep,
} from '@edsis/nest';

// Guards
export { JwtAuthGuard, RolesGuard, JwtAuthStrategy } from '@edsis/nest';

// Pipes
export { ParseIntPipe, TrimPipe, SanitizePipe } from '@edsis/nest';

// Validators
export { SecurityValidator, IsSafeString, IsStrongPassword } from '@edsis/nest';

🚀 Quick Start

1. Install package

npm install @edsis/nest

2. Basic authentication setup

import { Auth, CurrentUser, UserContext } from '@edsis/nest';

@Controller('users')
export class UsersController {
  @Auth()
  @Get('profile')
  getProfile(@CurrentUser() user: UserContext) {
    return user;
  }

  @Auth('admin')
  @Delete(':id')
  deleteUser(@Param('id') id: string) {
    return this.usersService.delete(id);
  }
}

3. Use DTOs for validation

import { PaginationDto, ResponseDto } from '@edsis/nest';

@Get()
async findAll(@Query() pagination: PaginationDto): Promise<ResponseDto<User[]>> {
  const users = await this.service.findAll(pagination);
  return new ResponseDto(users, 'Users retrieved successfully');
}

4. Setup global error handling and logging

import { AllExceptionsFilter, LoggingInterceptor } from '@edsis/nest';

// In main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Global error handling
  app.useGlobalFilters(new AllExceptionsFilter());

  // Global logging
  app.useGlobalInterceptors(new LoggingInterceptor());

  await app.listen(3000);
}
bootstrap();

5. Rate Limiting (Prevent abuse)

import { RateLimitGuard, RateLimit } from '@edsis/nest/guards';
import { MemoryRateLimitStorage, RedisRateLimitStorage } from '@edsis/nest/cache';

// In main.ts (global rate limiting)
const app = await NestFactory.create(AppModule);
const reflector = app.get(Reflector);
const storage = app.get('RATE_LIMIT_STORAGE'); // or new MemoryRateLimitStorage()

app.useGlobalGuards(
  new RateLimitGuard(reflector, storage, {
    limit: 100, // 100 requests per minute
    window: 60000,
  }),
);

// In controller (custom limits per endpoint)
@Controller('auth')
export class AuthController {
  // Strict limit for login attempts
  @Post('login')
  @RateLimit(5) // 5 attempts per minute
  async login(@Body() dto: LoginDto) {
    return this.authService.login(dto);
  }

  // Public endpoint without rate limit
  @Get('health')
  @SkipRateLimit()
  health() {
    return { status: 'ok' };
  }
}

// Setup storage provider
@Module({
  providers: [
    {
      provide: 'RATE_LIMIT_STORAGE',
      useClass: RedisRateLimitStorage, // or MemoryRateLimitStorage
    },
  ],
})
export class AppModule {}

6. Health Checks (Kubernetes ready)

import { HealthModule } from '@edsis/nest/health';

// Basic usage
@Module({
  imports: [HealthModule],
})
export class AppModule {}

// Endpoints available:
// GET /health - Full health check
// GET /health/live - Liveness probe
// GET /health/ready - Readiness probe

// Kubernetes deployment.yaml
/*
livenessProbe:
  httpGet:
    path: /health/live
    port: 3000
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /health/ready
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 5
*/

7. Circuit Breaker (Resilience)

import { CircuitBreaker, UseCircuitBreaker } from '@edsis/nest/utils';

// Method decorator
class UserService {
  @UseCircuitBreaker({
    timeout: 3000,
    errorThresholdPercentage: 50,
    resetTimeout: 30000,
    fallback: () => ({ id: 'unknown', name: 'Guest' }),
  })
  async fetchUserFromExternalAPI(id: string): Promise<User> {
    // This call is protected by circuit breaker
    return await this.httpService.get(`/users/${id}`);
  }
}

// Manual usage
const breaker = new CircuitBreaker<User>(
  async (userId: string) => {
    return await this.userService.findOne(userId);
  },
  {
    timeout: 3000,
    errorThresholdPercentage: 50,
    fallback: () => null,
  },
);

const user = await breaker.execute('user-123');

// Check circuit state
const stats = breaker.getStats();
console.log(stats.state); // CLOSED, OPEN, or HALF_OPEN

8. Audit logging for sensitive operations

import { AuditLog } from '@edsis/nest/audit';
import { Auth } from '@edsis/nest/decorators';

@Controller('admin')
export class AdminController {
  @AuditLog('admin.user.delete')
  @Auth('admin')
  @Delete('users/:id')
  async deleteUser(@Param('id') id: string) {
    // Automatically tracked in audit log
    return this.adminService.deleteUser(id);
  }
}

9. String utilities for naming conventions

import { toPascalCase, toSnakeCase, pluralize } from '@edsis/nest/utils';

// Generate class names
const className = toPascalCase('user_profile'); // 'UserProfile'

// Generate database column names
const columnName = toSnakeCase('createdAt'); // 'created_at'

// Generate plural forms
const tableName = pluralize('user'); // 'users'

🔄 Roadmap

  • Phase 1: Authentication, Validation, API Response
  • Phase 2: Logging & Auditing, Caching, Error Handling
  • Phase 3A: String Utilities (Case conversion, Pluralization, Validation)
  • Phase 3B: Rate Limiting, Health Checks, Circuit Breaker
  • Phase 4: Advanced Security Features (Coming soon)

📄 License

MIT

🔗 Related Packages


Status: Production Ready - Enterprise-grade utilities for NestJS ✅