anton-bakker-errors
v0.1.1
Published
Shared error handling: typed errors, classification, reporting, and React hooks
Maintainers
Readme
anton-bakker-errors
Shared error handling for TypeScript projects: typed errors with classification, pluggable reporting, and React hooks.
Zero runtime dependencies. React is an optional peer dependency.
Installation
npm install anton-bakker-errorsQuick Start
Node.js / Lambda / deploy-engine (core only)
import { createError, fromUnknown, ok, fail, summarizeErrors } from 'anton-bakker-errors';
// Create a typed error
const err = createError('TIMEOUT', 'Request timed out', { category: 'transient' });
// → { code: 'TIMEOUT', severity: 'warning', category: 'transient', retryable: true, ... }
// Convert unknown caught values
try {
await riskyOperation();
} catch (e) {
const appError = fromUnknown(e); // auto-categorises based on message
}
// Result type
async function getUser(id: string): Promise<OperationResult<User>> {
try {
const user = await db.get(id);
return ok(user);
} catch (e) {
return fail(fromUnknown(e));
}
}React (with hooks)
import { useErrorHandler } from 'anton-bakker-errors/react';
function MyComponent() {
const { handleError, errorMessage, clearError, hasError } = useErrorHandler();
const save = async () => {
try {
await saveData();
} catch (err) {
handleError(err);
}
};
return hasError ? <Alert onClose={clearError}>{errorMessage}</Alert> : <Form onSubmit={save} />;
}API
Core (anton-bakker-errors)
| Export | Description |
|--------|-------------|
| createError(code, message, opts?) | Create a typed AppError with auto-derived severity and retryable |
| fromUnknown(err, fallbackCode?) | Convert unknown to AppError with auto-categorisation |
| fromAmplifyErrors(errors) | Convert Amplify GraphQL error array to AppError |
| ok(data) | Create success OperationResult |
| fail(error) | Create error OperationResult |
| isAppError(value) | Type guard for AppError |
| summarizeErrors(errors) | Aggregate errors by severity, category, retryable count |
| registerErrorCodes(codes) | Register custom error codes with user-friendly messages |
| getUserFriendlyMessage(code) | Look up user-friendly message for an error code |
| getErrorCode(code) | Look up full error code definition |
| noopReporter | Silent reporter (default) |
| compositeReporter(...reporters) | Fan out to multiple reporters |
React (anton-bakker-errors/react)
| Export | Description |
|--------|-------------|
| useErrorHandler(opts?) | React hook with handleError, clearError, errorMessage, pluggable reporter |
| getUserFriendlyMessage(code) | Re-exported for convenience |
Error Classification
Every AppError has a category that drives retry and handling decisions:
| Category | Retryable | Severity | Examples |
|----------|-----------|----------|----------|
| transient | ✅ | warning | Network timeout, throttle, ECONNREFUSED |
| configuration | ❌ | error | Missing env var, bad config |
| validation | ❌ | warning | Invalid input |
| authorization | ❌ | error | Permission denied, 403 |
| not_found | ❌ | warning | 404, ENOENT |
| conflict | ✅ | warning | Concurrent modification |
| fatal | ❌ | critical | Unrecoverable errors |
fromUnknown() auto-categorises based on error message patterns (timeout, network, permission, etc.).
Custom Error Codes
import { registerErrorCodes, getUserFriendlyMessage } from 'anton-bakker-errors';
registerErrorCodes({
VESSEL_NOT_FOUND: {
message: 'Vessel not found',
userMessage: 'The vessel could not be found. Please check the IMO number.',
category: 'not_found',
},
BOOKING_CONFLICT: {
message: 'Booking conflict',
userMessage: 'This booking slot is no longer available.',
category: 'conflict',
},
});
getUserFriendlyMessage('VESSEL_NOT_FOUND');
// → 'The vessel could not be found. Please check the IMO number.'Pluggable Reporting
import { compositeReporter, type ErrorReporter } from 'anton-bakker-errors';
const cloudwatchReporter: ErrorReporter = {
report: (error) => {
// Send to CloudWatch, Sentry, etc.
},
};
// React: pass reporter to hook
const { handleError } = useErrorHandler({ reporter: cloudwatchReporter });
// Combine multiple reporters
const combined = compositeReporter(cloudwatchReporter, slackReporter);Types
| Type | Description |
|------|-------------|
| AppError | { code, message, severity, category, retryable, timestamp, details?, cause? } |
| OperationResult<T> | { success, data?, error? } |
| ErrorSeverity | 'info' \| 'warning' \| 'error' \| 'critical' |
| ErrorCategory | 'transient' \| 'configuration' \| 'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'fatal' |
| ErrorReporter | { report(error): void; flush?(): Promise<void> } |
| ErrorCodeDefinition | { message, userMessage?, category, severity? } |
Development
npm install
npm test # 50 tests
npm run lint # zero warnings
npm run build # compiles to dist/Licence
MIT
