A comprehensive utility library for Node.js applications providing error handling, logging, data manipulation, and common utility functions.
- Overview
- Installation
- Features
- Architecture
- API Reference
- Usage Examples
- Development
- Testing
- Contributing
- License
@lazy-js/utils is a TypeScript-based utility library designed to provide common functionality needed in modern Node.js applications. It includes robust error handling, structured logging, data merging capabilities, pagination utilities, and response formatting helpers.
npm install @lazy-js/utils- Error Handling: Structured error classes with HTTP status codes and categorization
- Logging: Configurable logger with multiple log levels and formatting options
- Data Merging: Deep merge functionality with configurable array handling strategies
- Pagination: Comprehensive pagination utilities for API responses
- Response Formatting: Standardized success/error response structures
- Utility Functions: Type checking and data validation helpers
- Generators: Mock data generators for testing and development
The library follows a modular architecture with clear separation of concerns:
graph TB
A[Main Index] --> B[Errors Module]
A --> C[Logger Module]
A --> D[Merge Module]
A --> E[Pagination Module]
A --> F[Responses Module]
A --> G[Generators Module]
A --> H[Utility Functions]
B --> B1[AppError Class]
B --> B2[Error Constants]
B --> B3[Error Converters]
B --> B4[Zod Error Handler]
C --> C1[Logger Class]
C --> C2[Log Levels]
C --> C3[Formatting Options]
D --> D1[Deep Merge]
D --> D2[Array Merge Strategies]
D --> D3[ID-based Merging]
E --> E1[Pagination Class]
E --> E2[Page Calculation]
E --> E3[Response Formatting]
F --> F1[Success Response]
F --> F2[Error Response]
F --> F3[Pagination Integration]
G --> G1[Random Hex Generator]
G --> G2[Mock ObjectId]
H --> H1[isEmptyArray]
H --> H2[isObject]
A structured error class that extends the native Error with additional metadata:
class AppError extends Error {
public code: string; // Error code identifier
public statusCode?: number; // HTTP status code
public label?: string; // Human readable label
public service: string; // Service name where error occurred
public category?: string; // Error category
public date: Date; // Timestamp of error
public originalService?: string;
}Predefined error configurations for common scenarios:
// General errors
generalErrors.PATH_NOT_FOUND; // 404 - Requested URL not found
generalErrors.INTERNAL_SERVER_ERROR; // 500 - Internal server error
// Axios/Network errors
axiosErrors.REQUEST_TIMEOUT; // 408 - Request timed out
axiosErrors.SERVER_NOT_REACHABLE; // 503 - Server is not reachable
axiosErrors.TOO_MANY_REDIRECTS; // 310 - Too many redirectsConvert any error to a structured AppError:
import { convertAnyErrorToAppError } from '@lazy-js/utils';
try {
// Some operation that might fail
} catch (error) {
const appError = convertAnyErrorToAppError(error, 'user-service');
}A configurable logger with multiple log levels and formatting options:
import { Logger } from '@lazy-js/utils';
const logger = new Logger({
module: 'user-service',
timestampFormat: 'iso',
colorize: true,
servicName: 'api-gateway',
});
logger.info('User created successfully');
logger.error('Failed to create user', error);
logger.debug('Processing user data', { userId: 123 });- Multiple Log Levels: ERROR, WARN, INFO, DEBUG
- Timestamp Formats: ISO, locale, or none
- Colorized Output: ANSI color codes for better readability
- Module Support: Hierarchical logging with module names
- Console Methods: Group, table, time measurement support
Advanced merging functionality with configurable array handling:
import { deepMergeWithOptions } from '@lazy-js/utils';
const result = deepMergeWithOptions(existingData, updateData, {
idKey: '_id',
arrayMergeStrategy: 'merge', // 'merge' | 'replace' | 'append'
generateIds: true,
idGenerator: () => new MockObjectId().toString(),
});- merge: Intelligently merge arrays based on ID matching
- replace: Replace entire arrays
- append: Concatenate arrays
Comprehensive pagination utilities:
import { Pagination } from '@lazy-js/utils';
const pagination = new Pagination({ page: 1, limit: 10 });
pagination.setTotalResults(150);
const response = pagination.getPaginationResponse();
// Returns: {
// totalResults: 150,
// currentPage: 1,
// totalPages: 15,
// countPerPage: 10,
// firstPage: 1,
// lastPage: 15,
// isFirstPage: true,
// isLastPage: false
// }import { success, error } from '@lazy-js/utils';
// Success response
const successResponse = success(data, pagination);
// Error response
const errorResponse = error(errorObject);import { isEmptyArray, isObject } from '@lazy-js/utils';
isEmptyArray([]); // true
isEmptyArray([1, 2, 3]); // false
isObject({}); // true
isObject(null); // false
isObject([]); // trueimport { randomHex, MockObjectId } from '@lazy-js/utils';
randomHex(16); // "a1b2c3d4e5f6g7h8"
const mockId = new MockObjectId(); // Generates 24-char hex stringimport { AppError, convertAnyErrorToAppError, Logger } from '@lazy-js/utils';
const logger = Logger.create('user-service');
async function createUser(userData: any) {
try {
// Simulate API call
const response = await api.createUser(userData);
logger.info('User created successfully', { userId: response.id });
return response;
} catch (error) {
const appError = convertAnyErrorToAppError(error, 'user-service');
logger.error('Failed to create user', appError);
throw appError;
}
}import { deepMergeWithOptions, MockObjectId } from '@lazy-js/utils';
const existingUsers = [
{ _id: '1', name: 'John', age: 30 },
{ _id: '2', name: 'Jane', age: 25 },
];
const updates = [
{ _id: '1', age: 31 },
{ name: 'Bob', age: 28 },
];
const mergedUsers = deepMergeWithOptions(existingUsers, updates, {
idKey: '_id',
generateIds: true,
idGenerator: () => new MockObjectId().toString(),
});
// Result: Updated John (age: 31), Jane unchanged, new Bob with generated IDimport { success, error, Pagination } from '@lazy-js/utils';
export async function getUsers(req: Request, res: Response) {
try {
const { page = 1, limit = 10 } = req.query;
const pagination = new Pagination({
page: Number(page),
limit: Number(limit),
});
const users = await userService.getUsers(pagination);
const total = await userService.getUserCount();
pagination.setTotalResults(total);
res.json(success(users, pagination));
} catch (err) {
const appError = convertAnyErrorToAppError(err, 'user-service');
res.status(appError.statusCode || 500).json(error(appError));
}
}- Node.js 16+
- npm or yarn
# Clone the repository
git clone <repository-url>
cd lazy-js-utils
# Install dependencies
npm install
# Build the project
npm run build
# Development mode with watch
npm run devnpm run build- Build both ESM and CommonJS versionsnpm run build:esm- Build ESM version onlynpm run build:cjs- Build CommonJS version onlynpm run dev- Development mode with file watching
src/
βββ index.ts # Main entry point
βββ utils/
β βββ errors/ # Error handling utilities
β βββ generators/ # Data generators
β βββ is-empty-array/ # Array validation
β βββ is-object/ # Object validation
β βββ logger/ # Logging system
β βββ merge/ # Data merging utilities
β βββ pagination/ # Pagination helpers
β βββ responses/ # Response formatting
The project uses Vitest for testing:
# Run tests
npm test
# Run tests in watch mode
npm run test:watchThe test suite covers:
- Error handling and conversion
- Data merging logic
- Pagination calculations
- Logger functionality
- Utility functions
graph LR
A[Main Index] --> B[Errors]
A --> C[Logger]
A --> D[Merge]
A --> E[Pagination]
A --> F[Responses]
A --> G[Generators]
A --> H[Utilities]
D --> I[lodash.clonedeep]
D --> J[lodash.mergewith]
D --> K[lodash.isarray]
D --> H
F --> E
G --> L[randomHex]
H --> M[isEmptyArray]
H --> N[isObject]
style A fill:#e1f5fe
style D fill:#f3e5f5
style C fill:#e8f5e8
style B fill:#fff3e0
The project includes multiple TypeScript configurations:
tsconfig.json- ESM build configurationtsconfig.cjs.json- CommonJS build configurationtsconfig.test.json- Test configuration
- ESM:
dist/esm/- Modern ES modules - CommonJS:
dist/cjs/- Node.js compatibility - Types:
dist/types/- TypeScript declarations
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow TypeScript best practices
- Add tests for new functionality
- Update documentation as needed
- Ensure all tests pass before submitting
This project is licensed under the ISC License - see the LICENSE file for details.
For support and questions:
- Open an issue on GitHub
- Check existing documentation
- Review test examples for usage patterns
Built with β€οΈ for the Node.js community