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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hiennc24/common

v2.2.12

Published

Production-ready TypeScript utilities for Node.js: multi-tenant database management, NoSQL injection protection, error handling, validation, caching, and more. Battle-tested with 188/188 tests.

Readme

Stop Writing Boilerplate. Start Shipping Features.

Production-ready TypeScript utilities that eliminate 1000+ lines of repetitive code from your Node.js projects.

npm version tests TypeScript license

🚀 Quick Start

import { NotFoundError, sanitizeMongoFilter, CacheManager } from '@hiennc24/common';

// Production-ready error handling in one line
throw new NotFoundError('User not found', 'USER_NOT_FOUND', { userId: '123' });

// NoSQL injection protection built-in
const safeFilter = sanitizeMongoFilter(userInput); // Automatically strips $where, $function, etc.

// Multi-tenant caching without the headache
const cache = new CacheManager(redisClient, logger, 'user-service');

🎯 Why @hiennc24/common?

Because every Node.js project needs the same 80% of utilities, but nobody wants to write them twice.

  • Zero compromises on security - Built-in NoSQL injection prevention with circular reference protection
  • Battle-tested reliability - 188/188 tests passing, production-ready since v1.0
  • Type-safe by design - Full TypeScript definitions with intelligent autocomplete
  • Multi-tenant ready - Database connections and caching with tenant isolation out of the box
  • Actually maintained - Regular security audits, zero known vulnerabilities
  • Tree-shakeable - Import only what you need, ESM + CommonJS support

📦 Installation

npm install @hiennc24/common

No peer dependencies. Works with Express, NestJS, Fastify, or any Node.js framework.


💡 Core Features

🛡️ Production-Ready Error Handling

Stop writing custom error classes. Get 10 HTTP-aware errors with proper TypeScript types and prototype chains.

Before @hiennc24/common:

// 30+ lines of boilerplate per error class
class NotFoundError extends Error {
  public code: number;
  public details?: any;
  constructor(message: string, details?: any) {
    super(message);
    this.name = 'NotFoundError';
    this.code = 404;
    this.details = details;
    Object.setPrototypeOf(this, NotFoundError.prototype);
  }
}
// Repeat for ValidationError, UnauthorizedError, ServerError...

After @hiennc24/common:

import {
  NotFoundError,
  ValidationError,
  UnauthorizedError,
  ErrorFactory
} from '@hiennc24/common';

// Use directly
throw new NotFoundError('User not found', 'USER_NOT_FOUND', { userId: '123' });

// Or use the factory for common patterns
throw ErrorFactory.createNotFoundError('User', userId, { requestId });
throw ErrorFactory.createValidationError('Invalid email', ['email'], { value });

Includes: ServerError, NotFoundError, ValidationError, UnauthorizedError, PermissionDeniedError, BadRequestError, ConflictError, AlreadyExistsError, TooManyRequestsError, ServiceUnavailableError


🔒 Built-in Security Against NoSQL Injection

Your MongoDB queries are only as secure as your input sanitization.

import { sanitizeMongoFilter } from '@hiennc24/common';

// Dangerous user input
const maliciousInput = {
  email: '[email protected]',
  $where: 'this.password.length > 0', // 🚨 Injection attempt - blocked
  $function: { body: 'return true' }   // 🚨 Code execution - blocked
};

// Automatically strips dangerous operators
const safeFilter = sanitizeMongoFilter(maliciousInput);
// Result: { email: '[email protected]' } ✅

// Handles circular references (prevents DoS)
const circular: any = { a: 1 };
circular.self = circular;
sanitizeMongoFilter(circular); // Won't crash your app ✅

Protects against: $where, $function, $expr, $accumulator, $mapReduce, group, and other code execution operators. Safe query operators like $ne, $regex, $in are allowed.


🗄️ Multi-Tenant Database Management

Managing connections for 100+ tenants? ConnectMultipleDB handles caching, retry logic, and automatic cleanup.

import { ConnectMultipleDB } from '@hiennc24/common';

const dbManager = new ConnectMultipleDB(
  logger,
  redisCache,
  { getConnectionString: async (domain) => fetchFromVault(domain) },
  { maxPoolSize: 10, maxConnecting: 5 }
);

// Automatically caches connections per tenant
const tenantA_DB = await dbManager.getConnection('tenant-a.com');
const tenantB_DB = await dbManager.getConnection('tenant-b.com');

// Auto-closes idle connections after 2 hours (configurable)
// Retry logic with exponential backoff built-in

Features:

  • Connection pooling per tenant
  • Redis-backed caching (1-hour TTL)
  • Automatic idle connection cleanup
  • Configurable retry attempts (default: 5)
  • Domain validation and encryption support

✅ Type-Safe Validation Service

Stop repeating the same null checks and type guards.

import { ValidationService } from '@hiennc24/common';

// Before: Manual validation everywhere
if (!entity || typeof entity !== 'object') {
  throw new Error('Invalid entity');
}
if (!filter || typeof filter !== 'object') {
  throw new Error('Invalid filter');
}

// After: One-liner validation with context
ValidationService.validateEntity(entity, 'createUser');
ValidationService.validateFilter(filter, 'findUsers');
ValidationService.validateCondition(condition, 'updateUser');
ValidationService.validatePipeline(pipeline, 'aggregateData');

// Throws ValidationError with method context for better debugging

🎯 MongoDB-Style Field Projection

Filter entity fields like MongoDB projections, but for plain JavaScript objects.

import { FieldProjector } from '@hiennc24/common';

const user = {
  id: '123',
  email: '[email protected]',
  password: 'hashed_password',
  role: 'admin',
  createdAt: new Date()
};

// Include only specific fields (MongoDB-style)
const publicUser = FieldProjector.project(user, 'id email role');
// { id: '123', email: '[email protected]', role: 'admin' }

// Exclude sensitive fields
const safeUser = FieldProjector.project(user, '-password -createdAt');
// { id: '123', email: '[email protected]', role: 'admin' }

// Object notation also supported
const projected = FieldProjector.project(user, { email: 1, role: 1 });

Perfect for: API responses, logging sanitization, DTOs, GraphQL resolvers


⚡ Smart Caching with Multi-Tenancy

Redis caching that understands your multi-tenant architecture.

import { CacheManager } from '@hiennc24/common';

const cache = new CacheManager<User>(
  redisClient,
  logger,
  'user-service',
  'tenant-a.com' // Automatic tenant isolation
);

// Cache with automatic key generation
await cache.set('user:123', userData, { ttl: 3600 });

// Get with type safety
const user = await cache.get<User>('user:123');

// Tenant-specific keys automatically
// Actual Redis key: "tenant-a.com:user-service:user:123"

Features:

  • Automatic tenant isolation
  • Release version support (cache invalidation on deploy)
  • Reference-based caching for complex objects
  • Type-safe generics
  • Development mode bypass

🔐 AES Encryption Utilities

Simple, secure encryption for configuration and secrets.

import { Crypto } from '@hiennc24/common';

const encrypted = Crypto.encrypt('sensitive-data', 'your-secret-key');
const decrypted = Crypto.decrypt(encrypted, 'your-secret-key');

// Perfect for: API keys in config, connection strings, tokens

📝 Structured Logging with Winston

Pre-configured Winston logger with context support.

import { logger } from '@hiennc24/common';

logger.info('User created', { userId: '123', email: '[email protected]' });
logger.error('Database error', { error: err.message, stack: err.stack });
logger.warn('Rate limit approaching', { requests: 95, limit: 100 });

🛠️ Essential Helpers

Utilities you copy-paste between projects.

import {
  isChanged,
  findChangedValue,
  waitByPromise,
  isUndefinedOrNull,
  isStringAndNotEmpty
} from '@hiennc24/common';

// Detect changes between objects
const hasChanges = isChanged(originalUser, updatedUser);

// Find exactly what changed
const delta = findChangedValue(originalUser, updatedUser);
// { email: '[email protected]', role: 'admin' }

// Async sleep
await waitByPromise(1000); // Wait 1 second

// Type guards
if (isStringAndNotEmpty(value)) {
  // TypeScript knows value is string
}

🧪 Battle-Tested Quality

  • 188/188 tests passing - Comprehensive test coverage for every feature
  • 100% TypeScript - Full type definitions with zero any abuse
  • Zero security vulnerabilities - Regular audits with npm audit
  • Production-ready - Used in multi-tenant SaaS platforms since v1.0
  • Actively maintained - Security patches within 48 hours

📚 Full API Reference

Error Classes

  • AppError - Base error class with enhanced details
  • ServerError (500) - Internal server errors
  • NotFoundError (404) - Resource not found
  • ValidationError (400) - Input validation failed
  • UnauthorizedError (401) - Authentication required
  • PermissionDeniedError (403) - Insufficient permissions
  • BadRequestError (400) - Invalid request format
  • ConflictError (409) - Resource conflict
  • AlreadyExistsError (422) - Resource already exists
  • TooManyRequestsError (429) - Rate limit exceeded
  • ServiceUnavailableError (503) - Service unavailable

Error Utilities

  • ErrorUtils.createErrorResponse() - Standardized error responses
  • ErrorUtils.isOperationalError() - Distinguish operational vs programming errors
  • ErrorFactory.createValidationError() - Validation errors with field context
  • ErrorFactory.createAuthError() - Authentication errors
  • ErrorFactory.createNotFoundError() - Resource not found errors

Security

  • sanitizeMongoFilter(filter) - Remove dangerous MongoDB operators
  • Crypto.encrypt(data, key) - AES encryption
  • Crypto.decrypt(data, key) - AES decryption

Database

  • ConnectMultipleDB - Multi-tenant database connection manager
    • getConnection(domain) - Get/create connection for tenant
    • closeConnection(domain) - Close specific connection
    • closeAllConnections() - Cleanup all connections

Validation

  • ValidationService.validateEntity() - Validate entity objects
  • ValidationService.validateFilter() - Validate filter objects
  • ValidationService.validateCondition() - Validate query conditions
  • ValidationService.validatePipeline() - Validate aggregation pipelines

Field Projection

  • FieldProjector.project(entity, projection) - Apply MongoDB-style field filtering

Caching

  • CacheManager<T> - Redis caching with multi-tenancy
    • set(key, value, options) - Cache data
    • get<T>(key) - Retrieve cached data
    • delete(key) - Remove from cache
    • clear() - Clear all cache

Helpers

  • isChanged(source, dest) - Deep equality check
  • findChangedValue(source, dest) - Find changed properties
  • waitByPromise(ms) - Async sleep
  • isUndefinedOrNull(value) - Type guard for null/undefined
  • isStringAndNotEmpty(value) - Type guard for non-empty strings
  • generateTimestamp() - Get current timestamp

Logging

  • logger.info(), logger.error(), logger.warn(), logger.debug() - Winston-based logging

🤝 Contributing

Found a bug? Have a feature request? Contributions welcome!

  1. Fork the repository: https://github.com/hiennc24/common
  2. Create your feature branch: git checkout -b feature/amazing-feature
  3. Run tests: npm test (all 188 must pass)
  4. Commit changes: git commit -m 'Add amazing feature'
  5. Push to branch: git push origin feature/amazing-feature
  6. Open a Pull Request

Before submitting:

  • Add tests for new features
  • Ensure TypeScript types are correct
  • Update documentation if needed

🐛 Issues & Support

  • Bug Reports: GitHub Issues
  • Security Issues: Email author directly (see package.json)
  • Questions: Open a discussion on GitHub

📄 License

ISC License - Copyright (c) Hien Nguyen

See LICENSE for details.


🌟 Support This Project

If @hiennc24/common saves you from writing boilerplate, give it a star on GitHub!

Star on GitHub

Every star helps other developers discover this package and motivates continued maintenance.


📦 Package Stats

  • Bundle Size: Tree-shakeable ESM + CommonJS
  • Dependencies: 6 production dependencies (axios, cron, crypto-js, express, lodash, winston)
  • Node Version: 14+ (TypeScript 4.9+)
  • Framework Agnostic: Works with Express, NestJS, Fastify, Koa, etc.

Stop reinventing the wheel. Start with @hiennc24/common.

npm install @hiennc24/common