NestJS
Import from @system-core/core/integrations/nestjs.
Use this integration when the host application is NestJS and you want to bridge Nest execution context to the system-core HTTP adapter model. The adapter has zero @nestjs/* imports — it relies on structural typing, so the package installs without requiring NestJS in the dependency tree.
Use Cases
- NestJS controllers calling package-owned auth or CMS flows
- Guards that validate Bearer tokens through the system-core auth system
- A single
SystemCoreModule.forRoot()that registers the runtime as injectable providers - Exception filters that map system-core errors to NestJS HTTP responses
How It Works
system-core's HttpAdapter interface uses event: unknown as the universal integration point. Every framework adapter implements this same interface against its own request/response pair.
The NestJS adapter wraps NestJS's ExecutionContext into a { request, response } object that satisfies the HttpAdapter contract. All package-owned logic functions — auth middleware, rate limiting, CMS helpers — work unchanged through it.
ExecutionContext → getNestjsEvent(ctx) → NestjsHttpContext → nestjsAdapter → HttpAdapterBasic Setup
1 — Install
npm install @system-core/core zod @prisma/client
npm install bcryptjs jsonwebtoken nodemailer2 — Register the runtime module
// app.module.ts
import { Module } from '@nestjs/common'
import { SystemCoreModule } from '@system-core/core/integrations/nestjs'
import { nestjsAdapter } from '@system-core/core/integrations/nestjs'
import { createSystem } from '@system-core/core'
import { prismaClient } from './prisma'
const system = await createSystem({ prisma: prismaClient })
@Module({
imports: [
SystemCoreModule.forRoot({
http: nestjsAdapter,
auth: system.auth,
cms: system.cms
})
]
})
export class AppModule {}The module is global: true — inject via SYSTEM_CORE_TOKEN anywhere:
import { Inject, Injectable } from '@nestjs/common'
import { SYSTEM_CORE_TOKEN } from '@system-core/core/integrations/nestjs'
import type { SystemCoreProviders } from '@system-core/core/integrations/nestjs'
@Injectable()
export class PagesService {
constructor(
@Inject(SYSTEM_CORE_TOKEN) private readonly core: SystemCoreProviders
) {}
listPublished() {
return (this.core.cms as ReturnType<typeof system.cms>).listPublishedPages()
}
}Guards
Auth Guard
import { UseGuards, Controller, Get } from '@nestjs/common'
import { createAuthGuard } from '@system-core/core/integrations/nestjs'
const AuthGuard = createAuthGuard(system.auth)
@Controller('me')
@UseGuards(AuthGuard)
export class MeController {
@Get()
getMe() { return 'authorized' }
}createAuthGuard reads the Authorization: Bearer <token> header, verifies it through auth.sessions.verifyToken, and attaches the session to request.user. Throws 401 if the token is missing or invalid.
Permission Guard
Chain a permission guard after the auth guard:
import { createPermissionGuard } from '@system-core/core/integrations/nestjs'
const CanPublishGuard = createPermissionGuard(
'cms:publish',
(userId, permission) =>
system.auth.authorization.hasEffectivePermission(userId, permission)
)
@UseGuards(AuthGuard, CanPublishGuard)
@Post('pages/:id/publish')
async publishPage(@Param('id') id: string) { ... }Using the Adapter Directly in Controllers
When you need raw access to request data inside a handler:
import { Controller, Get, ExecutionContext } from '@nestjs/common'
import { getNestjsEvent, nestjsAdapter } from '@system-core/core/integrations/nestjs'
@Controller('echo')
export class EchoController {
@Get()
async echo(@ExecutionCtx() ctx: ExecutionContext) {
const event = getNestjsEvent(ctx)
const method = nestjsAdapter.getMethod(event)
const url = nestjsAdapter.getRequestURL(event)
return { method, url: url.pathname }
}
}Exception Filter
Map system-core errors to NestJS HTTP responses:
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common'
import { isSystemCoreError } from '@system-core/core/integrations/nestjs'
@Catch()
export class SystemCoreExceptionFilter implements ExceptionFilter {
catch(error: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp()
const response = ctx.getResponse()
if (isSystemCoreError(error)) {
response.status(error.statusCode).json({ message: error.message })
} else {
response.status(500).json({ message: 'Internal server error' })
}
}
}Register globally in main.ts:
app.useGlobalFilters(new SystemCoreExceptionFilter())Platform Compatibility
The adapter detects the underlying platform from the response shape and works with both:
| Platform | Cookie API used |
|---|---|
| Express (default) | res.cookie() / res.clearCookie() |
| Fastify | res.setCookie() / @fastify/cookie |
| Either (fallback) | Raw Set-Cookie header |
No configuration needed — the adapter checks which methods are present at runtime.
What Stays Unchanged
All other framework adapters — Nuxt/H3 (integrations/nuxt) and Express/Fastify (integrations/express) — are not affected. This adapter is purely additive.
API Reference
| Export | Kind | Description |
|---|---|---|
nestjsAdapter / httpAdapter | HttpAdapter | The core adapter instance |
getNestjsEvent(ctx) | function | Convert ExecutionContext → NestjsHttpContext |
createAuthGuard(auth) | function | Factory returning a Bearer token Guard class |
createPermissionGuard(perm, fn) | function | Factory returning a permission Guard class |
SystemCoreModule | object | Dynamic module with .forRoot(config) |
SYSTEM_CORE_TOKEN | const | DI injection token string |
isSystemCoreError(err) | function | Type guard for exception filters |
NestjsHttpContext | type | { request, response } shape |
SystemCoreProviders | type | Providers registered by forRoot |