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

@egintegrations/core-utils

v0.1.0

Published

Foundational TypeScript utilities for retry logic, error handling, health checks, and idempotency. Designed for use across API, BOT, and service applications with zero external dependencies.

Downloads

10

Readme

@egintegrations/core-utils

Foundational TypeScript utilities for retry logic, error handling, health checks, and idempotency. Designed for use across API, BOT, and service applications with zero external dependencies.

Features

  • Retry Logic: Exponential backoff retry with configurable parameters
  • Error Handling: Comprehensive error classes for common scenarios
  • Health Checks: Framework-agnostic health and readiness checks
  • Idempotency: Pluggable storage interface for idempotent operations
  • Zero Dependencies: No external runtime dependencies
  • TypeScript: Full TypeScript support with type definitions
  • Dual Module: ESM and CommonJS support

Installation

npm install @egintegrations/core-utils

Usage

Retry Logic

The retry utility provides exponential backoff retry logic with configurable parameters.

import { retryWithBackoff, RetryableError } from '@egintegrations/core-utils';

// Basic usage with default configuration
const result = await retryWithBackoff(async () => {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) throw new Error('Request failed');
  return response.json();
});

// Custom configuration
const result = await retryWithBackoff(
  async () => {
    return await performOperation();
  },
  {
    maxAttempts: 5,
    initialDelay: 2000, // 2 seconds
    maxDelay: 60000, // 60 seconds max
    backoffMultiplier: 2,
    onRetry: (attempt, error, delay) => {
      console.log(`Retry attempt ${attempt}, waiting ${delay}ms`);
    },
  }
);

// Only retry specific errors
const result = await retryWithBackoff(
  async () => {
    return await performOperation();
  },
  {
    retryableErrors: [RetryableError, NetworkError],
  }
);

Configuration Options:

  • maxAttempts (default: 3): Maximum number of retry attempts
  • initialDelay (default: 1000ms): Initial delay before first retry
  • maxDelay (default: 30000ms): Maximum delay between retries
  • backoffMultiplier (default: 2): Multiplier for exponential backoff
  • retryableErrors (default: []): Array of error classes to retry (empty = retry all)
  • onRetry (optional): Callback function called on each retry attempt

Error Handling

Pre-defined error classes with HTTP status codes for common scenarios.

import {
  BaseError,
  ValidationError,
  AuthenticationError,
  AuthorizationError,
  NotFoundError,
  RateLimitError,
  ToolExecutionError,
} from '@egintegrations/core-utils';

// Validation errors (400)
throw new ValidationError('Invalid email format');

// Authentication errors (401)
throw new AuthenticationError('Invalid credentials');

// Authorization errors (403)
throw new AuthorizationError('Admin access required');

// Not found errors (404)
throw new NotFoundError('User not found');

// Rate limit errors (429)
throw new RateLimitError('Too many requests', 60); // retryAfter: 60 seconds

// Tool execution errors (500)
const cause = new Error('Database connection failed');
throw new ToolExecutionError('Failed to execute tool', cause);

// Custom errors
throw new BaseError('Custom error', 418, 'CUSTOM_ERROR_CODE');

// Error handling
try {
  await performOperation();
} catch (error) {
  if (error instanceof BaseError) {
    console.log(`Status: ${error.statusCode}, Code: ${error.code}`);
  }
}

Error Classes:

| Class | Status Code | Code | Description | |-------|-------------|------|-------------| | BaseError | 500 | BASE_ERROR | Base error class for all errors | | ValidationError | 400 | VALIDATION_ERROR | Input validation failures | | AuthenticationError | 401 | AUTHENTICATION_ERROR | Authentication failures | | AuthorizationError | 403 | AUTHORIZATION_ERROR | Permission/authorization failures | | NotFoundError | 404 | NOT_FOUND_ERROR | Resource not found | | RateLimitError | 429 | RATE_LIMIT_ERROR | Rate limit exceeded | | ToolExecutionError | 500 | TOOL_EXECUTION_ERROR | Tool execution failures |

Health Checks

Framework-agnostic health and readiness checks for services.

import {
  HealthChecker,
  runHealthChecks,
  runReadinessChecks,
} from '@egintegrations/core-utils';

// Using HealthChecker class
const checker = new HealthChecker();

// Add health checks
checker.addHealthCheck({
  name: 'database',
  check: async () => {
    try {
      await db.ping();
      return true;
    } catch {
      return false;
    }
  },
});

checker.addHealthCheck({
  name: 'cache',
  check: async () => {
    try {
      await redis.ping();
      return true;
    } catch {
      return false;
    }
  },
});

// Run health checks
const healthStatus = await checker.runHealthChecks();
console.log(healthStatus);
// {
//   healthy: true,
//   timestamp: '2026-01-21T12:00:00.000Z',
//   checks: { database: true, cache: true },
//   uptime: 3600
// }

// Add readiness checks
checker.addReadinessCheck({
  name: 'migrations',
  check: async () => {
    const pending = await db.getPendingMigrations();
    return pending.length === 0;
  },
});

// Run readiness checks
const readinessStatus = await checker.runReadinessChecks();
console.log(readinessStatus);
// {
//   ready: true,
//   timestamp: '2026-01-21T12:00:00.000Z',
//   checks: { migrations: true }
// }

// Convenience functions for simple use cases
const healthStatus = await runHealthChecks([
  { name: 'database', check: async () => true },
  { name: 'api', check: async () => true },
]);

const readinessStatus = await runReadinessChecks([
  { name: 'config', check: async () => true },
]);

Express Integration Example:

import express from 'express';
import { HealthChecker } from '@egintegrations/core-utils';

const app = express();
const checker = new HealthChecker();

// Add your checks
checker.addHealthCheck({
  name: 'database',
  check: async () => {
    /* ... */
  },
});

// Health endpoint
app.get('/health', async (req, res) => {
  const status = await checker.runHealthChecks();
  res.status(status.healthy ? 200 : 503).json(status);
});

// Readiness endpoint
app.get('/ready', async (req, res) => {
  const status = await checker.runReadinessChecks();
  res.status(status.ready ? 200 : 503).json(status);
});

Idempotency

Pluggable storage interface for implementing idempotent operations.

import {
  IdempotencyManager,
  InMemoryIdempotencyStore,
  generateIdempotencyKey,
} from '@egintegrations/core-utils';

// Using in-memory store (for development/testing)
const store = new InMemoryIdempotencyStore(24 * 60 * 60 * 1000); // 24 hour TTL
const manager = new IdempotencyManager(store);

// Execute with idempotency
const orderId = await manager.executeWithIdempotency(
  'create-order-user123-item456',
  async () => {
    return await createOrder({ userId: 123, itemId: 456 });
  }
);

// Subsequent calls with same key return cached result without re-execution
const sameOrderId = await manager.executeWithIdempotency(
  'create-order-user123-item456',
  async () => {
    return await createOrder({ userId: 123, itemId: 456 }); // Not executed
  }
);

// Generate unique idempotency keys
const key = generateIdempotencyKey('payment'); // "payment_timestamp_randomhex"

// Manual operations
await manager.save('operation-key', result, 3600000); // 1 hour TTL
const cached = await manager.check('operation-key');
await manager.delete('operation-key');

Custom Storage Implementation:

import { IdempotencyStore, IdempotencyManager } from '@egintegrations/core-utils';
import Redis from 'ioredis';

class RedisIdempotencyStore implements IdempotencyStore {
  constructor(private redis: Redis) {}

  async get(key: string): Promise<any | null> {
    const value = await this.redis.get(key);
    return value ? JSON.parse(value) : null;
  }

  async set(key: string, value: any, ttlMs: number): Promise<void> {
    await this.redis.set(key, JSON.stringify(value), 'PX', ttlMs);
  }

  async delete(key: string): Promise<void> {
    await this.redis.del(key);
  }
}

// Use custom store
const redis = new Redis();
const store = new RedisIdempotencyStore(redis);
const manager = new IdempotencyManager(store);

Convenience Functions (using default in-memory store):

import {
  checkIdempotency,
  saveIdempotencyResult,
} from '@egintegrations/core-utils';

// Check for existing result
const cached = await checkIdempotency('operation-key');
if (cached) {
  return cached;
}

// Perform operation and save result
const result = await performOperation();
await saveIdempotencyResult('operation-key', result);

API Reference

Retry

retryWithBackoff<T>(fn: () => Promise<T>, config?: RetryConfig): Promise<T>

Executes a function with exponential backoff retry logic.

RetryableError

Error class that can be used to mark errors as retryable.

Errors

All error classes extend BaseError with the following properties:

  • message: string - Error message
  • statusCode: number - HTTP status code
  • code: string - Error code
  • name: string - Error name

Health Checks

HealthChecker

Class for managing health and readiness checks.

Methods:

  • addHealthCheck(check: HealthCheck): void - Add a health check
  • addReadinessCheck(check: HealthCheck): void - Add a readiness check
  • runHealthChecks(): Promise<HealthStatus> - Run all health checks
  • runReadinessChecks(): Promise<ReadinessStatus> - Run all readiness checks

runHealthChecks(checks: HealthCheck[]): Promise<HealthStatus>

Convenience function to run health checks without creating a HealthChecker instance.

runReadinessChecks(checks: HealthCheck[]): Promise<ReadinessStatus>

Convenience function to run readiness checks without creating a HealthChecker instance.

Idempotency

IdempotencyManager

Class for managing idempotent operations with a pluggable storage backend.

Constructor:

  • constructor(store: IdempotencyStore, defaultTtlMs?: number)

Methods:

  • check(key: string): Promise<any | null> - Check for existing result
  • save(key: string, result: any, ttlMs?: number): Promise<void> - Save result
  • delete(key: string): Promise<void> - Delete result
  • executeWithIdempotency<T>(key: string, fn: () => Promise<T>, ttlMs?: number): Promise<T> - Execute operation with idempotency

InMemoryIdempotencyStore

In-memory implementation of IdempotencyStore interface.

Constructor:

  • constructor(defaultTtlMs?: number) - Default: 24 hours

Methods:

  • get(key: string): Promise<any | null>
  • set(key: string, value: any, ttlMs: number): Promise<void>
  • delete(key: string): Promise<void>
  • destroy(): void - Cleanup and stop background cleanup interval

generateIdempotencyKey(prefix?: string): string

Generates a unique idempotency key with optional prefix.

hashIdempotencyKey(key: string): string

Hashes an idempotency key using SHA-256.

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Run tests with coverage
npm test -- --coverage

# Type check
npm run typecheck

# Lint
npm run lint

# Watch mode
npm run dev

Contributing

Contributions are welcome! Please ensure:

  1. All tests pass (npm test)
  2. Code coverage remains ≥80%
  3. TypeScript types are properly defined
  4. Code follows the existing style (run npm run lint)

License

MIT © EGI Integrations

Extracted From

This package was extracted from the egi-botnet project's bot-sdk-node package and refactored to be framework-agnostic with zero external dependencies.

Related Packages

Support

For issues and questions, please open an issue on GitHub.