npm package: @hqxyz/hq-node-commons
Description: Common libraries and utilities for NestJS TypeScript projects
Author: HQ Team
Latest version: 1.3.0

# HQ Node Commons

A collection of common utilities and libraries for NestJS TypeScript projects.

![CI/CD](https://github.com/hq/node-commons/workflows/CI/CD/badge.svg)
[![npm version](https://badge.fury.io/js/@hq/node-commons.svg)](https://badge.fury.io/js/@hq/node-commons)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
[![codecov](https://codecov.io/gh/hq/node-commons/branch/main/graph/badge.svg)](https://codecov.io/gh/hq/node-commons)

## Installation

```bash
npm install --save @hq/node-commons
```

## Features

- HTTP utilities (response formats, exceptions)
- Common validators
- Useful decorators
- Date and object utilities
- Configuration validation
- Slack notifications with error reporting

## Usage

```typescript
import { 
  ApiResponseBuilder, 
  DateUtils, 
  Log, 
  StringValidator, 
  ConfigValidator, 
  ConfigSchema,
  NotificationsModule,
  SlackService
} from '@hq/node-commons';

// Use ApiResponseBuilder
const response = ApiResponseBuilder.success({ id: 1, name: 'Example' });

// Use DateUtils
const today = new Date();
const tomorrow = DateUtils.addDays(today, 1);

// Use decorators
class UserService {
  @Log({ logResult: true })
  async findById(id: string) {
    // Method implementation
  }
}

// Use validators
const isValidEmail = StringValidator.isEmail('example@example.com');

// Use configuration validation
@Module({
  imports: [
    ConfigModule.forRoot({
      validate: ConfigSchema.createValidator(
        ConfigSchema.commonValidators(),
        ConfigSchema.databaseValidators()
      )
    }),
    NotificationsModule.register()
  ]
})
export class AppModule {}
```

## Documentation

### HTTP Utilities

#### ApiResponse

Standardized API response format:

```typescript
interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: {
    code: string;
    message: string;
    details?: any;
  };
  meta?: {
    pagination?: {
      page: number;
      limit: number;
      total: number;
      totalPages: number;
    };
    [key: string]: any;
  };
}
```

#### ApiResponseBuilder

Helper to create standardized API responses:

- `ApiResponseBuilder.success(data, meta)` - Create a success response
- `ApiResponseBuilder.error(code, message, details)` - Create an error response
- `ApiResponseBuilder.paginated(data, page, limit, total, additionalMeta)` - Create a paginated response

#### HTTP Exceptions

Custom HTTP exceptions with standardized format:

- `HttpException` - Base exception
- `BadRequestException` - 400 Bad Request
- `UnauthorizedException` - 401 Unauthorized
- `ForbiddenException` - 403 Forbidden
- `NotFoundException` - 404 Not Found

### Validators

#### StringValidator

String validation utilities:

- `StringValidator.isEmail(value)` - Check if string is a valid email
- `StringValidator.isUrl(value)` - Check if string is a valid URL
- `StringValidator.isUuidV4(value)` - Check if string is a valid UUID v4
- `StringValidator.isAlphanumeric(value)` - Check if string contains only alphanumeric characters

### Decorators

#### Log

Method decorator to log execution:

```typescript
@Log({ logArgs: true, logResult: true })
async findById(id: string) {
  // Method implementation
}
```

Options:
- `logArgs` - Log method arguments (default: true)
- `logResult` - Log method result (default: true)

### Utilities

#### DateUtils

Date manipulation utilities:

- `DateUtils.formatIsoDate(date)` - Format date to ISO string without milliseconds
- `DateUtils.startOfDay(date)` - Get the start of the day
- `DateUtils.endOfDay(date)` - Get the end of the day
- `DateUtils.isBetween(date, start, end)` - Check if date is between two dates
- `DateUtils.addDays(date, days)` - Add days to a date

#### ObjectUtils

Object manipulation utilities:

- `ObjectUtils.removeNullish(obj)` - Remove null and undefined values
- `ObjectUtils.isEmpty(obj)` - Check if object is empty
- `ObjectUtils.deepClone(obj)` - Deep clone an object
- `ObjectUtils.pick(obj, keys)` - Pick specific properties
- `ObjectUtils.omit(obj, keys)` - Omit specific properties

### Configuration Validation

#### ConfigValidator

Service to validate NestJS configuration on application startup:

```typescript
// Inject ConfigValidator in your module
@Module({
  imports: [ConfigModule.forRoot()],
  providers: [ConfigValidator],
})
export class AppModule {}

// Use in a service
@Injectable()
export class AppService implements OnModuleInit {
  constructor(private readonly configValidator: ConfigValidator) {}

  onModuleInit() {
    // This will throw an error if required config is missing
    this.configValidator.validateConfig([
      { key: 'DATABASE_URL', required: true },
      { 
        key: 'PORT', 
        validator: (value) => parseInt(value, 10) > 0,
        errorMessage: 'PORT must be a positive number'
      },
    ]);
  }
}
```

#### ConfigSchema

Helper to create predefined configuration schemas:

```typescript
// Use with NestJS ConfigModule
@Module({
  imports: [
    ConfigModule.forRoot({
      validate: ConfigSchema.createValidator(
        ConfigSchema.commonValidators(),
        ConfigSchema.databaseValidators(),
        ConfigSchema.jwtValidators()
      )
    })
  ]
})
export class AppModule {}
```

Available schemas:
- `ConfigSchema.commonValidators()` - Common environment variables (NODE_ENV, PORT)
- `ConfigSchema.databaseValidators()` - Database configuration
- `ConfigSchema.jwtValidators()` - JWT authentication configuration
- `ConfigSchema.redisValidators()` - Redis configuration
- `ConfigSchema.awsValidators()` - AWS configuration
- `ConfigSchema.compose(...validators)` - Combine multiple validators
- `ConfigSchema.createValidator(...validators)` - Create a validator function for ConfigModule

### Slack Notifications

#### SlackService

Service for sending notifications to Slack:

```typescript
// Import the module in your application
@Module({
  imports: [
    NotificationsModule.register(),
    // Or register it globally
    // NotificationsModule.registerGlobal(),
  ],
})
export class AppModule {}

// Inject and use the service
@Injectable()
export class YourService {
  constructor(private readonly slackService: SlackService) {}

  async doSomething() {
    try {
      // Your code here
    } catch (error) {
      // Send detailed error notification to Slack
      await this.slackService.sendErrorNotification({
        error,
        context: 'YourService.doSomething',
        metadata: { userId: '123', operation: 'important-action' },
        severity: 'high',
        notification: {
          channel: 'errors',
          mentionUsers: ['U123ABC'], // User IDs to mention
          mentionGroups: ['S456DEF'], // Group IDs to mention
          mentionEveryone: false,     // Whether to mention @channel
        },
      });
    }
  }
}
```

Configuration:
- `SLACK_WEBHOOK_URL` - Webhook URL for Slack integration
- `SLACK_DEFAULT_CHANNEL` - Default channel for notifications (default: 'alerts')
- `DEPLOYMENT_ENV` - Environment name for better context in notifications
- `APP_NAME` - Application name for better context in notifications

The notification includes:
- Error message and stack trace
- Context of where the error occurred
- Environment and severity level
- Timestamp and unique error ID
- User ID if provided
- Custom metadata
- Color-coded based on severity
- Formatted for readability with sections and fields

Severity levels:
- `low` (green) - Non-critical issues
- `medium` (amber) - Default, moderately important issues
- `high` (red) - Critical issues that need immediate attention
- `critical` (purple) - Highest priority issues

## Contributing

We welcome contributions! Please see our [contributing guide](CONTRIBUTING.md) for details.

### Commit Message Format

This repository follows [Conventional Commits](https://www.conventionalcommits.org/):

- `feat`: A new feature
- `fix`: A bug fix
- `docs`: Documentation only changes
- `style`: Changes that do not affect the meaning of the code
- `refactor`: A code change that neither fixes a bug nor adds a feature
- `perf`: A code change that improves performance
- `test`: Adding missing tests or correcting existing tests
- `build`: Changes that affect the build system or external dependencies
- `ci`: Changes to our CI configuration files and scripts
- `chore`: Other changes that don't modify src or test files
- `revert`: Reverts a previous commit

Example: `feat(http): add new response formatter`

## CI/CD Pipeline

This project uses GitHub Actions for continuous integration and deployment:

1. **Streamlined Process**: Direct pushes to `main` branch trigger the complete CI/CD pipeline
2. **Code Quality**: Linting and formatting checks ensure consistent code style
3. **Testing**: Comprehensive test suite ensures code reliability
4. **Automated Releases**: Semantic versioning with automatic CHANGELOG generation based on commit messages
5. **Documentation**: Automatic API documentation generation and deployment to GitHub Pages

For detailed information on setting up and troubleshooting the CI/CD pipeline, see [GitHub Actions Setup Guide](docs/github-actions-setup.md).

## License

MIT