npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@pagamio/nestjs-api-commons

v0.2.0

Published

Common utilities, modules, and services for NestJS-based Pagamio APIs

Readme

Pagamio NestJS API Commons

A comprehensive commons library for NestJS-based Pagamio APIs, providing reusable modules, utilities, and services.

📦 Installation

pnpm add @pagamio/nestjs-api-commons

🏗️ Module Structure

1. Authentication Module (auth/)

Provides authentication and authorization utilities.

Features:

  • JWT authentication strategy
  • API Key authentication strategy
  • Role-based access control
  • Custom decorators for public routes and role management

Usage:

import {
  AuthModule,
  JwtAuthGuard,
  Roles,
  Public,
  CurrentUser,
} from '@pagamio/nestjs-api-commons';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    AuthModule.forRoot(), // ✅ Dynamic module
  ],
})
export class AppModule {}

@Controller('users')
@UseGuards(JwtAuthGuard, RolesGuard)
export class UsersController {
  @Get('profile')
  @Roles('admin', 'user')
  getProfile(@CurrentUser() user: any) {
    return user;
  }

  @Public()
  @Get('public')
  getPublicData() {
    return { message: 'Public endpoint' };
  }
}

2. Database Module (database/)

Base entities and repositories with common database operations.

Features:

  • Base entity with UUID, timestamps, and soft deletes
  • Base repository with common CRUD operations
  • Transaction interceptor

Usage:

import { BaseEntity, BaseRepository } from '@pagamio/nestjs-api-commons';

@Entity()
export class User extends BaseEntity {
  @Column()
  name: string;

  @Column()
  email: string;
}

@Injectable()
export class UserRepository extends BaseRepository<User> {}

3. Validation Module (validation/)

DTOs and pipes for request validation.

Features:

  • Pagination DTO
  • Base query DTO with search and sorting
  • Custom validation pipes

Usage:

import { PaginationDto, BaseQueryDto } from '@pagamio/nestjs-api-commons';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Query() query: PaginationDto & BaseQueryDto) {
    return this.productsService.findAll(query);
  }
}

4. Observability Module (observability/)

Logging, health checks, and metrics.

Features:

  • Custom logger service with Winston integration
  • Request logging interceptor
  • Health check controller
  • Metrics service
  • Configurable log levels and transports

Usage:

import {
  LoggerService,
  MetricsService,
  ObservabilityModule,
} from '@pagamio/nestjs-api-commons';

@Module({
  imports: [ObservabilityModule],
})
export class AppModule {}

@Injectable()
export class MyService {
  constructor(
    private logger: LoggerService,
    private metrics: MetricsService,
  ) {
    this.logger.setContext('MyService');
  }

  doSomething() {
    this.logger.log('Doing something...');
    this.metrics.incrementCounter('my_service_calls');
  }
}

Logger Features:

  • Structured logging with Winston
  • Multiple transports (console, file)
  • Automatic file logging in production
  • Colorized console output
  • Contextual logging

5. HTTP Module (http/)

HTTP interceptors and exception filters.

Features:

  • Response wrapper interceptor
  • Timeout interceptor
  • Logging interceptor
  • HTTP exception filter
  • Global exception filter

Usage:

import {
  ResponseWrapperInterceptor,
  HttpExceptionFilter,
  AllExceptionsFilter,
  HttpModule,
} from '@pagamio/nestjs-api-commons';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalInterceptors(new ResponseWrapperInterceptor());
  app.useGlobalFilters(new HttpExceptionFilter(), new AllExceptionsFilter());

  await app.listen(3000);
}

6. Events Module (events/)

Event-driven architecture infrastructure with base classes, decorators, and utilities.

Features:

  • BaseEvent: Abstract base class for all events with metadata support
  • System Events: Pre-built events for common system occurrences
  • @DomainEvent: Decorator for marking domain events with metadata
  • @EventListener: Enhanced event listener decorator with retry logic
  • EventSerializer: Utilities for serializing/deserializing events
  • EventsModule: Module configuration with EventEmitter2

Usage:

import {
  BaseEvent,
  DomainEvent,
  EventListener,
  EventsModule,
  SYSTEM_EVENTS,
} from '@pagamio/nestjs-api-commons';

// 1. Import EventsModule in your AppModule
@Module({
  imports: [
    EventsModule.forRoot({
      wildcard: true,
      delimiter: '.',
      maxListeners: 10,
    }),
  ],
})
export class AppModule {}

// 2. Create domain events by extending BaseEvent
@DomainEvent('user.created', { version: 1 })
export class UserCreatedEvent extends BaseEvent {
  constructor(
    public readonly userId: string,
    public readonly email: string,
  ) {
    super(userId); // Pass userId for user-initiated events
  }

  getPayload() {
    return {
      userId: this.userId,
      email: this.email,
    };
  }
}

// 3. Emit events in your services
@Injectable()
export class UsersService {
  constructor(private readonly eventEmitter: EventEmitter2) {}

  async create(dto: CreateUserDto) {
    const user = await this.usersRepository.save(dto);

    // Emit event
    this.eventEmitter.emit(
      'user.created',
      new UserCreatedEvent(user.id, user.email),
    );

    return user;
  }
}

// 4. Listen to events with automatic retry
@Injectable()
export class UserEventsListener {
  constructor(private readonly logger: LoggerService) {}

  @EventListener('user.created', {
    async: true,
    maxRetries: 3,
    retryDelay: 1000,
  })
  async handleUserCreated(event: UserCreatedEvent) {
    this.logger.log(`User created: ${event.email}`);
    // Send welcome email, etc.
  }
}

System Events:

Pre-built events for common system-level occurrences:

import {
  AppStartedEvent,
  AppShuttingDownEvent,
  HealthCheckFailedEvent,
  CriticalErrorEvent,
  SYSTEM_EVENTS,
} from '@pagamio/nestjs-api-commons';

// Emit system events
this.eventEmitter.emit(
  SYSTEM_EVENTS.APP_STARTED,
  new AppStartedEvent('MyApp', '1.0.0', 'production', 3000),
);

Event Serialization:

import { EventSerializer } from '@pagamio/nestjs-api-commons';

const event = new UserCreatedEvent('user-123', '[email protected]');

// Serialize to JSON string
const json = EventSerializer.serialize(event);

// Deserialize back
const deserialized = EventSerializer.deserialize(json);

// Batch operations
const events = [event1, event2, event3];
const batchJson = EventSerializer.serializeBatch(events);

BaseEvent Features:

Every event automatically includes:

  • eventId: Unique UUID for deduplication
  • occurredAt: Timestamp when event occurred
  • userId: Optional user ID who initiated the event
  • correlationId: Optional correlation ID for distributed tracing
  • metadata: Optional additional metadata

7. Jobs Module (jobs/)

Background job processing infrastructure with BullMQ integration.

Features:

  • BaseProcessor: Abstract base class providing reference implementation patterns (⚠️ cannot be extended across modules due to NestJS BullMQ validation)
  • JobResult: Standardized result interface with success/error/metadata
  • @RetryableJob: Decorator for configuring retry behavior with backoff strategies
  • @JobMetrics: Decorator for automatic metrics collection
  • QueueFactory: Standardized queue creation (high-priority, critical, batch)
  • Retry Strategies: Exponential, linear, jittered, conditional, and error-specific
  • QueueHealthIndicator: Health checks for queue monitoring
  • Custom Errors: JobError, JobTimeoutError, JobValidationError, etc.

Usage:

import {
  JobsModule,
  BaseProcessor,
  JobResult,
  RetryableJob,
  JobMetricsDecorator,
  QueueFactory,
} from '@pagamio/nestjs-api-commons';

// 1. Import JobsModule in your AppModule
@Module({
  imports: [
    JobsModule.forRoot({
      connection: {
        host: 'localhost',
        port: 6379,
      },
      enableHealthChecks: true,
    }),
  ],
})
export class AppModule {}

// 2. Register queues in feature modules
@Module({
  imports: [
    JobsModule.forFeature([{ name: 'email' }, { name: 'data-export' }]),
  ],
})
export class JobsFeatureModule {}

// 3. Create job processors by extending WorkerHost directly
// ⚠️ IMPORTANT: Due to NestJS BullMQ's instanceof validation, processors MUST extend
// WorkerHost directly. BaseProcessor cannot be used as a parent class across module boundaries.
// Instead, implement the process() method and create JobResult objects manually.
@Processor('email')
@RetryableJob({
  maxAttempts: 3,
  backoffType: 'exponential',
  delay: 1000,
  maxDelay: 10000,
})
@JobMetricsDecorator({
  prefix: 'email_job',
  tags: { processor: 'email' },
})
export class EmailProcessor extends WorkerHost {
  constructor(protected readonly logger: LoggerService) {
    super();
    this.logger.setContext(EmailProcessor.name);
  }

  async process(job: Job<EmailJobDto>): Promise<JobResult<{ sent: boolean }>> {
    try {
      // Your processing logic
      const sent = await this.sendEmail(job.data);

      // Return standardized result manually
      return {
        success: true,
        data: { sent },
        metadata: { recipient: job.data.to },
      };
    } catch (error) {
      // Handle errors
      throw error;
    }
  }
}

// Note: BaseProcessor provides reference implementation patterns but cannot be
// extended directly. Use its code as a template for common functionality.

// 4. Enqueue jobs in your services
@Injectable()
export class EmailService {
  constructor(@InjectQueue('email') private emailQueue: Queue) {}

  async sendWelcomeEmail(email: string) {
    await this.emailQueue.add('send', {
      to: email,
      subject: 'Welcome!',
      body: 'Thanks for joining us!',
    });
  }
}

Queue Factory:

import { QueueFactory } from '@pagamio/nestjs-api-commons';

const connection = { host: 'localhost', port: 6379 };

// Standard queue
const emailQueue = QueueFactory.createQueue('email', connection);

// High-priority queue (10 priority, 5 attempts, fast backoff)
const urgentQueue = QueueFactory.createHighPriorityQueue('urgent', connection);

// Critical queue (20 priority, 10 attempts, keeps 1000 completed jobs)
const criticalQueue = QueueFactory.createCriticalQueue('critical', connection);

// Batch processing queue (1 attempt, auto-cleanup)
const batchQueue = QueueFactory.createBatchQueue('batch', connection);

// Custom retry configuration
const customQueue = QueueFactory.createQueueWithRetry(
  'custom',
  connection,
  5, // max attempts
  2000, // retry delay in ms
);

Retry Strategies:

import {
  exponentialBackoff,
  linearBackoff,
  jitteredExponentialBackoff,
  conditionalRetry,
  withMaxAttempts,
  errorSpecificRetry,
} from '@pagamio/nestjs-api-commons';

// Exponential backoff: 1s, 2s, 4s, 8s...
const strategy1 = exponentialBackoff(1000, 60000);

// Linear backoff: 1s, 3s, 5s, 7s...
const strategy2 = linearBackoff(1000, 2000, 30000);

// Jittered exponential (prevents thundering herd)
const strategy3 = jitteredExponentialBackoff(1000, 60000, 0.2);

// Conditional retry (only retry certain errors)
const strategy4 = conditionalRetry(
  exponentialBackoff(1000),
  (attempt, error) => error.message !== 'Permanent failure',
);

// Max attempts wrapper
const strategy5 = withMaxAttempts(exponentialBackoff(1000), 5);

// Error-specific strategies
const strategy6 = errorSpecificRetry(
  new Map([
    [NetworkError, exponentialBackoff(1000)],
    [ValidationError, fixedDelay(500)],
  ]),
  exponentialBackoff(2000), // default
);

Queue Health Checks:

import {
  QueueHealthIndicator,
  HealthCheck,
  HealthCheckService,
} from '@pagamio/nestjs-api-commons';

@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private queueHealth: QueueHealthIndicator,
    @InjectQueue('email') private emailQueue: Queue,
  ) {}

  @Get('queues')
  @HealthCheck()
  checkQueues() {
    return this.health.check([
      () =>
        this.queueHealth.isHealthy('email-queue', this.emailQueue, {
          maxFailedJobs: 50,
          maxWaitingJobs: 1000,
        }),
      () => this.queueHealth.pingCheck('email-ping', this.emailQueue),
    ]);
  }
}

Custom Job Errors:

import {
  JobError,
  JobTimeoutError,
  JobValidationError,
  JobProcessingError,
  JobMaxRetriesError,
} from '@pagamio/nestjs-api-commons';

// In your processor
if (timeout) {
  throw new JobTimeoutError('Job exceeded 30s timeout');
}

if (invalid) {
  throw new JobValidationError('Invalid email format', {
    field: 'email',
    value: job.data.email,
  });
}

// Errors automatically logged and tracked

8. Pagination Module (pagination/)

Comprehensive pagination utilities supporting both offset-based and cursor-based pagination.

Features:

  • Offset Pagination: Traditional page/limit pagination with metadata
  • Cursor Pagination: High-performance pagination for large datasets
  • @Paginate Decorator: Auto-documentation for pagination endpoints
  • CursorEncoder: Base64 encoding/decoding for cursor strings
  • PaginationHelper: Utilities for creating paginated responses

Usage:

Offset-Based Pagination:

import {
  PaginationQueryDto,
  PaginatedResponseDto,
  PaginationHelper,
  Paginate,
} from '@pagamio/nestjs-api-commons';

@Controller('products')
export class ProductsController {
  @Get()
  @Paginate(20, 100) // default limit 20, max 100
  async findAll(
    @Query() query: PaginationQueryDto,
  ): Promise<PaginatedResponseDto<Product>> {
    const [items, total] = await this.productsService.findAndCount({
      skip: query.getSkip(),
      take: query.getTake(),
      order: { [query.sortBy || 'createdAt']: query.order },
    });

    return PaginationHelper.createResponse(items, query, total);
  }
}

Cursor-Based Pagination:

import {
  CursorPaginationQueryDto,
  CursorPaginatedResponseDto,
  PaginationHelper,
  CursorPaginate,
  CursorEncoder,
} from '@pagamio/nestjs-api-commons';

@Controller('messages')
export class MessagesController {
  @Get()
  @CursorPaginate(50, 100)
  async findAll(
    @Query() query: CursorPaginationQueryDto,
  ): Promise<CursorPaginatedResponseDto<Message>> {
    const limit = query.limit || 50;

    // Build query with cursor filter
    const where: any = {};
    if (query.cursor) {
      const filter = PaginationHelper.parseCursorToFilter(
        query.cursor,
        query.sortBy || 'createdAt',
        query.order || 'asc',
      );
      Object.assign(where, filter);
    }

    // Fetch one extra item to check for next page
    const items = await this.messagesService.find({
      where,
      take: limit + 1,
      order: { [query.sortBy || 'createdAt']: query.order },
    });

    return PaginationHelper.createCursorResponse(items, query);
  }
}

Cursor Utilities:

import { CursorEncoder } from '@pagamio/nestjs-api-commons';

// Encode cursor
const cursor = CursorEncoder.encode({
  id: '123',
  createdAt: '2025-11-18T00:00:00Z',
});

// Decode cursor
const decoded = CursorEncoder.decode(cursor);

// Create cursor from entity
const entity = { id: '123', createdAt: new Date(), name: 'Test' };
const cursor = CursorEncoder.createFromEntity(entity, 'createdAt');

// Validate cursor
if (CursorEncoder.isValid(cursor)) {
  // Use cursor
}

Response Format:

Offset pagination response:

{
  "data": [...],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 100,
    "totalPages": 5,
    "hasNextPage": true,
    "hasPreviousPage": false
  }
}

Cursor pagination response:

{
  "data": [...],
  "meta": {
    "nextCursor": "eyJpZCI6IjEyMyJ9...",
    "previousCursor": null,
    "hasNextPage": true,
    "hasPreviousPage": false,
    "count": 20
  }
}

9. Versioning Module (versioning/)

API versioning and deprecation utilities for managing API lifecycle.

Features:

  • @Deprecated Decorator: Mark endpoints as deprecated with sunset dates
  • DeprecationWarningInterceptor: Automatic deprecation headers (RFC 8594)
  • VersionHeaderInterceptor: Add API version information to responses
  • VersionParser: Parse and compare semver versions

Usage:

Deprecating Endpoints:

import { Deprecated } from '@pagamio/nestjs-api-commons';

@Controller({ path: 'users', version: '1' })
export class UsersV1Controller {
  @Get(':id')
  @Deprecated({
    message: 'Use /api/v2/users/:id instead for enhanced user data',
    sunset: '2026-06-01',
    alternativeUrl: '/api/v2/users/:id',
    since: '2.0.0',
  })
  async findOne(@Param('id') id: string) {
    // Old implementation
    return this.usersService.findOne(id);
  }
}

Response Headers (automatic):

Deprecation: true
Sunset: Sat, 01 Jun 2026 00:00:00 GMT
Link: </api/v2/users/:id>; rel="alternate"
X-API-Deprecation-Info: {"message":"Use /api/v2/users/:id instead...","since":"2.0.0","sunset":"2026-06-01","alternative":"/api/v2/users/:id"}

Version Parsing and Comparison:

import { VersionParser } from '@pagamio/nestjs-api-commons';

// Parse versions
const version = VersionParser.parse('v2.1.0');
// { major: 2, minor: 1, patch: 0 }

// Compare versions
VersionParser.compare('2.0.0', '1.9.9'); // 1 (greater)
VersionParser.isGreaterThan('2.0.0', '1.0.0'); // true
VersionParser.isLessThan('1.0.0', '2.0.0'); // true
VersionParser.isEqual('v1.0', '1.0.0'); // true

// Validate versions
VersionParser.isValid('1.2.3'); // true
VersionParser.isValid('invalid'); // false

// Extract from headers
const version = VersionParser.extractFromHeader(
  'application/json; version=2.0',
);
// '2.0'

Adding Version Headers:

import { VersionHeaderInterceptor } from '@pagamio/nestjs-api-commons';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useValue: new VersionHeaderInterceptor('1.0.0'),
    },
  ],
})
export class AppModule {}

Response Headers:

X-API-Version: 1.0.0
X-API-Requested-Version: v1

10. Utils (utils/)

Common utility functions.

Common utility functions.

Features:

  • CryptoUtil: Password hashing, comparison, random string generation
  • DateUtil: Date manipulation and formatting
  • StringUtil: String transformations (camelCase, snake_case, slugify, etc.)

Usage:

import { CryptoUtil, DateUtil, StringUtil } from '@pagamio/nestjs-api-commons';

// Crypto utilities
const hashed = await CryptoUtil.hashPassword('password123');
const isValid = await CryptoUtil.comparePassword('password123', hashed);

// Date utilities
const tomorrow = DateUtil.addDays(new Date(), 1);
const isPast = DateUtil.isPast(new Date('2020-01-01'));

// String utilities
const slug = StringUtil.slugify('Hello World!'); // 'hello-world'
const camel = StringUtil.toCamelCase('hello world'); // 'helloWorld'

🚀 Quick Start

  1. Install the package:
pnpm add @pagamio/nestjs-api-commons
  1. Import modules in your app:
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; // ← Add this
import {
  AuthModule,
  DatabaseModule,
  ValidationModule,
  ObservabilityModule,
  HttpModule,
} from '@pagamio/nestjs-api-commons';

@Module({
  imports: [
    // ← Configure environment variables first
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
    AuthModule,
    DatabaseModule,
    ValidationModule,
    ObservabilityModule,
    HttpModule,
  ],
})
export class AppModule {}
  1. Use utilities and decorators:
import {
  Public,
  Roles,
  CurrentUser,
  CryptoUtil,
  LoggerService,
} from '@pagamio/nestjs-api-commons';

💡 Complete Usage Example

Here's a complete example showing how to use the library in your NestJS application:

1. Install dependencies in your project:

pnpm add @pagamio/nestjs-api-commons @nestjs/config

2. Create .env file in your project root:

JWT_SECRET=my-super-secret-key-change-in-production
VALID_API_KEYS=dev-key-123,prod-key-456
LOG_LEVEL=debug
NODE_ENV=development

3. Configure your app.module.ts:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AuthModule, ObservabilityModule } from '@pagamio/nestjs-api-commons';
import { UsersModule } from './users/users.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    AuthModule,
    ObservabilityModule,
    UsersModule,
  ],
})
export class AppModule {}

4. Use in your controller:

import { Controller, Get, UseGuards } from '@nestjs/common';
import {
  JwtAuthGuard,
  RolesGuard,
  Roles,
  Public,
  CurrentUser,
  LoggerService,
} from '@pagamio/nestjs-api-commons';

@Controller('users')
@UseGuards(JwtAuthGuard, RolesGuard)
export class UsersController {
  constructor(private logger: LoggerService) {
    this.logger.setContext('UsersController');
  }

  @Get('profile')
  @Roles('admin', 'user')
  getProfile(@CurrentUser() user: any) {
    this.logger.log(`User ${user.userId} accessed their profile`);
    return user;
  }

  @Public()
  @Get('public')
  getPublicInfo() {
    this.logger.log('Public endpoint accessed');
    return { message: 'This is public' };
  }
}

5. Run your application:

pnpm run start:dev

The library will automatically read the environment variables from your .env file!

🔧 Configuration

Environment Variables

This library reads environment variables from your consuming application, not from the library itself. You need to configure these in your main project.

Where to place your .env file:

  • Place the .env file in the root directory of your application (the project that uses this library)
  • Not in the node_modules/@pagamio/nestjs-api-commons/ folder

How the library picks up environment variables:

The library uses process.env to read configuration, which means:

  1. Using @nestjs/config (Recommended):

    // In your main application's app.module.ts
    import { Module } from '@nestjs/common';
    import { ConfigModule } from '@nestjs/config';
    import {
      AuthModule,
      ObservabilityModule,
    } from '@pagamio/nestjs-api-commons';
    
    @Module({
      imports: [
        // Load .env file from your project root
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: '.env', // or '.env.development', '.env.production', etc.
        }),
        AuthModule,
        ObservabilityModule,
        // ... other modules
      ],
    })
    export class AppModule {}
  2. Using dotenv directly:

    // In your main.ts (before creating the app)
    import * as dotenv from 'dotenv';
    dotenv.config();
    
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      await app.listen(3000);
    }
    bootstrap();

Required environment variables in your application's .env file:

# JWT Configuration (for AuthModule)
JWT_SECRET=your-secret-key-here

# API Key Configuration (for API Key authentication)
VALID_API_KEYS=key1,key2,key3

# Logging Configuration (for LoggerService)
LOG_LEVEL=info
# Options: error, warn, info, debug, verbose
NODE_ENV=development
# Use 'production' to enable file logging to logs/ directory

Example project structure:

your-application/
├── .env                    # ← Your environment variables go here
├── .env.development
├── .env.production
├── src/
│   ├── app.module.ts       # ← Configure ConfigModule here
│   ├── main.ts
│   └── ...
├── node_modules/
│   └── @pagamio/nestjs-api-commons/  # ← Library reads from YOUR .env
├── package.json
└── ...

Note: The library modules will automatically pick up these environment variables when they are instantiated in your application. You don't need to pass them manually.

🔍 Troubleshooting Environment Variables

Problem: "JWT_SECRET is undefined"

  • ✅ Ensure .env file is in your project root (not in node_modules)
  • ✅ Add ConfigModule.forRoot() before importing AuthModule
  • ✅ Check that your .env file is not in .gitignore during development
  • ✅ Restart your development server after adding/changing .env

Problem: "Logger not working as expected"

  • ✅ Set LOG_LEVEL environment variable (defaults to 'info')
  • ✅ Check NODE_ENV - file logging only works in production

Problem: "API Key authentication not working"

  • ✅ Ensure VALID_API_KEYS is a comma-separated list with no spaces
  • ✅ Example: VALID_API_KEYS=key1,key2,key3
  • ✅ Wrong: VALID_API_KEYS=key1, key2, key3 ❌ (spaces will cause issues)

📝 Development

# Install dependencies
pnpm install

# Build the library
pnpm run build

# Run tests
pnpm test

# Lint
pnpm run lint

🤝 Contributing

Contributions are welcome! Please check the CHANGELOG.md for version history.

📄 License

MIT - See LICENSE file for details

👥 Author

Pagamio Team

🔗 Links