@bombillazo/error-x 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -3
- package/dist/index.cjs +195 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -34
- package/dist/index.d.ts +120 -34
- package/dist/index.js +196 -84
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@bombillazo/error-x)
|
|
5
5
|
[](https://github.com/bombillazo/error-x/blob/master/LICENSE)
|
|
6
6
|
|
|
7
|
-
A smart, isomorphic, and
|
|
7
|
+
A smart, isomorphic, and opinionated error library for TypeScript applications. Provides type-safe error handling with great DX, solving common pain points like unknown error types, lost stack traces, async error handling, and error serialization.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -12,11 +12,11 @@ A smart, isomorphic, and satisfying error library for TypeScript applications. P
|
|
|
12
12
|
- 🔄 **Smart error conversion** from various formats (API responses, strings, Error objects)
|
|
13
13
|
- 📝 **Auto-formatted messages and error codes** with proper capitalization and punctuation
|
|
14
14
|
- 👤 **User-friendly messages** separate from technical messages
|
|
15
|
-
- 🕒 **Automatic timestamps** for error tracking
|
|
16
15
|
- 🔗 **Error chaining** with cause preservation and stack trace preservation
|
|
17
16
|
- 📊 **Flexible metadata** for additional context
|
|
18
17
|
- 🎛️ **Error handling options** for UI behavior and application actions
|
|
19
18
|
- 📦 **Serialization/deserialization** support for network transfer and storage
|
|
19
|
+
- 🎨 **Pre-configured error presets** for common error types
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
@@ -236,6 +236,179 @@ const error = new ErrorX({
|
|
|
236
236
|
})
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
+
## Error Presets
|
|
240
|
+
|
|
241
|
+
ErrorX provides pre-configured error templates for common scenarios, making it easy to create consistent, well-structured errors without repetition. All HTTP presets (400-511) are included with proper status codes, messages, and user-friendly text.
|
|
242
|
+
|
|
243
|
+
### Features
|
|
244
|
+
|
|
245
|
+
- ✅ **Pre-configured templates** with httpStatus, code, name, message, and uiMessage
|
|
246
|
+
- ✅ **Type-safe** with full TypeScript support
|
|
247
|
+
- ✅ **Fully customizable** via destructuring and override pattern
|
|
248
|
+
- ✅ **Categorized by type** - all HTTP presets include `type: 'http'` for easy filtering
|
|
249
|
+
- ✅ **User-friendly messages** included for all presets
|
|
250
|
+
|
|
251
|
+
### Usage Patterns
|
|
252
|
+
|
|
253
|
+
#### 1. Direct Usage
|
|
254
|
+
|
|
255
|
+
Use a preset as-is without modifications:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { ErrorX } from '@bombillazo/error-x'
|
|
259
|
+
|
|
260
|
+
// Simple usage
|
|
261
|
+
throw new ErrorX(ErrorX.HTTP.NOT_FOUND)
|
|
262
|
+
// Result: 404 error with default message and UI message
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### 2. Override Specific Fields
|
|
266
|
+
|
|
267
|
+
Customize the error while keeping other preset values:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
throw new ErrorX({
|
|
271
|
+
...ErrorX.HTTP.NOT_FOUND,
|
|
272
|
+
message: 'User not found',
|
|
273
|
+
metadata: { userId: 123 }
|
|
274
|
+
})
|
|
275
|
+
// Result: 404 error with custom message but keeps httpStatus, code, name, uiMessage, type
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### 3. Add Metadata and Actions
|
|
279
|
+
|
|
280
|
+
Enhance presets with additional context and behaviors:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
throw new ErrorX({
|
|
284
|
+
...ErrorX.HTTP.UNAUTHORIZED,
|
|
285
|
+
metadata: { attemptedAction: 'viewProfile', userId: 456 },
|
|
286
|
+
actions: [
|
|
287
|
+
{ action: 'logout', payload: { clearStorage: true } },
|
|
288
|
+
{ action: 'redirect', payload: { redirectURL: '/login' } }
|
|
289
|
+
]
|
|
290
|
+
})
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### 4. Add Error Cause
|
|
294
|
+
|
|
295
|
+
Chain errors by adding a cause:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
try {
|
|
299
|
+
// some operation
|
|
300
|
+
} catch (originalError) {
|
|
301
|
+
throw new ErrorX({
|
|
302
|
+
...ErrorX.HTTP.INTERNAL_SERVER_ERROR,
|
|
303
|
+
cause: originalError,
|
|
304
|
+
metadata: { operation: 'database-query' }
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Available HTTP Presets
|
|
310
|
+
|
|
311
|
+
#### 4xx Client Errors
|
|
312
|
+
|
|
313
|
+
| Preset | Status | Description |
|
|
314
|
+
| ------ | ------ | ----------- |
|
|
315
|
+
| BAD_REQUEST | 400 | Invalid request data |
|
|
316
|
+
| UNAUTHORIZED | 401 | Authentication required |
|
|
317
|
+
| PAYMENT_REQUIRED | 402 | Payment required to access resource |
|
|
318
|
+
| FORBIDDEN | 403 | Insufficient permissions |
|
|
319
|
+
| NOT_FOUND | 404 | Resource not found |
|
|
320
|
+
| METHOD_NOT_ALLOWED | 405 | HTTP method not allowed |
|
|
321
|
+
| NOT_ACCEPTABLE | 406 | Requested format not supported |
|
|
322
|
+
| PROXY_AUTHENTICATION_REQUIRED | 407 | Proxy authentication required |
|
|
323
|
+
| REQUEST_TIMEOUT | 408 | Request took too long |
|
|
324
|
+
| CONFLICT | 409 | Resource conflict |
|
|
325
|
+
| GONE | 410 | Resource no longer available |
|
|
326
|
+
| LENGTH_REQUIRED | 411 | Missing length information |
|
|
327
|
+
| PRECONDITION_FAILED | 412 | Required condition not met |
|
|
328
|
+
| PAYLOAD_TOO_LARGE | 413 | Request payload too large |
|
|
329
|
+
| URI_TOO_LONG | 414 | Request URL too long |
|
|
330
|
+
| UNSUPPORTED_MEDIA_TYPE | 415 | File type not supported |
|
|
331
|
+
| RANGE_NOT_SATISFIABLE | 416 | Requested range cannot be satisfied |
|
|
332
|
+
| EXPECTATION_FAILED | 417 | Server cannot meet request requirements |
|
|
333
|
+
| IM_A_TEAPOT | 418 | I'm a teapot (RFC 2324) |
|
|
334
|
+
| UNPROCESSABLE_ENTITY | 422 | Validation failed |
|
|
335
|
+
| LOCKED | 423 | Resource is locked |
|
|
336
|
+
| FAILED_DEPENDENCY | 424 | Request failed due to dependency error |
|
|
337
|
+
| TOO_EARLY | 425 | Request sent too early |
|
|
338
|
+
| UPGRADE_REQUIRED | 426 | Upgrade required to continue |
|
|
339
|
+
| PRECONDITION_REQUIRED | 428 | Required conditions missing |
|
|
340
|
+
| TOO_MANY_REQUESTS | 429 | Rate limit exceeded |
|
|
341
|
+
| REQUEST_HEADER_FIELDS_TOO_LARGE | 431 | Request headers too large |
|
|
342
|
+
| UNAVAILABLE_FOR_LEGAL_REASONS | 451 | Content unavailable for legal reasons |
|
|
343
|
+
|
|
344
|
+
#### 5xx Server Errors
|
|
345
|
+
|
|
346
|
+
| Preset | Status | Description |
|
|
347
|
+
| ------ | ------ | ----------- |
|
|
348
|
+
| INTERNAL_SERVER_ERROR | 500 | Unexpected server error |
|
|
349
|
+
| NOT_IMPLEMENTED | 501 | Feature not implemented |
|
|
350
|
+
| BAD_GATEWAY | 502 | Upstream server error |
|
|
351
|
+
| SERVICE_UNAVAILABLE | 503 | Service temporarily down |
|
|
352
|
+
| GATEWAY_TIMEOUT | 504 | Upstream timeout |
|
|
353
|
+
| HTTP_VERSION_NOT_SUPPORTED | 505 | HTTP version not supported |
|
|
354
|
+
| VARIANT_ALSO_NEGOTIATES | 506 | Internal configuration error |
|
|
355
|
+
| INSUFFICIENT_STORAGE | 507 | Insufficient storage |
|
|
356
|
+
| LOOP_DETECTED | 508 | Infinite loop detected |
|
|
357
|
+
| NOT_EXTENDED | 510 | Additional extensions required |
|
|
358
|
+
| NETWORK_AUTHENTICATION_REQUIRED | 511 | Network authentication required |
|
|
359
|
+
|
|
360
|
+
### Real-World Examples
|
|
361
|
+
|
|
362
|
+
#### API Endpoint
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
import { ErrorX } from '@bombillazo/error-x'
|
|
366
|
+
|
|
367
|
+
app.get('/users/:id', async (req, res) => {
|
|
368
|
+
const user = await db.users.findById(req.params.id)
|
|
369
|
+
|
|
370
|
+
if (!user) {
|
|
371
|
+
throw new ErrorX({
|
|
372
|
+
...ErrorX.HTTP.NOT_FOUND,
|
|
373
|
+
message: 'User not found',
|
|
374
|
+
metadata: { userId: req.params.id }
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
res.json(user)
|
|
379
|
+
})
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### Authentication Middleware
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
const requireAuth = (req, res, next) => {
|
|
386
|
+
if (!req.user) {
|
|
387
|
+
throw new ErrorX({
|
|
388
|
+
...ErrorX.HTTP.UNAUTHORIZED,
|
|
389
|
+
actions: [
|
|
390
|
+
{ action: 'redirect', payload: { redirectURL: '/login' } }
|
|
391
|
+
]
|
|
392
|
+
})
|
|
393
|
+
}
|
|
394
|
+
next()
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### Rate Limiting
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
if (isRateLimited(req.ip)) {
|
|
402
|
+
throw new ErrorX({
|
|
403
|
+
...ErrorX.HTTP.TOO_MANY_REQUESTS,
|
|
404
|
+
metadata: {
|
|
405
|
+
ip: req.ip,
|
|
406
|
+
retryAfter: 60
|
|
407
|
+
}
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
239
412
|
## Smart Features
|
|
240
413
|
|
|
241
414
|
### Auto Code Generation
|
|
@@ -246,7 +419,7 @@ Error codes are automatically generated from the error name:
|
|
|
246
419
|
new ErrorX({ message: 'Failed', name: 'DatabaseError' })
|
|
247
420
|
// code: 'DATABASE_ERROR'
|
|
248
421
|
|
|
249
|
-
new ErrorX({ message: 'Failed', name: 'userAuthError' })
|
|
422
|
+
new ErrorX({ message: 'Failed', name: 'userAuthError' })
|
|
250
423
|
// code: 'USER_AUTH_ERROR'
|
|
251
424
|
|
|
252
425
|
new ErrorX({ message: 'Failed', name: 'API Timeout' })
|