@struktos/adapter-nestjs
v0.1.0
Published
NestJS adapter for Struktos.js - Enterprise-grade context propagation, authentication, and logging for NestJS applications
Maintainers
Readme
@struktos/adapter-nestjs
NestJS adapter for Struktos.js - Enterprise-grade context propagation, authentication, and logging for NestJS applications
🎯 What is this?
@struktos/adapter-nestjs brings the power of Struktos.js to NestJS applications, providing seamless integration with NestJS's dependency injection, decorators, and module system.
Key Features:
- ✅ Context Propagation - Automatic context propagation via
StruktosCoreModule - ✅ Custom Decorators -
@Ctx(),@TraceId(),@CurrentUser()for easy context access - ✅ Auth Guards -
StruktosAuthGuardintegrates with@struktos/auth - ✅ Role-Based Auth -
@Roles()decorator for role-based authorization - ✅ Claims-Based Auth -
@RequireClaim()for fine-grained permissions - ✅ Interceptors - Request logging and response enrichment
- ✅ Full TypeScript - Complete type safety with NestJS
📦 Installation
npm install @struktos/adapter-nestjs @struktos/core @nestjs/common @nestjs/core reflect-metadata
# Optional - for authentication
npm install @struktos/auth
# Optional - for structured logging
npm install @struktos/logger🚀 Quick Start
1. Import Module
import { Module } from '@nestjs/common';
import { StruktosCoreModule } from '@struktos/adapter-nestjs';
@Module({
imports: [
StruktosCoreModule.forRoot({
generateTraceId: () => `trace-${Date.now()}`,
enableCancellation: true,
}),
],
})
export class AppModule {}2. Use Context in Controllers
import { Controller, Get, UseGuards } from '@nestjs/common';
import {
Ctx,
TraceId,
CurrentUser,
Roles,
StruktosAuthGuard
} from '@struktos/adapter-nestjs';
@Controller('users')
export class UsersController {
@Get()
findAll(@TraceId() traceId: string) {
console.log(`TraceID: ${traceId}`);
return this.usersService.findAll();
}
@Get('profile')
@UseGuards(StruktosAuthGuard)
getProfile(@CurrentUser() user: User) {
return user;
}
@Get('admin')
@UseGuards(StruktosAuthGuard)
@Roles('Admin')
adminOnly() {
return { message: 'Admin content' };
}
}📖 API Reference
Modules
StruktosCoreModule
Main module that provides context propagation and all Struktos features.
// Synchronous configuration
StruktosCoreModule.forRoot({
generateTraceId: () => uuid.v4(),
enableCancellation: true,
extractUser: (req) => req.user,
onContextCreated: (ctx, req) => console.log('Context created'),
onContextDestroyed: (ctx, req) => console.log('Context destroyed'),
isGlobal: true, // default
});
// Async configuration
StruktosCoreModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
generateTraceId: () => config.get('TRACE_PREFIX') + uuid.v4(),
}),
inject: [ConfigService],
});StruktosAuthModule
Authentication-only module for when you don't need full context propagation.
StruktosAuthModule.forRoot({
authService: myAuthService,
useGlobalGuard: true,
});StruktosLoggingModule
Logging-only module with interceptors.
StruktosLoggingModule.forRoot({
logger: myLogger,
useGlobalInterceptor: true,
});Decorators
Context Decorators
// Get full context
@Get()
handler(@Ctx() ctx: RequestContext<NestJSContextData>) {
console.log(ctx.get('traceId'));
}
// Get specific context value
@Get()
handler(@Ctx('userId') userId: string) {
console.log(userId);
}
// Shorthand decorators
@Get()
handler(
@TraceId() traceId: string,
@UserId() userId: string,
@CurrentUser() user: User,
@CurrentUser('email') email: string,
@RequestTimestamp() timestamp: number,
@IsCancelled() isCancelled: () => boolean,
) {}Auth Decorators
// Role-based authorization
@Roles('Admin')
@Roles('Admin', 'Moderator') // OR logic
// Claims-based authorization
@RequireClaim('permission', 'write:documents')
@RequireClaim('feature', 'beta-access')
// Multiple claims (AND logic)
@RequireClaims([
{ type: 'permission', value: 'read' },
{ type: 'department', value: 'engineering' }
])
// Mark route as public
@Public()
// Combined decorator
@Auth({
roles: ['Admin'],
claim: { type: 'permission', value: 'admin:write' }
})
// Shorthand
@AdminOnly()
@ModeratorOrAdmin()Guards
// Unified auth + authorization guard
@UseGuards(StruktosAuthGuard)
@Roles('Admin')
handler() {}
// Role-only guard (assumes user already authenticated)
@UseGuards(StruktosRolesGuard)
@Roles('Admin')
handler() {}
// Claims-only guard
@UseGuards(StruktosClaimsGuard)
@RequireClaim('permission', 'write')
handler() {}Interceptors
// Add trace ID and timing to responses
@UseInterceptors(StruktosContextInterceptor)
// Request/response logging
@UseInterceptors(StruktosLoggingInterceptor)
// Simple timing header only
@UseInterceptors(StruktosTimingInterceptor)
// Global registration
@Module({
providers: [
{
provide: APP_INTERCEPTOR,
useClass: StruktosContextInterceptor,
},
],
})🔐 Authentication Integration
With @struktos/auth
import { AuthService, InMemoryAuthStore } from '@struktos/auth';
import {
StruktosCoreModule,
StruktosAuthModule,
AUTH_SERVICE
} from '@struktos/adapter-nestjs';
const authStore = new InMemoryAuthStore();
const authService = new AuthService(authStore, {
jwtSecret: 'your-secret',
});
@Module({
imports: [
StruktosCoreModule.forRoot(),
StruktosAuthModule.forRoot({
authService,
useGlobalGuard: true, // Apply to all routes
}),
],
})
export class AppModule {}Public Routes with Global Guard
@Controller('auth')
export class AuthController {
@Public() // Bypasses global auth guard
@Post('login')
login() {}
@Public()
@Post('register')
register() {}
}📊 Context Access Anywhere
Context is automatically available in services, repositories, and any async operation:
import { Injectable } from '@nestjs/common';
import { RequestContext } from '@struktos/core';
import { NestJSContextData } from '@struktos/adapter-nestjs';
@Injectable()
export class UsersService {
async findAll() {
const ctx = RequestContext.current<NestJSContextData>();
const traceId = ctx?.get('traceId');
const userId = ctx?.get('userId');
console.log(`[${traceId}] User ${userId} fetching all users`);
return this.userRepository.find();
}
}🧪 Testing
import { Test } from '@nestjs/testing';
import { StruktosCoreModule, AUTH_SERVICE } from '@struktos/adapter-nestjs';
describe('UsersController', () => {
let controller: UsersController;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [StruktosCoreModule.forRoot()],
controllers: [UsersController],
providers: [
UsersService,
{
provide: AUTH_SERVICE,
useValue: {
validateToken: jest.fn().mockResolvedValue({
id: 'test-user',
username: 'test',
roles: ['Admin'],
}),
},
},
],
}).compile();
controller = module.get<UsersController>(UsersController);
});
it('should return users', async () => {
const result = await controller.findAll();
expect(result).toBeDefined();
});
});🏗️ Architecture
HTTP Request
↓
[StruktosMiddleware] - Initialize RequestContext
↓
[StruktosAuthGuard] - Authenticate & Authorize
↓
[StruktosContextInterceptor] - Pre-processing
↓
[Controller] - @Ctx(), @TraceId(), @CurrentUser()
↓
[Service] - RequestContext.current()
↓
[Repository] - RequestContext.current()
↓
[Response] - X-Trace-Id, X-Response-Time headers🤝 Related Packages
- @struktos/core - Core context propagation
- @struktos/auth - Authentication & authorization
- @struktos/logger - Structured logging
- @struktos/adapter-express - Express adapter
- @struktos/adapter-fastify - Fastify adapter
📄 License
MIT © Struktos.js Team
🔗 Links
Built with ❤️ for enterprise NestJS development
