ErrorBoundary - sebamar88/bytekit GitHub Wiki
EN: Global error boundary for centralized error handling, automatic retry, error normalization, and reporting. Converts plain
Errorinstances into typedAppErrorsubclasses by detecting keywords.ES: Boundary de errores global para manejo centralizado, reintento automático, normalización de errores y reportes. Convierte instancias de
Errorplanas en subclases tipadas deAppErrordetectando palabras clave.
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";const boundary = new ErrorBoundary(config?: 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 |
EN:
AppErroris the base typed error. All subclasses inheritcode,message,statusCode,context?, andoriginalError?.ES:
AppErrores el error base tipado. Todas las subclases heredancode,message,statusCode,context?yoriginalError?.
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);
}| 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 = 60EN: 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
}| 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 |
EN: When a plain
Erroris passed tohandle()orexecute(), it is automatically converted to the most appropriateAppErrorsubclass by scanning the error message for keywords:ES: Cuando un
Errorplano se pasa ahandle()oexecute(), se convierte automáticamente a la subclaseAppErrormá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) |
EN:
execute()automatically retries whenisRetryable()returnstrue. A status code is retryable if it is 408 (Timeout), 429 (Rate Limit), or 5xx (Server Error). The retry count and delay are configured viamaxRetriesandretryDelay.ES:
execute()reintenta automáticamente cuandoisRetryable()devuelvetrue. 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 conmaxRetriesyretryDelay.
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
EN: Use
getGlobalErrorBoundary()to share a single boundary across your entire application. CallresetGlobalErrorBoundary()to clear it (useful in tests).ES: Usa
getGlobalErrorBoundary()para compartir un único boundary en toda la aplicación. Llama aresetGlobalErrorBoundary()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();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" }
);// 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);// 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");// 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, ... },
// ...
// ]
// }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");- 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