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

devware-commons

v0.0.22

Published

Common utilities and services for DevWare projects

Downloads

90

Readme

DevWare Commons

A comprehensive NestJS library providing essential modules and utilities for building modern applications. This package includes authentication, email/SMS services, AWS Parameter Store integration, and common utilities to accelerate development across DevWare projects.

Features

  • 🔐 Authentication Module - JWT-based authentication with session management
  • 📧 Mail Service - AWS SES integration for sending emails
  • 📱 SMS Service - Twilio integration for sending text messages
  • Files Module - AWS S3 integration for secure file management with presigned URLs
  • 🔧 Parameter Store - AWS Systems Manager Parameter Store client
  • 🛠️ Common Utilities - Validators, pipes, interceptors, and helpers

Installation

npm install devware-commons

Quick Start

Import Individual Modules

// Import specific modules (recommended)
import { AuthModule } from 'devware-commons/auth';
import { MailModule } from 'devware-commons/mail';
import { SmsModule } from 'devware-commons/sms';
import { FilesModule } from 'devware-commons/files';
import { ValidateMongoIdPipe } from 'devware-commons/common';

Or Import Everything

// Import everything from root (for backward compatibility)
import {
  AuthModule,
  MailService,
  SmsService,
  FilesService,
} from 'devware-commons';

Modules

🔐 Authentication Module

Provides JWT-based authentication with refresh token support and MongoDB session storage.

Configuration

import { Module } from '@nestjs/common';
import { AuthModule } from 'devware-commons/auth';
import { UserService } from './user.service';

@Module({
  imports: [
    AuthModule.forRoot({
      params: (injectedService: UsersService) => ({
        jwtSecret: 'your-jwt-secret',
        refreshTokenSecret: 'your-refresh-secret',
        userService: injectedService,
      }),
      options: {
        inject: [UsersService],
        imports: [UsersModule],
      },
    }),
  ],
})
export class AppModule {}

Configuration Parameters

| Parameter | Type | Required | Description | | -------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | jwtSecret | string | ✅ | Secret key for JWT token signing | | refreshTokenSecret | string | ✅ | Secret key for refresh token signing | | userService | any | ✅ | Your user service implementation, user service should include the methods userForAuth(id), checkIsAdmin(user) and validateUser(username, password) |

Exports

  • AuthService - Authentication service for login/logout operations
  • JwtAuthGuard - Guard for protecting routes with JWT authentication
  • SessionServiceOptions - Interface for configuration options

📧 Mail Module

AWS SES integration for sending HTML emails with validation and error handling.

Configuration

import { MailModule } from 'devware-commons/mail';

@Module({
  imports: [
    MailModule.forRoot({
      params: {
        region: 'us-east-1', // AWS region
        from: '[email protected]', // Default sender (optional)
      },
      options: {
        isGlobal: true, // Make service globally available (optional)
      },
    }),
  ],
})
export class AppModule {}

Configuration Parameters

| Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------- | | region | string | ✅ | AWS region where SES is configured | | from | string | ❌ | Default sender email address |

Usage

import { MailService, SendEmailDto } from 'devware-commons/mail';

@Injectable()
export class ExampleService {
  constructor(private mailService: MailService) {}

  async sendWelcomeEmail(userEmail: string) {
    const result = await this.mailService.sendEmail({
      to: userEmail,
      subject: 'Welcome to Our Platform',
      body: '<h1>Welcome!</h1><p>Thank you for joining us.</p>',
      from: '[email protected]', // Optional, uses default if not provided
    });
  }
}

Email Parameters

| Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------- | | to | string | ✅ | Recipient email address | | subject | string | ✅ | Email subject (max 200 chars) | | body | string | ✅ | HTML email content (max 10,000 chars) | | from | string | ❌ | Sender email (uses default if not provided) |

📱 SMS Module

Twilio integration for sending text messages with validation and error handling.

Configuration

import { SmsModule } from 'devware-commons/sms';

@Module({
  imports: [
    SmsModule.forRoot({
      params: {
        phoneNumber: '+1234567890', // Your Twilio phone number
        accountSid: 'your-account-sid',
        authToken: 'your-auth-token',
      },
      options: {
        isGlobal: true, // Make service globally available (optional)
      },
    }),
  ],
})
export class AppModule {}

Configuration Parameters

| Parameter | Type | Required | Description | | ------------- | ------ | -------- | ----------------------------------- | | phoneNumber | string | ✅ | Twilio phone number for sending SMS | | accountSid | string | ✅ | Twilio Account SID | | authToken | string | ✅ | Twilio Auth Token |

Usage

import { SmsService, SendSmsDto } from 'devware-commons/sms';

@Injectable()
export class ExampleService {
  constructor(private smsService: SmsService) {}

  async sendVerificationCode(phoneNumber: string, code: string) {
    const response = await this.smsService.sendSMS({
      to: phoneNumber,
      message: `Your verification code is: ${code}`,
    });

    return response;
  }
}

SMS Parameters

| Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------- | | to | string | ✅ | Recipient phone number | | message | string | ✅ | Text message content |

� Files Module

AWS S3 integration for secure file management with MongoDB metadata storage and presigned URL generation.

Configuration

import { FilesModule } from 'devware-commons/files';

@Module({
  imports: [
    FilesModule.forRoot({
      params: {
        region: 'us-east-1', // AWS region
        publicBucketName: 'my-public-bucket', // Optional: for public files
        privateBucketName: 'my-private-bucket', // Optional: for private files
      },
      options: {
        isGlobal: true, // Make service globally available (optional)
      },
    }),
  ],
})
export class AppModule {}

Configuration Parameters

| Parameter | Type | Required | Description | | ------------------- | ------ | -------- | --------------------------------------- | | region | string | ✅ | AWS region where S3 buckets are located | | publicBucketName | string | ❌ | S3 bucket name for public files | | privateBucketName | string | ❌ | S3 bucket name for private files |

Note: At least one bucket (public or private) must be configured.

Usage

import { FilesService, FileDataDto, FileStatus } from 'devware-commons/files';

@Injectable()
export class ExampleService {
  constructor(private filesService: FilesService) {}

  // Upload a file (creates record and returns presigned URL)
  async uploadFile() {
    const fileData: FileDataDto = {
      name: 'document.pdf',
      size: 1024000, // size in bytes
      mimeType: 'application/pdf',
      extension: '.pdf',
      isPublic: false, // true for public bucket, false for private
    };

    const result = await this.filesService.fileUpload(fileData);

    // result contains:
    // - file: MongoDB document with metadata
    // - signedUrl: Presigned URL for S3 upload (expires in 520 seconds)

    return result;
  }

  // Retrieve multiple files by IDs
  async getFiles(fileIds: string[]) {
    const files = await this.filesService.getFiles({ fileIds });

    // Returns array of files with id, name, and S3 details
    return files;
  }

  // Update file status
  async publishFile(fileId: string) {
    const updatedFile = await this.filesService.changeFileStatus(
      fileId,
      FileStatus.ACTIVE,
    );

    return updatedFile;
  }
}

File Upload DTOs

FileDataDto

| Parameter | Type | Required | Description | | ----------- | ------- | -------- | ------------------------------------------------- | | name | string | ✅ | Original filename | | size | number | ✅ | File size in bytes | | mimeType | string | ✅ | MIME type (e.g., 'image/jpeg', 'application/pdf') | | extension | string | ✅ | File extension (e.g., '.jpg', '.pdf') | | isPublic | boolean | ✅ | Upload to public (true) or private (false) bucket |

File Status Enum

enum FileStatus {
  DRAFT = 'DRAFT', // Initial status after upload
  ACTIVE = 'ACTIVE', // File is active and available
  DELETED = 'DELETED', // File is marked as deleted
}

Response Interfaces

File Upload Response

{
  file: {
    _id: string;
    fileMeta: {
      name: string;
      size: number;
      mimeType: string;
      extension: string;
    }
    s3: {
      bucket: string;
      key: string; // unique filename generated
    }
    status: FileStatus;
    createdAt: Date;
    updatedAt: Date;
  }
  signedUrl: string; // Presigned URL for S3 upload (expires in 520 seconds)
}

File Retrieve Response

{
  id: string;
  name: string;
  s3: {
    bucket: string;
    key: string;
  }
}

Complete File Upload Flow

  1. Create File Record: Call fileUpload() with file metadata
  2. Upload to S3: Use the returned presigned URL to upload file to S3
  3. Update Status: Change status from DRAFT to ACTIVE after successful upload
  4. Retrieve Files: Use getFiles() to fetch file information when needed
// Step 1: Create file record and get presigned URL
const { file, signedUrl } = await this.filesService.fileUpload({
  name: 'profile-picture.jpg',
  size: 524288, // 512KB
  mimeType: 'image/jpeg',
  extension: '.jpg',
  isPublic: true,
});

// Step 2: Upload file to S3 using the presigned URL
// (This happens on the client side or using HTTP client)
const uploadResponse = await fetch(signedUrl, {
  method: 'PUT',
  body: fileBuffer,
  headers: {
    'Content-Type': 'image/jpeg',
  },
});

// Step 3: Update file status after successful upload
if (uploadResponse.ok) {
  await this.filesService.changeFileStatus(file._id, FileStatus.ACTIVE);
}

Controller Integration

The module includes a built-in controller with the following endpoint:

POST / files / upload;

Request Body:

{
  "name": "document.pdf",
  "size": 1024000,
  "mimeType": "application/pdf",
  "extension": ".pdf",
  "isPublic": false
}

Response:

{
  "file": {
    "_id": "64f8a1b2c3d4e5f6a7b8c9d0",
    "fileMeta": {
      "name": "document.pdf",
      "size": 1024000,
      "mimeType": "application/pdf",
      "extension": ".pdf"
    },
    "s3": {
      "bucket": "my-private-bucket",
      "key": "1698765432000_abc123_document.pdf"
    },
    "status": "DRAFT",
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T10:30:00.000Z"
  },
  "signedUrl": "https://s3.amazonaws.com/my-private-bucket/1698765432000_abc123_document.pdf?..."
}

🔧 Parameter Store Service

AWS Systems Manager Parameter Store client for retrieving configuration parameters.

Usage

import { ParameterStoreService } from 'devware-commons/parameter-store';

@Injectable()
export class ConfigService {
  async loadConfiguration() {
    try {
      const parameters = await ParameterStoreService.getParameters({
        region: 'us-east-1',
        environment: 'production',
        projectName: 'my-app',
        parameterNames: ['database-url', 'api-key', 'secret-key'],
      });

      console.log('Database URL:', parameters['database-url']);
      console.log('API Key:', parameters['api-key']);
      console.log('Secret Key:', parameters['secret-key']);

      return parameters;
    } catch (error) {
      console.error('Failed to load parameters:', error.message);
      throw error;
    }
  }
}

Configuration Parameters

| Parameter | Type | Required | Description | | ---------------- | -------- | -------- | -------------------------------------------- | | region | string | ✅ | AWS region where parameters are stored | | environment | string | ✅ | Environment identifier (staging, production) | | projectName | string | ✅ | Project name used in parameter paths | | parameterNames | string[] | ✅ | Array of parameter names to retrieve |

Retrieve All Parameters by Path

The getAllByPath method retrieves all parameters under a specific path hierarchy in AWS Parameter Store. This is useful when you want to load all configuration parameters for a given path without specifying individual parameter names.

import { ParameterStoreService } from 'devware-commons/parameter-store';

@Injectable()
export class ConfigService {
  async loadAllConfigurationsByPath() {
    try {
      const parameters = await ParameterStoreService.getAllByPath(
        '/production/my-app',
        {
          region: 'us-east-1',
          recursive: true, // Optional: retrieve nested paths (default: true)
          decrypt: true, // Optional: decrypt SecureString parameters (default: true)
        },
      );

      // Returns object with parameter names (without path) as keys
      // e.g., { 'database-url': 'value', 'api-key': 'value', 'secret-key': 'value' }
      console.log('All parameters:', parameters);

      return parameters;
    } catch (error) {
      console.error('Failed to load parameters by path:', error.message);
      throw error;
    }
  }
}

getAllByPath Parameters

| Parameter | Type | Required | Description | | ----------- | ------- | -------- | ----------------------------------------------------------------- | | path | string | ✅ | The path prefix for parameters (e.g., '/production/my-app') | | region | string | ✅ | AWS region where parameters are stored | | recursive | boolean | ❌ | Retrieve all parameters within the path hierarchy (default: true) | | decrypt | boolean | ❌ | Decrypt SecureString parameters (default: true) |

Parameter Naming Convention

Parameters should be stored in AWS Parameter Store with the following path structure:

/{environment}/{projectName}/{parameterName}

Example:

  • /production/my-app/database-url
  • /production/my-app/api-key
  • /staging/my-app/database-url

🛠️ Common Utilities

Collection of useful utilities, pipes, interceptors, and validators.

🔑 Password Service

The PasswordService provides secure password reset functionality, including generating unique password reset requests, validating them, and invalidating used or expired requests. It is designed to work with MongoDB and integrates with NestJS dependency injection.

Features

  • Request Password Change: Generates a unique, expiring password reset request for a given email address.
  • Validate Request: Checks if a password reset request is valid (active and not expired).
  • Invalidate Request: Marks a password reset request as inactive after use.

Usage Example

import { PasswordService } from 'devware-commons/auth';

@Injectable()
export class AuthService {
  constructor(private passwordService: PasswordService) {}

  async initiatePasswordReset(email: string) {
    const uniqueId = await this.passwordService.requestChangePassword({
      email,
      expDurationInHours: 2, // Optional, defaults to 24 hours
    });
    // Send uniqueId to user via email
    return uniqueId;
  }

  async validateResetRequest(uniqueId: string) {
    const request =
      await this.passwordService.validatePasswordRequest(uniqueId);
    if (!request) throw new Error('Invalid or expired request');
    return request;
  }

  async completeReset(id: string) {
    await this.passwordService.invalidateRequest(id);
  }
}

Methods

| Method | Description | | ------------------------------- | --------------------------------------------------------- | | requestChangePassword(params) | Creates a password reset request and returns a unique ID. | | validatePasswordRequest(id) | Validates if a reset request is active and not expired. | | invalidateRequest(id) | Marks a reset request as inactive after use. |

Model

The service uses a ChangePasswordRequest Mongoose model with fields:

  • email: User's email address
  • expiration: Expiry date/time
  • uniqueId: Unique reset token
  • active: Boolean (true if request is valid)

Exports

import {
  ValidateMongoIdPipe,
  TransformInterceptor,
  validatorDto,
} from 'devware-commons/common';

ValidateMongoIdPipe

Validates MongoDB ObjectId format in route parameters.

@Controller('users')
export class UsersController {
  @Get(':id')
  async findOne(@Param('id', ValidateMongoIdPipe) id: string) {
    // id is guaranteed to be a valid MongoDB ObjectId
    return this.usersService.findOne(id);
  }
}

TransformInterceptor

Standardizes API responses with success/error format.

app.useGlobalInterceptors(new TransformInterceptor());

Response Interface

Standard response interface for consistent API responses.

import { Response } from 'devware-commons/common';

// Success response
const successResponse: Response<User> = {
  success: true,
  data: user,
};

// Error response
const errorResponse: Response<null> = {
  success: false,
  status: 400,
  error: { message: 'Invalid input' },
  data: null,
};

validatorDto

Utility function for validating DTOs using class-validator.

import { validatorDto } from 'devware-commons/common';

class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  name: string;
}

async function createUser(data: any) {
  const validData = await validatorDto(CreateUserDto, data);
  // validData is now validated and typed
}

Phone validation REGEX

US_PHONE_NUMBER_REGEX;

Phone validation REGEX

const password = hashPassword(
  password,
  saltOrRounds, // this is optional value: 10
);

Advanced Configuration

Dynamic Configuration with Dependency Injection

You can inject dependencies into module configurations:

@Module({
  imports: [
    MailModule.forRoot({
      params: (configService: ConfigService) => ({
        region: configService.get('AWS_REGION'),
        from: configService.get('DEFAULT_FROM_EMAIL'),
      }),
      options: {
        inject: [ConfigService],
        imports: [ConfigModule],
      },
    }),
  ],
})
export class AppModule {}