import { Injectable, UnauthorizedException } from '@nestjs/common'; import { AsyncLocalStorage } from 'async_hooks'; import { RequestContext } from './request-context.type'; @Injectable() /** * RequestContext holds per-request metadata including: * - HTTP request * - Auth payload (decoded JWT, optional) * - Prisma transaction client (optional) * - Correlation ID and other future cross-cutting concerns */ export class RequestContextService { private readonly als = new AsyncLocalStorage(); run(context: RequestContext, fn: () => void) { this.als.run(context, fn); } get(): RequestContext { const store = this.als.getStore(); if (!store) { throw new Error('RequestContext not initialized'); } return store; } set(key: K, value: RequestContext[K]) { this.get()[key] = value; } // Helpers get user() { const user = this.get().user; if (!user) throw new UnauthorizedException(); return user; } get tx() { return this.get().tx; } set tx(tx) { this.set('tx', tx); } get isTransaction(): boolean { return !!this.get().tx; } get orgId(): string { return this.orgId } set orgId(id: string) { this.set('orgId', id) } }