
Security News
/Research
Popular node-ipc npm Package Infected with Credential Stealer
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.
@osmanekrem/error-handler
Advanced tools
Advanced error handling utilities for TypeScript applications with middleware, metrics, and monitoring support
Advanced error handling utilities for TypeScript applications with middleware, metrics, and monitoring support.
Quick Start ⢠Documentation ⢠Examples ⢠API Reference ⢠Contributing
| Feature | Description | Status |
|---|---|---|
| š Structured Error Handling | Consistent error types and codes | ā |
| š§ TRPC Integration | Seamless integration with tRPC | ā |
| š”ļø Type Safety | Full TypeScript support | ā |
| š Circuit Breaker | Built-in circuit breaker pattern | ā |
| š Error Metadata | Rich error context and metadata | ā |
| šÆ Factory Functions | Pre-built error creators | ā |
| š Type Guards | Runtime error type checking | ā |
| š Comprehensive Logging | Structured error logging | ā |
| š Framework Middleware | Express.js, Fastify, and Hono support | ā |
| š Error Metrics | Built-in monitoring and analytics | ā |
| š Prometheus Integration | Production-ready metrics | ā |
| šļø Error Dashboard | Real-time error monitoring | ā |
| š Security Features | Context sanitization and sensitive data protection | ā |
| š Retry Strategies | Multiple retry strategies for different scenarios | ā |
| š¦ Error Caching | Deduplication and caching system | ā |
# npm
npm install @osmanekrem/error-handler
# yarn
yarn add @osmanekrem/error-handler
# pnpm
pnpm add @osmanekrem/error-handler
# bun
bun add @osmanekrem/error-handler
# For tRPC integration (optional)
npm install @trpc/server
# For framework integrations (optional)
npm install express fastify hono
import {
AppError,
createError,
errorHandler,
isAppError
} from '@osmanekrem/error-handler';
// Create a structured error
const userError = createError.notFound('User', { userId: '123' });
// Handle errors with context
try {
await riskyOperation();
} catch (error) {
const appError = errorHandler(error, 'user-operation', {
logErrors: true,
sanitizeContext: true
});
throw appError;
}
// Type-safe error checking
if (isAppError(error)) {
console.log('Error code:', error.code);
console.log('Severity:', error.getSeverity());
}
// Express.js
import express from 'express';
import { expressErrorMiddleware } from '@osmanekrem/error-handler';
const app = express();
app.use(expressErrorMiddleware({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development'
}));
// Hono
import { Hono } from 'hono';
import { honoErrorMiddleware } from '@osmanekrem/error-handler';
const app = new Hono();
app.use('*', honoErrorMiddleware({
logErrors: true,
sanitizeContext: true
}));
// Fastify
import Fastify from 'fastify';
import { fastifyErrorPlugin } from '@osmanekrem/error-handler';
const fastify = Fastify();
await fastify.register(fastifyErrorPlugin, {
logErrors: true
});
The AppError class is the foundation of the error handling system:
import { AppError } from '@osmanekrem/error-handler';
const error = new AppError(
'USER_NOT_FOUND', // Error code
'User not found', // Message
404, // HTTP status code
true, // Is operational
{ userId: '123' } // Context
);
// Error properties
console.log(error.code); // 'USER_NOT_FOUND'
console.log(error.statusCode); // 404
console.log(error.isOperational); // true
console.log(error.getSeverity()); // 'medium'
console.log(error.timestamp); // Date object
The library includes 68+ predefined error codes organized by category:
import { ErrorCodes } from '@osmanekrem/error-handler';
// Authentication & Authorization
ErrorCodes.UNAUTHORIZED
ErrorCodes.FORBIDDEN
ErrorCodes.TOKEN_EXPIRED
// Validation
ErrorCodes.VALIDATION_ERROR
ErrorCodes.MISSING_REQUIRED_FIELD
ErrorCodes.INVALID_FORMAT
// Database
ErrorCodes.DATABASE_ERROR
ErrorCodes.CONNECTION_ERROR
ErrorCodes.QUERY_ERROR
// External Services
ErrorCodes.EXTERNAL_SERVICE_ERROR
ErrorCodes.RATE_LIMIT_EXCEEDED
ErrorCodes.SERVICE_UNAVAILABLE
Pre-built error creators for common scenarios:
import { createError } from '@osmanekrem/error-handler';
// Authentication errors
const authError = createError.unauthorized('Invalid token');
const forbiddenError = createError.forbidden('Access denied');
// Validation errors
const validationError = createError.validation('Invalid email format');
const missingField = createError.missingRequiredField('email');
// Resource errors
const notFound = createError.notFound('User', { userId: '123' });
const conflict = createError.conflict('Email already exists');
// Database errors
const dbError = createError.database('Connection failed');
const queryError = createError.queryError('SELECT * FROM users');
// External service errors
const serviceError = createError.external('PaymentService', 'API timeout');
const rateLimit = createError.rateLimitExceeded('API', 60); // retry after 60s
// Business logic errors
const businessError = createError.businessRuleViolation('Insufficient balance');
const quotaError = createError.quotaExceeded('API calls', 1000);
import { BaseCustomError, DatabaseError, ValidationError } from '@osmanekrem/error-handler';
// Database-specific error
const dbError = new DatabaseError('Connection failed', {
host: 'localhost',
port: 5432,
operation: 'connect'
});
// Validation error with field details
const validationError = new ValidationError('Invalid email format', {
field: 'email',
value: 'invalid-email',
expectedFormat: 'user@domain.com'
});
import express from 'express';
import {
expressErrorMiddleware,
asyncHandler,
createError
} from '@osmanekrem/error-handler';
const app = express();
// Global error middleware
app.use(expressErrorMiddleware({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development',
sanitizeContext: true,
onError: (error) => {
// Custom error handling
console.log('Custom error handler:', error.code);
}
}));
// Async route handler
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await getUser(req.params.id);
if (!user) {
throw createError.notFound('User', { userId: req.params.id });
}
res.json(user);
}));
import { Hono } from 'hono';
import {
honoErrorMiddleware,
honoErrorHandler,
createHonoError
} from '@osmanekrem/error-handler';
const app = new Hono();
// Middleware approach
app.use('*', honoErrorMiddleware({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development',
sanitizeContext: true,
includeRequestInfo: true
}));
// Or using onError hook
app.onError(honoErrorHandler({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development'
}));
// Route handlers
app.get('/users/:id', async (c) => {
const user = await getUser(c.req.param('id'));
if (!user) {
throw createHonoError('USER_NOT_FOUND', 'User not found', 404, {
userId: c.req.param('id')
});
}
return c.json(user);
});
import Fastify from 'fastify';
import { fastifyErrorPlugin, createFastifyError } from '@osmanekrem/error-handler';
const fastify = Fastify();
// Register error plugin
await fastify.register(fastifyErrorPlugin, {
logErrors: true,
includeStack: process.env.NODE_ENV === 'development'
});
// Route handlers
fastify.get('/users/:id', async (request, reply) => {
const user = await getUser(request.params.id);
if (!user) {
throw createFastifyError('USER_NOT_FOUND', 'User not found', 404, {
userId: request.params.id
});
}
return user;
});
import { initTRPC } from '@trpc/server';
import { toTRPCError, isAppError } from '@osmanekrem/error-handler';
const t = initTRPC.create();
const userRouter = t.router({
getUser: t.procedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
try {
const user = await getUser(input.id);
if (!user) {
throw createError.notFound('User', { userId: input.id });
}
return user;
} catch (error) {
if (isAppError(error)) {
throw toTRPCError(error);
}
throw error;
}
})
});
import { CircuitBreaker } from '@osmanekrem/error-handler';
const circuitBreaker = new CircuitBreaker({
failureThreshold: 5, // Open after 5 failures
recoveryTimeout: 60000, // 1 minute recovery time
monitoringPeriod: 10000, // 10 seconds monitoring
halfOpenMaxCalls: 3 // Max calls in half-open state
});
// Execute with circuit breaker protection
try {
const result = await circuitBreaker.execute(
() => callExternalService(),
'external-service'
);
} catch (error) {
if (error.code === 'SERVICE_UNAVAILABLE') {
// Circuit breaker is open
console.log('Service is down, using fallback');
}
}
// Monitor circuit breaker state
console.log('State:', circuitBreaker.getState());
console.log('Healthy:', circuitBreaker.isHealthy());
console.log('Stats:', circuitBreaker.getStats());
import { ErrorMetrics, PrometheusMetrics } from '@osmanekrem/error-handler';
const metrics = new ErrorMetrics({
enablePrometheus: true,
customLabels: { service: 'user-service' },
retentionPeriod: 24 * 60 * 60 * 1000, // 24 hours
maxErrors: 10000
});
// Record errors
metrics.recordError(error, {
service: 'user-service',
userId: '123',
requestId: 'req-456'
});
// Get statistics
const stats = metrics.getStats();
console.log('Total errors:', stats.totalErrors);
console.log('Error rate:', stats.errorRate);
console.log('Top errors:', stats.topErrors);
// Prometheus metrics
const prometheus = new PrometheusMetrics({
serviceName: 'user-service',
version: '1.0.0'
});
// Export metrics for Prometheus
app.get('/metrics', (req, res) => {
res.set('Content-Type', 'text/plain');
res.send(prometheus.export());
});
import {
retry,
RetryStrategy,
DatabaseRetryStrategy,
ApiRetryStrategy
} from '@osmanekrem/error-handler';
// Basic retry
const result = await retry(
() => riskyOperation(),
{ maxAttempts: 3, delay: 1000 }
);
// Database retry strategy
const dbRetry = new DatabaseRetryStrategy({
maxAttempts: 5,
baseDelay: 1000,
maxDelay: 10000,
backoffMultiplier: 2
});
const user = await dbRetry.execute(() => getUserFromDB(id));
// API retry strategy
const apiRetry = new ApiRetryStrategy({
maxAttempts: 3,
baseDelay: 500,
maxDelay: 5000,
retryableStatusCodes: [500, 502, 503, 504]
});
const data = await apiRetry.execute(() => callExternalAPI());
import { ErrorCache, DeduplicationService } from '@osmanekrem/error-handler';
const errorCache = new ErrorCache({
maxSize: 1000,
ttl: 300000, // 5 minutes
cleanupInterval: 60000 // 1 minute
});
const deduplication = new DeduplicationService({
windowSize: 60000, // 1 minute
maxDuplicates: 10
});
// Cache errors
errorCache.set('user-123', error);
// Deduplicate errors
const result = await deduplication.processError(error, {
userId: '123',
operation: 'getUser'
});
if (result.isDuplicate) {
console.log('Duplicate error detected');
} else {
console.log('New error, processing...');
}
import {
createError,
errorHandler,
CircuitBreaker,
ErrorMetrics
} from '@osmanekrem/error-handler';
class OrderService {
private circuitBreaker = new CircuitBreaker();
private metrics = new ErrorMetrics();
async createOrder(orderData: OrderData) {
try {
// Validate order data
this.validateOrderData(orderData);
// Check inventory with circuit breaker
const inventory = await this.circuitBreaker.execute(
() => this.checkInventory(orderData.items),
'inventory-service'
);
// Process payment
const payment = await this.processPayment(orderData.payment);
// Create order
const order = await this.saveOrder(orderData);
return order;
} catch (error) {
const appError = errorHandler(error, 'create-order', {
logErrors: true,
sanitizeContext: true
});
this.metrics.recordError(appError, {
service: 'order-service',
operation: 'createOrder'
});
throw appError;
}
}
private validateOrderData(data: OrderData) {
if (!data.items || data.items.length === 0) {
throw createError.validation('Order must contain at least one item');
}
if (!data.payment) {
throw createError.missingRequiredField('payment');
}
if (data.total <= 0) {
throw createError.businessRuleViolation('Order total must be greater than 0');
}
}
private async checkInventory(items: OrderItem[]) {
// External service call
const response = await fetch('/api/inventory/check', {
method: 'POST',
body: JSON.stringify({ items })
});
if (!response.ok) {
throw createError.external('InventoryService', 'Failed to check inventory');
}
return response.json();
}
}
import {
createError,
CircuitBreaker,
retry,
ApiRetryStrategy
} from '@osmanekrem/error-handler';
class UserService {
private userCircuitBreaker = new CircuitBreaker({
failureThreshold: 3,
recoveryTimeout: 30000
});
private paymentRetry = new ApiRetryStrategy({
maxAttempts: 3,
baseDelay: 1000,
retryableStatusCodes: [500, 502, 503, 504]
});
async getUserWithPaymentInfo(userId: string) {
try {
// Get user with circuit breaker protection
const user = await this.userCircuitBreaker.execute(
() => this.getUser(userId),
'user-service'
);
if (!user) {
throw createError.notFound('User', { userId });
}
// Get payment info with retry strategy
const paymentInfo = await this.paymentRetry.execute(
() => this.getPaymentInfo(userId),
'payment-service'
);
return {
...user,
paymentInfo
};
} catch (error) {
if (error.code === 'SERVICE_UNAVAILABLE') {
// Circuit breaker is open, return cached data
return this.getCachedUser(userId);
}
throw error;
}
}
}
The main error class with structured error handling.
import { AppError } from '@osmanekrem/error-handler';
const error = new AppError(
'USER_NOT_FOUND',
'User not found',
404,
true, // isOperational
{ userId: '123' } // context
);
// Check error properties
console.log(error.code); // 'USER_NOT_FOUND'
console.log(error.statusCode); // 404
console.log(error.isOperational); // true
console.log(error.getSeverity()); // 'medium'
Pre-built error creators for common scenarios.
import { createError } from '@osmanekrem/error-handler';
// Authentication errors
const authError = createError.unauthorized('Invalid token');
const forbiddenError = createError.forbidden('Access denied');
// Validation errors
const validationError = createError.validation('Invalid email format');
const missingField = createError.missingRequiredField('email');
// Resource errors
const notFound = createError.notFound('User', { userId: '123' });
const conflict = createError.conflict('Email already exists');
// Database errors
const dbError = createError.database('Connection failed');
const queryError = createError.queryError('SELECT * FROM users');
// External service errors
const serviceError = createError.external('PaymentService', 'API timeout');
const rateLimit = createError.rateLimitExceeded('API', 60); // retry after 60s
Convert AppError to TRPCError for tRPC compatibility.
import { toTRPCError } from '@osmanekrem/error-handler';
import { TRPCError } from '@trpc/server';
try {
// Some operation
} catch (error) {
if (isAppError(error)) {
throw toTRPCError(error);
}
throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unknown error' });
}
Global error handler with logging and context.
import { errorHandler, withErrorHandling } from '@osmanekrem/error-handler';
// Manual error handling
try {
// Some operation
} catch (error) {
const appError = errorHandler(error, 'user-operation', {
logErrors: true,
logLevel: 'error',
includeStack: true,
sanitizeContext: true,
});
throw appError;
}
// Higher-order function
const safeOperation = withErrorHandling(
async (userId: string) => {
// Risky operation
return await getUser(userId);
},
'get-user',
{ logErrors: true }
);
Protect against cascading failures.
import { CircuitBreaker } from '@osmanekrem/error-handler';
const circuitBreaker = new CircuitBreaker({
failureThreshold: 5,
recoveryTimeout: 60000, // 1 minute
halfOpenMaxCalls: 3,
});
// Execute with circuit breaker protection
try {
const result = await circuitBreaker.execute(
() => callExternalService(),
'external-service'
);
} catch (error) {
// Handle circuit breaker errors
}
// Check circuit breaker state
console.log(circuitBreaker.getState());
console.log(circuitBreaker.isHealthy());
console.log(circuitBreaker.getStats());
Runtime error type checking.
import { isAppError, isAppErrorWithCode, isRetryableAppError } from '@osmanekrem/error-handler';
try {
// Some operation
} catch (error) {
if (isAppError(error)) {
console.log('AppError:', error.code);
}
if (isAppErrorWithCode(error, 'USER_NOT_FOUND')) {
// Handle specific error
}
if (isRetryableAppError(error)) {
// Retry logic
}
}
Seamless integration with Hono framework.
import { Hono } from 'hono';
import { honoErrorMiddleware, honoErrorHandler, createHonoError } from '@osmanekrem/error-handler';
const app = new Hono();
// Using middleware approach
app.use('*', honoErrorMiddleware({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development',
sanitizeContext: true
}));
// Or using onError hook
app.onError(honoErrorHandler({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development'
}));
// Route handlers
app.get('/users/:id', async (c) => {
const user = await getUser(c.req.param('id'));
if (!user) {
throw createHonoError('USER_NOT_FOUND', 'User not found', 404, {
userId: c.req.param('id')
});
}
return c.json(user);
});
app.post('/users', async (c) => {
const body = await c.req.json();
if (!body.email) {
throw createHonoError('MISSING_REQUIRED_FIELD', 'Email is required', 400, {
field: 'email'
});
}
// Create user logic
return c.json({ success: true });
});
The library includes predefined error codes for consistency:
UNAUTHORIZED - Authentication requiredFORBIDDEN - Access deniedTOKEN_EXPIRED - Token has expiredINVALID_TOKEN - Invalid tokenINSUFFICIENT_PERMISSIONS - Insufficient permissionsVALIDATION_ERROR - Validation failedINVALID_INPUT - Invalid input providedMISSING_REQUIRED_FIELD - Required field is missingINVALID_FORMAT - Invalid formatNOT_FOUND - Resource not foundCONFLICT - Resource conflictDUPLICATE_RESOURCE - Resource already existsRESOURCE_LOCKED - Resource is lockedRESOURCE_EXPIRED - Resource has expiredDATABASE_ERROR - Database operation failedCONNECTION_ERROR - Database connection failedQUERY_ERROR - Database query failedTRANSACTION_ERROR - Database transaction failedCONSTRAINT_VIOLATION - Database constraint violationEXTERNAL_SERVICE_ERROR - External service errorSERVICE_UNAVAILABLE - Service temporarily unavailableRATE_LIMIT_EXCEEDED - Rate limit exceededAPI_ERROR - API error occurredINTERNAL_SERVER_ERROR - Internal server errorTIMEOUT - Operation timed outMEMORY_ERROR - Memory error occurredDISK_ERROR - Disk error occurredNETWORK_ERROR - Network error occurredEach error includes metadata for monitoring and alerting:
import { getErrorMetadata } from '@osmanekrem/error-handler';
const metadata = getErrorMetadata(error);
console.log(metadata);
// {
// code: 'USER_NOT_FOUND',
// severity: 'medium',
// category: 'resource',
// retryable: false,
// userMessage: 'User not found',
// isOperational: true,
// statusCode: 404,
// timestamp: Date
// }
// ā
Good - Structured and informative
throw createError.notFound('User', {
userId: '123',
operation: 'getUser',
timestamp: new Date().toISOString()
});
// ā Bad - Generic and unhelpful
throw new Error('User not found');
// ā
Good - Rich context for debugging
throw createError.database('Query failed', {
query: 'SELECT * FROM users WHERE id = ?',
parameters: ['123'],
userId: '123',
operation: 'getUser',
database: 'postgres',
connectionId: 'conn-456'
});
// ā Bad - Minimal context
throw createError.database('Query failed');
// ā
Good - Protected external calls
const circuitBreaker = new CircuitBreaker();
const result = await circuitBreaker.execute(
() => callExternalAPI(),
'external-service'
);
// ā Bad - No protection
const result = await callExternalAPI();
// ā
Good - Comprehensive error handling
try {
const user = await getUser(id);
} catch (error) {
if (isAppErrorWithCode(error, 'USER_NOT_FOUND')) {
return { success: false, message: 'User not found' };
}
if (isRetryableAppError(error)) {
// Implement retry logic
return retry(() => getUser(id), { maxAttempts: 3 });
}
throw errorHandler(error, 'getUser', {
logErrors: true,
sanitizeContext: true
});
}
// ā Bad - Poor error handling
try {
const user = await getUser(id);
} catch (error) {
console.log(error); // Just logging
}
// ā
Good - Type-safe error checking
if (isAppError(error)) {
console.log('Error code:', error.code);
console.log('Severity:', error.getSeverity());
if (error.isTypeOf('USER_NOT_FOUND')) {
// Handle specific error type
}
}
// ā Bad - Unsafe error checking
if (error.code === 'USER_NOT_FOUND') {
// TypeScript error - error might not have code property
}
// ā
Good - Comprehensive monitoring
const metrics = new ErrorMetrics({
enablePrometheus: true,
customLabels: { service: 'user-service' }
});
try {
await riskyOperation();
} catch (error) {
const appError = errorHandler(error, 'risky-operation');
metrics.recordError(appError, {
service: 'user-service',
userId: '123',
requestId: 'req-456'
});
throw appError;
}
// ā
Good - Appropriate error codes
if (!user) {
throw createError.notFound('User', { userId });
}
if (!isValidEmail(email)) {
throw createError.invalidFormat('email', 'user@domain.com');
}
if (balance < amount) {
throw createError.insufficientFunds(amount, balance);
}
// ā Bad - Generic error codes
if (!user) {
throw createError.internal('User not found');
}
Problem: TypeScript can't find module types
// Error: Cannot find module '@osmanekrem/error-handler'
Solution: Ensure proper installation and TypeScript configuration
npm install @osmanekrem/error-handler
# or
yarn add @osmanekrem/error-handler
Problem: Circuit breaker always returns errors
// Circuit breaker is always OPEN
Solution: Check configuration and failure threshold
const circuitBreaker = new CircuitBreaker({
failureThreshold: 5, // Increase if needed
recoveryTimeout: 60000, // Check timeout value
monitoringPeriod: 10000 // Adjust monitoring period
});
Problem: Sensitive data in error logs
// Password appears in error context
Solution: Enable context sanitization
const appError = errorHandler(error, 'operation', {
sanitizeContext: true // Enable sanitization
});
Problem: Error metrics not being recorded
// metrics.getStats() returns empty data
Solution: Ensure metrics are properly initialized and errors are recorded
const metrics = new ErrorMetrics({
enablePrometheus: true,
retentionPeriod: 24 * 60 * 60 * 1000
});
// Record errors explicitly
metrics.recordError(error, { service: 'my-service' });
Enable debug mode for detailed error information:
const appError = errorHandler(error, 'operation', {
logErrors: true,
logLevel: 'debug',
includeStack: true
});
If you experience performance issues:
const appError = errorHandler(error, 'operation', {
includeStack: process.env.NODE_ENV === 'development'
});
const errorCache = new ErrorCache({
maxSize: 1000, // Reduce if needed
ttl: 300000 // 5 minutes
});
// Batch errors for better performance
const errorBatcher = new ErrorBatcher({
batchSize: 100,
flushInterval: 5000
});
Before:
try {
const user = await getUser(id);
} catch (error) {
console.error('Error:', error.message);
throw new Error('User not found');
}
After:
import { createError, errorHandler } from '@osmanekrem/error-handler';
try {
const user = await getUser(id);
} catch (error) {
const appError = errorHandler(error, 'getUser', {
logErrors: true,
sanitizeContext: true
});
throw appError;
}
Before:
app.use((error, req, res, next) => {
console.error(error);
res.status(500).json({ error: 'Internal server error' });
});
After:
import { expressErrorMiddleware } from '@osmanekrem/error-handler';
app.use(expressErrorMiddleware({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development'
}));
Before:
class UserNotFoundError extends Error {
constructor(userId: string) {
super(`User not found: ${userId}`);
this.name = 'UserNotFoundError';
}
}
After:
import { createError } from '@osmanekrem/error-handler';
// Use factory function
throw createError.notFound('User', { userId });
| Operation | Time (ms) | Memory (MB) |
|---|---|---|
| Create AppError | 0.01 | 0.1 |
| Error Handler | 0.05 | 0.2 |
| Circuit Breaker | 0.02 | 0.3 |
| Error Metrics | 0.03 | 0.5 |
| Error Caching | 0.01 | 0.2 |
// Monitor memory usage
const metrics = new ErrorMetrics({
maxErrors: 10000, // Limit error records
retentionPeriod: 24 * 60 * 60 * 1000 // 24 hours
});
// Clean up old errors
setInterval(() => {
metrics.reset();
}, 24 * 60 * 60 * 1000); // Reset every 24 hours
We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/osmanekrem/error-handler.git
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build the project
npm run build
# Run linting
npm run lint
MIT License - see LICENSE file for details.
Made with ā¤ļø by Osman Ekrem
FAQs
Advanced error handling utilities for TypeScript applications with middleware, metrics, and monitoring support
The npm package @osmanekrem/error-handler receives a total of 21 weekly downloads. As such, @osmanekrem/error-handler popularity was classified as not popular.
We found that @osmanekrem/error-handler demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Ā It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.

Security News
TeamPCP and BreachForums are promoting a Shai-Hulud supply chain attack contest with a $1,000 prize for the biggest package compromise.

Security News
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.