ErrorBoundary - sebamar88/bytekit GitHub Wiki

🛡️ ErrorBoundary

EN: Global error boundary for centralized error handling, automatic retry, error normalization, and reporting. Converts plain Error instances into typed AppError subclasses by detecting keywords.

ES: Boundary de errores global para manejo centralizado, reintento automático, normalización de errores y reportes. Convierte instancias de Error planas en subclases tipadas de AppError detectando palabras clave.


📦 Import

import {
  ErrorBoundary,
  AppError,
  AppValidationError,
  NotFoundError,
  UnauthorizedError,
  ForbiddenError,
  ConflictError,
  RateLimitError,
  TimeoutError,
  getGlobalErrorBoundary,
  resetGlobalErrorBoundary,
} from "bytekit/error-boundary";
// or | o también:
import { ErrorBoundary, AppError /* ... */ } from "bytekit";

⚙️ Constructor

const boundary = new ErrorBoundary(config?: ErrorBoundaryConfig);

ErrorBoundaryConfig

Property / Propiedad Type / Tipo Default Description (EN) Descripción (ES)
logger Logger undefined Logger instance for error logging Instancia de Logger para registro de errores
handlers ErrorHandler[] [] Initial array of error handlers Array inicial de manejadores de errores
onError (error, context) => void undefined Custom callback invoked on every error Callback personalizado invocado en cada error
onErrorRecovery (error, context) => void undefined Callback invoked on successful recovery Callback invocado en recuperación exitosa
maxRetries number 3 Maximum retry attempts for retryable errors Máximo de reintentos para errores reintentables
retryDelay number 1000 Delay between retries in milliseconds Retardo entre reintentos en milisegundos
fallbackUI string undefined Fallback UI identifier Identificador de UI de respaldo
isDevelopment boolean undefined Enable development-mode logging Habilitar registro en modo desarrollo

🧱 AppError & Subclasses / AppError y Subclases

EN: AppError is the base typed error. All subclasses inherit code, message, statusCode, context?, and originalError?.

ES: AppError es el error base tipado. Todas las subclases heredan code, message, statusCode, context? y originalError?.

class AppError extends Error {
  readonly code: string;
  readonly statusCode: number;
  readonly context?: ErrorContext;
  readonly originalError?: Error;

  constructor(code: string, message: string, statusCode?: number, context?: ErrorContext, originalError?: Error);
}

Subclasses / Subclases

Class / Clase Code / Código Status Description (EN) Descripción (ES)
AppValidationError VALIDATION_ERROR 400 Validation failed Error de validación
UnauthorizedError UNAUTHORIZED 401 Authentication required Se requiere autenticación
ForbiddenError FORBIDDEN 403 Insufficient permissions Permisos insuficientes
NotFoundError NOT_FOUND 404 Resource not found Recurso no encontrado
TimeoutError TIMEOUT 408 Operation timed out Tiempo de espera agotado
ConflictError CONFLICT 409 Resource conflict Conflicto de recurso
RateLimitError RATE_LIMIT 429 Rate limit exceeded (has retryAfter) Límite de tasa excedido (incluye retryAfter)
// RateLimitError includes retryAfter in metadata
// RateLimitError incluye retryAfter en metadata
new RateLimitError("Too many requests", 60, { component: "API" });
// → metadata.retryAfter = 60

📋 ErrorContext

EN: Optional context object attached to errors for debugging.

ES: Objeto de contexto opcional adjunto a errores para depuración.

interface ErrorContext {
  component?: string;    // Component name / Nombre del componente
  context?: string;      // Free-form context / Contexto libre
  userId?: string;       // User identifier / Identificador de usuario
  sessionId?: string;    // Session identifier / Identificador de sesión
  metadata?: Record<string, unknown>; // Extra data / Datos extra
  originalError?: Error; // Original error / Error original
}

📋 Methods / Métodos

Method / Método Signature / Firma Description (EN) Descripción (ES)
handle handle(error: Error, context?: ErrorContext): Promise<void> Normalizes, logs, and dispatches error to all handlers Normaliza, registra y despacha el error a todos los manejadores
execute execute<T>(fn: () => Promise<T>, context?, retries?): Promise<T> Runs async function with auto-retry on retryable errors Ejecuta función async con reintento automático en errores reintentables
executeSync executeSync<T>(fn: () => T, context?): T Runs sync function with error handling Ejecuta función síncrona con manejo de errores
wrap wrap<T>(fn: T, context?): T Returns a wrapped async function with error handling Devuelve función async envuelta con manejo de errores
wrapSync wrapSync<T>(fn: T, context?): T Returns a wrapped sync function with error handling Devuelve función síncrona envuelta con manejo de errores
addHandler addHandler(handler: ErrorHandler): void Registers an error handler Registra un manejador de errores
removeHandler removeHandler(handler: ErrorHandler): void Removes a previously registered handler Elimina un manejador registrado previamente
clearHandlers clearHandlers(): void Removes all registered handlers Elimina todos los manejadores registrados
getErrorHistory getErrorHistory(limit?: number): Array<{error, context, timestamp}> Returns the last N errors (default 10) Devuelve los últimos N errores (por defecto 10)
clearErrorHistory clearErrorHistory(): void Clears the internal error stack Limpia la pila interna de errores
createErrorReport createErrorReport(): ErrorReport Generates a JSON-serializable report of all recorded errors Genera un reporte serializable en JSON de todos los errores registrados

🔄 Auto-Normalization / Auto-Normalización

EN: When a plain Error is passed to handle() or execute(), it is automatically converted to the most appropriate AppError subclass by scanning the error message for keywords:

ES: Cuando un Error plano se pasa a handle() o execute(), se convierte automáticamente a la subclase AppError más apropiada escaneando el mensaje del error en busca de palabras clave:

Keyword / Palabra clave Mapped to / Mapeado a
"timeout" / "Timeout" TimeoutError (408)
"validation" / "Validation" AppValidationError (400)
"not found" / "Not Found" NotFoundError (404)
(none matched) AppError (UNKNOWN_ERROR, 500)

♻️ Retry Logic / Lógica de Reintento

EN: execute() automatically retries when isRetryable() returns true. A status code is retryable if it is 408 (Timeout), 429 (Rate Limit), or 5xx (Server Error). The retry count and delay are configured via maxRetries and retryDelay.

ES: execute() reintenta automáticamente cuando isRetryable() devuelve true. Un código de estado es reintentable si es 408 (Timeout), 429 (Rate Limit) o 5xx (Error de Servidor). La cantidad de reintentos y el retardo se configuran con maxRetries y retryDelay.

execute(fn)
  ├── try → return result ✓
  └── catch
       ├── isRetryable(408 | 429 | 5xx)?
       │    ├── yes → wait(retryDelay) → retry (up to maxRetries)
       │    └── no  → handle(error) → throw
       └── retries exhausted → handle(error) → throw

🌐 Global Singleton / Singleton Global

EN: Use getGlobalErrorBoundary() to share a single boundary across your entire application. Call resetGlobalErrorBoundary() to clear it (useful in tests).

ES: Usa getGlobalErrorBoundary() para compartir un único boundary en toda la aplicación. Llama a resetGlobalErrorBoundary() para limpiarlo (útil en tests).

import { getGlobalErrorBoundary, resetGlobalErrorBoundary } from "bytekit/error-boundary";

const boundary = getGlobalErrorBoundary({ maxRetries: 5 });
// Subsequent calls return the same instance
// Las llamadas siguientes devuelven la misma instancia

// In tests / En tests:
resetGlobalErrorBoundary();

💡 Examples / Ejemplos

Basic error handling / Manejo básico de errores

import { ErrorBoundary, NotFoundError } from "bytekit/error-boundary";

const boundary = new ErrorBoundary({
  maxRetries: 3,
  retryDelay: 1000,
  onError: (error, ctx) => console.error(`[${ctx.component}]`, error.message),
});

// Execute with auto-retry / Ejecutar con reintento automático
const data = await boundary.execute(
  () => fetch("/api/users").then((r) => r.json()),
  { component: "UserService" }
);

Custom handlers / Manejadores personalizados

// Register a handler that sends errors to a tracking service
// Registrar un manejador que envía errores a un servicio de tracking
const telemetryHandler = async (error, context) => {
  await analytics.trackError({
    code: error instanceof AppError ? error.code : "UNKNOWN",
    message: error.message,
    component: context.component,
  });
};

boundary.addHandler(telemetryHandler);

// Later remove it / Luego removerlo
boundary.removeHandler(telemetryHandler);

Wrapping functions / Envolver funciones

// Wrap an async function — returns a new function with built-in error handling
// Envuelve una función async — retorna una nueva función con manejo de errores incluido
const safeFetch = boundary.wrap(
  async (url: string) => {
    const res = await fetch(url);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  },
  { component: "HttpClient" }
);

const result = await safeFetch("/api/data");

Error report / Reporte de errores

// Generate a full error report after some operations
// Generar un reporte completo de errores después de algunas operaciones
const report = boundary.createErrorReport();
console.log(report);
// {
//   timestamp: "2026-03-27T12:00:00.000Z",
//   errors: [
//     { code: "NOT_FOUND", message: "User not found", statusCode: 404, timestamp: 1711533600000, ... },
//     ...
//   ]
// }

Throwing typed errors / Lanzar errores tipados

import { RateLimitError, TimeoutError, AppValidationError } from "bytekit/error-boundary";

throw new RateLimitError("Slow down", 60); // retryAfter = 60s
throw new TimeoutError("Gateway timed out");
throw new AppValidationError("Email is required");

Véase También / See Also

  • RetryPolicy — Standalone retry strategies / Estrategias de reintento independientes
  • CircuitBreaker — Circuit breaker pattern / Patrón de circuit breaker
  • Logger — Structured logging / Registro estructurado
  • ApiClient — HTTP client with built-in error handling / Cliente HTTP con manejo de errores integrado
⚠️ **GitHub.com Fallback** ⚠️