npm package: @sklv-labs/ts-nestjs-cls
Description: NestJS Async Context Local Storage helper
Author: sklv-labs
Latest version: 0.1.1

# @sklv-labs/ts-nestjs-cls

A NestJS module wrapper for `nestjs-cls` that provides simplified configuration and automatic request ID handling using Continuation Local Storage (CLS).

## Features

- 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
- 🚀 **Easy Setup** - Simple API for both synchronous and asynchronous configuration
- 🛠️ **NestJS Native** - Built on top of NestJS with seamless integration
- 📦 **Auto Request ID** - Automatically extracts or generates request IDs from headers
- 🔌 **Plugin Support** - Easy integration with additional CLS plugins
- 🌐 **Platform Agnostic** - Works with both Express and Fastify adapters

## Installation

```bash
npm install @sklv-labs/ts-nestjs-cls
```

### Peer Dependencies

This package requires the following peer dependencies:

```bash
npm install @nestjs/common@^11.1.11 @nestjs/core@^11.1.11 nestjs-cls@^6.1.0
```

**Note:** This package requires Node.js 24 LTS or higher.

## Quick Start

```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { ClsModule } from '@sklv-labs/ts-nestjs-cls';

@Module({
  imports: [
    ClsModule.forRoot({
      enableMiddleware: true,
    }),
  ],
})
export class AppModule {}
```

### Using CLS Service

```typescript
import { Injectable } from '@nestjs/common';
import { ClsService } from '@sklv-labs/ts-nestjs-cls';

@Injectable()
export class MyService {
  constructor(private readonly cls: ClsService) {}

  getRequestId(): string | undefined {
    return this.cls.get('requestId');
  }
}
```

### Async Configuration

```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ClsModule } from '@sklv-labs/ts-nestjs-cls';

@Module({
  imports: [
    ConfigModule.forRoot(),
    ClsModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        enableMiddleware: config.get('CLS_ENABLED') === 'true',
        setup: (cls, req) => {
          // Custom setup logic
          cls.set('customKey', 'customValue');
        },
      }),
    }),
  ],
})
export class AppModule {}
```

### Custom Setup Function

```typescript
import { ClsModule, ClsService } from '@sklv-labs/ts-nestjs-cls';
import type { Request } from 'express';

@Module({
  imports: [
    ClsModule.forRoot({
      setup: (cls: ClsService, req: Request) => {
        // Extract request ID from header
        const requestId = req.headers['x-request-id'];
        if (requestId) {
          cls.set('requestId', Array.isArray(requestId) ? requestId[0] : requestId);
        }

        // Set additional context
        cls.set('userId', req.user?.id);
        cls.set('ip', req.ip);
      },
    }),
  ],
})
export class AppModule {}
```

### Using Plugins

```typescript
import { ClsModule } from '@sklv-labs/ts-nestjs-cls';
import { ClsPluginRequestId } from 'nestjs-cls';

@Module({
  imports: [
    ClsModule.forRoot({
      plugins: [
        new ClsPluginRequestId({
          // Plugin configuration
        }),
      ],
    }),
  ],
})
export class AppModule {}
```

## API Reference

### `ClsModule.forRoot(options?: ClsModuleOptions)`

Configure the CLS module synchronously.

#### Options

- `enableMiddleware?: boolean` - Enable CLS middleware (default: `true`)
- `setup?: (cls: ClsService, req: Request) => void` - Custom setup function for CLS context
- `plugins?: ClsPlugin[]` - Additional CLS plugins to register
- All other options from `nestjs-cls` `ClsModuleOptions` are supported

### `ClsModule.forRootAsync(options: ClsModuleAsyncOptions)`

Configure the CLS module asynchronously.

#### Options

- `imports?: Module[]` - Modules to import
- `inject?: Type[]` - Dependencies to inject into `useFactory`
- `useFactory: (...args) => ClsModuleOptions | Promise<ClsModuleOptions>` - Factory function returning configuration

## Default Behavior

By default, the module:

1. Extracts the `x-request-id` header from incoming requests
2. If no request ID is found, generates a new UUID using `crypto.randomUUID()`
3. Stores the request ID in the CLS context under the key `requestId`
4. Makes the CLS context available globally throughout your application

## Development

```bash
# Build
npm run build

# Lint
npm run lint

# Format
npm run format

# Test
npm run test

# Type check
npm run type-check
```

## License

MIT © [sklv-labs](https://github.com/sklv-labs)