@edsis/nest
v11.7.0
Published
NestJS Core Library with utilities and validators
Downloads
130
Maintainers
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/nestPeer 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
/interfaceswhen needed - Use
/commonfor 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 context2. 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>" → "<script>alert('xss')</script>"
}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: trueCustom 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=falseCustom 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_POOLprovider 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 timeLoggingInterceptor - 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/nest2. 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_OPEN8. 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
- @edsis/generator - CRUD code generator
- @edsis/access - Advanced RBAC system
Status: Production Ready - Enterprise-grade utilities for NestJS ✅
