@owlmeans/error 0.1.2 → 0.1.4
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 +36 -350
- package/package.json +4 -3
- package/tsconfig.json +5 -9
package/README.md
CHANGED
|
@@ -1,390 +1,76 @@
|
|
|
1
1
|
# @owlmeans/error
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Serializable error base class with type registration for cross-process error propagation.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
- **Transmitted** over the network as regular Error objects
|
|
11
|
-
- **Unmarshaled** (deserialized) on the client side back to the same typed error class
|
|
12
|
-
|
|
13
|
-
This ensures that error handling remains consistent and type-safe across the entire application stack.
|
|
7
|
+
- `ResilientError` base class survives JSON serialization/deserialization across service boundaries
|
|
8
|
+
- Error class registry ensures custom error types are correctly reconstructed after transport
|
|
9
|
+
- Helpers for marshaling errors to strings and back
|
|
14
10
|
|
|
15
11
|
## Installation
|
|
16
12
|
|
|
17
13
|
```bash
|
|
18
|
-
|
|
14
|
+
bun add @owlmeans/error
|
|
19
15
|
```
|
|
20
16
|
|
|
21
|
-
##
|
|
22
|
-
|
|
23
|
-
### ResilientError Class
|
|
24
|
-
|
|
25
|
-
The `ResilientError` class is the foundation of the error system. It extends the standard JavaScript `Error` class and provides additional functionality for marshaling, unmarshaling, and type conversion.
|
|
26
|
-
|
|
27
|
-
### Error Conversion System
|
|
28
|
-
|
|
29
|
-
The package includes a flexible converter system that allows registration of custom error types and their conversion logic through the `Converter` interface.
|
|
30
|
-
|
|
31
|
-
### Marshaling & Unmarshaling
|
|
32
|
-
|
|
33
|
-
- **Marshaling**: Converting a ResilientError into a transferable format
|
|
34
|
-
- **Unmarshaling**: Reconstructing a ResilientError from its marshaled form
|
|
35
|
-
|
|
36
|
-
## API Reference
|
|
37
|
-
|
|
38
|
-
### ResilientError Class
|
|
17
|
+
## Usage
|
|
39
18
|
|
|
40
|
-
|
|
19
|
+
Define and register a custom error type:
|
|
41
20
|
|
|
42
|
-
- `type: string` - The error type identifier
|
|
43
|
-
- `oiriginalStack?: string` - The original stack trace when the error was created
|
|
44
|
-
|
|
45
|
-
#### Static Properties
|
|
46
|
-
|
|
47
|
-
- `separator: string` - The separator used in marshaled error messages (default: `'|||'`)
|
|
48
|
-
- `typeName: string` - The default type name for ResilientError instances (default: `'ResilientError'`)
|
|
49
|
-
- `converters: Converter[]` - Array of registered error converters
|
|
50
|
-
|
|
51
|
-
#### Static Methods
|
|
52
|
-
|
|
53
|
-
##### `registerErrorClass(resilientErrorClass, errorClass?)`
|
|
54
|
-
|
|
55
|
-
Registers a custom error class with the converter system.
|
|
56
|
-
|
|
57
|
-
**Parameters:**
|
|
58
|
-
- `resilientErrorClass: ResilientErrorConstructor` - The ResilientError subclass to register
|
|
59
|
-
- `errorClass?: ErrorConstructor` - Optional native Error class to convert from
|
|
60
|
-
|
|
61
|
-
**Returns:** `Converter` - The created converter instance
|
|
62
|
-
|
|
63
|
-
**Example:**
|
|
64
21
|
```typescript
|
|
65
|
-
|
|
66
|
-
static typeName = 'CustomError'
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
ResilientError.registerErrorClass(CustomError, TypeError)
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
##### `ensure(err, throwOnUnknown?)`
|
|
73
|
-
|
|
74
|
-
Ensures an error is converted to a ResilientError instance.
|
|
75
|
-
|
|
76
|
-
**Parameters:**
|
|
77
|
-
- `err: Error | string` - The error to convert
|
|
78
|
-
- `throwOnUnknown?: boolean` - Whether to throw on unknown error types (default: false)
|
|
79
|
-
|
|
80
|
-
**Returns:** `ResilientError` - The converted error
|
|
81
|
-
|
|
82
|
-
**Example:**
|
|
83
|
-
```typescript
|
|
84
|
-
const resilientError = ResilientError.ensure(new Error('Something went wrong'))
|
|
85
|
-
const typedError = ResilientError.ensure('Error message')
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
##### `marshal(err)`
|
|
89
|
-
|
|
90
|
-
Marshals an error for network transmission.
|
|
91
|
-
|
|
92
|
-
**Parameters:**
|
|
93
|
-
- `err: Error` - The error to marshal
|
|
94
|
-
|
|
95
|
-
**Returns:** `Error` - A marshaled error object
|
|
96
|
-
|
|
97
|
-
**Example:**
|
|
98
|
-
```typescript
|
|
99
|
-
const original = new ResilientError('CustomError', 'Something failed')
|
|
100
|
-
const marshaled = ResilientError.marshal(original)
|
|
101
|
-
// marshaled.message contains: "CustomError|||Something failed|||[stack trace]"
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
#### Instance Methods
|
|
105
|
-
|
|
106
|
-
##### `marshal()`
|
|
107
|
-
|
|
108
|
-
Marshals the current error instance.
|
|
109
|
-
|
|
110
|
-
**Returns:** `Error` - A marshaled error object
|
|
111
|
-
|
|
112
|
-
**Example:**
|
|
113
|
-
```typescript
|
|
114
|
-
const error = new ResilientError('MyError', 'Description')
|
|
115
|
-
const marshaled = error.marshal()
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
##### `finalizeUnmarshal()`
|
|
119
|
-
|
|
120
|
-
Called after unmarshaling to perform any post-processing. Override in subclasses for custom behavior.
|
|
121
|
-
|
|
122
|
-
**Returns:** `void`
|
|
123
|
-
|
|
124
|
-
#### Constructor
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
constructor(type: string, message: string, stack?: string)
|
|
128
|
-
constructor(message: string, stack?: string)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Parameters:**
|
|
132
|
-
- `type: string` - The error type identifier
|
|
133
|
-
- `message: string` - The error message
|
|
134
|
-
- `stack?: string` - Optional stack trace
|
|
135
|
-
|
|
136
|
-
**Example:**
|
|
137
|
-
```typescript
|
|
138
|
-
const error1 = new ResilientError('ValidationError', 'Invalid input')
|
|
139
|
-
const error2 = new ResilientError('Network error') // uses default type
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Helper Functions
|
|
143
|
-
|
|
144
|
-
#### `enuserError<T>(err, throwOnUnknown?)`
|
|
145
|
-
|
|
146
|
-
Convenience function that ensures an error is a ResilientError instance.
|
|
147
|
-
|
|
148
|
-
**Parameters:**
|
|
149
|
-
- `err: Error | string` - The error to ensure
|
|
150
|
-
- `throwOnUnknown?: boolean` - Whether to throw on unknown error types
|
|
151
|
-
|
|
152
|
-
**Returns:** `T extends ResilientError` - The ensured error
|
|
153
|
-
|
|
154
|
-
**Example:**
|
|
155
|
-
```typescript
|
|
156
|
-
import { enuserError } from '@owlmeans/error'
|
|
157
|
-
|
|
158
|
-
const resilientError = enuserError(new Error('Something went wrong'))
|
|
159
|
-
const typedError = enuserError<MyCustomError>(someError)
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
#### `marshalError(err)`
|
|
163
|
-
|
|
164
|
-
Convenience function that marshals an error after ensuring it's a ResilientError.
|
|
165
|
-
|
|
166
|
-
**Parameters:**
|
|
167
|
-
- `err: Error | string` - The error to marshal
|
|
168
|
-
|
|
169
|
-
**Returns:** `Error` - The marshaled error
|
|
170
|
-
|
|
171
|
-
**Example:**
|
|
172
|
-
```typescript
|
|
173
|
-
import { marshalError } from '@owlmeans/error'
|
|
174
|
-
|
|
175
|
-
const marshaled = marshalError(new Error('Server error'))
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Utility Functions
|
|
179
|
-
|
|
180
|
-
#### `createErrorConverter(resilientErrorClass, errorClass?)`
|
|
181
|
-
|
|
182
|
-
Creates a converter for transforming native errors to ResilientError instances.
|
|
183
|
-
|
|
184
|
-
**Parameters:**
|
|
185
|
-
- `resilientErrorClass: ResilientErrorConstructor` - The target ResilientError class
|
|
186
|
-
- `errorClass?: ErrorConstructor` - Optional source Error class to match against
|
|
187
|
-
|
|
188
|
-
**Returns:** `Converter` - The created converter
|
|
189
|
-
|
|
190
|
-
**Example:**
|
|
191
|
-
```typescript
|
|
192
|
-
import { createErrorConverter } from '@owlmeans/error'
|
|
193
|
-
|
|
194
|
-
const converter = createErrorConverter(MyResilientError, TypeError)
|
|
195
|
-
ResilientError.converters.push(converter)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
#### `unmarshal<T>(errorClass)`
|
|
199
|
-
|
|
200
|
-
Creates an unmarshaling function for a specific error class.
|
|
201
|
-
|
|
202
|
-
**Parameters:**
|
|
203
|
-
- `errorClass: ResilientErrorConstructor` - The error class to unmarshal to
|
|
204
|
-
|
|
205
|
-
**Returns:** `(err: Error) => T` - Function that unmarshals errors to the specified type
|
|
206
|
-
|
|
207
|
-
**Example:**
|
|
208
|
-
```typescript
|
|
209
|
-
import { unmarshal } from '@owlmeans/error'
|
|
210
|
-
|
|
211
|
-
const unmarshalMyError = unmarshal(MyResilientError)
|
|
212
|
-
const restored = unmarshalMyError(marshaledError)
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Type Definitions
|
|
216
|
-
|
|
217
|
-
#### `ValueOrError<T>`
|
|
218
|
-
|
|
219
|
-
A utility type that represents either a value or a ResilientError.
|
|
22
|
+
import { ResilientError } from '@owlmeans/error'
|
|
220
23
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
```
|
|
24
|
+
export class ProjectResourceError extends ResilientError {
|
|
25
|
+
static typeName = 'viable-project:error'
|
|
224
26
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (someCondition) {
|
|
229
|
-
return "success"
|
|
27
|
+
constructor(message: string = 'error') {
|
|
28
|
+
super(`viable-project:${message}`)
|
|
29
|
+
this.type = ProjectResourceError.typeName
|
|
230
30
|
}
|
|
231
|
-
return new ResilientError('ProcessingError', 'Failed to process')
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
#### `Converter`
|
|
236
|
-
|
|
237
|
-
Interface for error conversion logic.
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
interface Converter {
|
|
241
|
-
match: (err: Error) => boolean
|
|
242
|
-
convert: (err: Error) => ResilientError
|
|
243
|
-
isMarshaled: (err: Error) => boolean
|
|
244
|
-
unmarshal: (err: Error) => ResilientError
|
|
245
31
|
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
**Methods:**
|
|
249
|
-
- `match(err)` - Determines if the converter can handle the error
|
|
250
|
-
- `convert(err)` - Converts the error to a ResilientError
|
|
251
|
-
- `isMarshaled(err)` - Checks if the error is in marshaled form
|
|
252
|
-
- `unmarshal(err)` - Unmarshals the error back to ResilientError
|
|
253
|
-
|
|
254
|
-
#### `ResilientErrorConstructor<T>`
|
|
255
|
-
|
|
256
|
-
Constructor interface for ResilientError classes.
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
interface ResilientErrorConstructor<T extends ResilientError = ResilientError> {
|
|
260
|
-
new (type: string, message: string, stack?: string): T
|
|
261
|
-
new (message: string, stack?: string): T
|
|
262
|
-
typeName: string
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
32
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
#### `SEPARATOR`
|
|
269
|
-
|
|
270
|
-
The default separator used in marshaled error messages.
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
const SEPARATOR = '|||'
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
#### `RESILENT_ERROR`
|
|
277
|
-
|
|
278
|
-
The default type name for ResilientError instances.
|
|
279
|
-
|
|
280
|
-
```typescript
|
|
281
|
-
const RESILENT_ERROR = 'ResilientError'
|
|
33
|
+
ResilientError.registerErrorClass(ProjectResourceError)
|
|
282
34
|
```
|
|
283
35
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
### Basic Error Handling
|
|
36
|
+
Marshal errors across service boundaries:
|
|
287
37
|
|
|
288
38
|
```typescript
|
|
289
|
-
import {
|
|
290
|
-
|
|
291
|
-
// Create a resilient error
|
|
292
|
-
const error = new ResilientError('ValidationError', 'Invalid email format')
|
|
293
|
-
|
|
294
|
-
// Ensure any error is resilient
|
|
295
|
-
const resilientError = enuserError(new Error('Something went wrong'))
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Custom Error Types
|
|
39
|
+
import { marshalError, ResilientError } from '@owlmeans/error'
|
|
299
40
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
class ValidationError extends ResilientError {
|
|
304
|
-
static typeName = 'ValidationError'
|
|
305
|
-
|
|
306
|
-
constructor(field: string, message: string) {
|
|
307
|
-
super(ValidationError.typeName, `${field}: ${message}`)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
41
|
+
// Server side: serialize for transport
|
|
42
|
+
const serialized = marshalError(caughtError)
|
|
310
43
|
|
|
311
|
-
//
|
|
312
|
-
ResilientError.
|
|
44
|
+
// Client side: reconstruct the typed error
|
|
45
|
+
const restored = ResilientError.ensure(receivedError)
|
|
313
46
|
```
|
|
314
47
|
|
|
315
|
-
|
|
48
|
+
## API
|
|
316
49
|
|
|
317
|
-
|
|
318
|
-
import { ResilientError, marshalError, enuserError } from '@owlmeans/error'
|
|
50
|
+
### `ResilientError`
|
|
319
51
|
|
|
320
|
-
|
|
321
|
-
function handleServerError(error: Error) {
|
|
322
|
-
const marshaled = marshalError(error)
|
|
323
|
-
return { error: marshaled.message }
|
|
324
|
-
}
|
|
52
|
+
Base class for all OwlMeans errors.
|
|
325
53
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
```
|
|
54
|
+
- `static typeName: string` — override in subclasses to identify the error type
|
|
55
|
+
- `static registerErrorClass(cls)` — register a subclass for automatic reconstruction from JSON
|
|
56
|
+
- `static ensure(err, throwOnUnknown?)` — convert any error to `ResilientError`
|
|
57
|
+
- `static marshal(err)` — serialize an error to a transportable `Error` object
|
|
58
|
+
- `type: string` — error type identifier set in the constructor
|
|
333
59
|
|
|
334
|
-
### Error
|
|
60
|
+
### `marshalError(err): Error`
|
|
335
61
|
|
|
336
|
-
|
|
337
|
-
import { ResilientError, createErrorConverter } from '@owlmeans/error'
|
|
338
|
-
|
|
339
|
-
class NetworkError extends ResilientError {
|
|
340
|
-
static typeName = 'NetworkError'
|
|
341
|
-
}
|
|
62
|
+
Convenience: ensures the error is a `ResilientError`, then marshals it.
|
|
342
63
|
|
|
343
|
-
|
|
344
|
-
const converter = createErrorConverter(NetworkError, TypeError)
|
|
345
|
-
ResilientError.converters.push(converter)
|
|
64
|
+
### `enuserError<T>(err): T`
|
|
346
65
|
|
|
347
|
-
|
|
348
|
-
const converted = ResilientError.ensure(new TypeError('Network failure'))
|
|
349
|
-
// converted will be a NetworkError instance
|
|
350
|
-
```
|
|
66
|
+
Ensures an unknown caught value is a `ResilientError`. Alias for `ResilientError.ensure`.
|
|
351
67
|
|
|
352
|
-
###
|
|
68
|
+
### `ValueOrError<T>`
|
|
353
69
|
|
|
354
70
|
```typescript
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
function fetchUserData(id: string): ValueOrError<User> {
|
|
358
|
-
try {
|
|
359
|
-
// Simulate API call
|
|
360
|
-
return { id, name: 'John Doe' }
|
|
361
|
-
} catch (error) {
|
|
362
|
-
return new ResilientError('FetchError', 'Failed to fetch user')
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const result = fetchUserData('123')
|
|
367
|
-
if (result instanceof ResilientError) {
|
|
368
|
-
console.error('Error:', result.message)
|
|
369
|
-
} else {
|
|
370
|
-
console.log('User:', result.name)
|
|
371
|
-
}
|
|
71
|
+
type ValueOrError<T> = T | ResilientError
|
|
372
72
|
```
|
|
373
73
|
|
|
374
|
-
##
|
|
375
|
-
|
|
376
|
-
1. **Define Custom Error Types**: Create specific error classes for different error categories
|
|
377
|
-
2. **Register Error Classes**: Use `registerErrorClass()` to enable automatic conversion
|
|
378
|
-
3. **Use Helper Functions**: Leverage `enuserError()` and `marshalError()` for common operations
|
|
379
|
-
4. **Implement finalizeUnmarshal()**: Override in custom error classes for post-processing
|
|
380
|
-
5. **Type Safety**: Use `ValueOrError<T>` type for functions that may return errors
|
|
381
|
-
|
|
382
|
-
## Integration with OwlMeans Common
|
|
383
|
-
|
|
384
|
-
This package integrates with the broader OwlMeans Common library ecosystem, following the established patterns for:
|
|
385
|
-
- **Types**: Error-related type definitions
|
|
386
|
-
- **Helpers**: Utility functions for error handling
|
|
387
|
-
- **Service**: Domain-specific error handling logic
|
|
388
|
-
- **i18n**: Internationalization support for error messages
|
|
74
|
+
## Related Packages
|
|
389
75
|
|
|
390
|
-
|
|
76
|
+
- [`@owlmeans/context`](../context) — context and services that propagate errors through the app
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/error",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,12 +21,13 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@owlmeans/i18n": "^0.1.
|
|
24
|
+
"@owlmeans/i18n": "^0.1.4"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
27
28
|
"nodemon": "^3.1.11",
|
|
28
29
|
"npm-check": "^6.0.1",
|
|
29
|
-
"typescript": "^
|
|
30
|
+
"typescript": "^6.0.2"
|
|
30
31
|
},
|
|
31
32
|
"publishConfig": {
|
|
32
33
|
"access": "public"
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": [
|
|
3
|
-
"
|
|
3
|
+
"@owlmeans/dep-config/tsconfig.base.json"
|
|
4
4
|
],
|
|
5
5
|
"compilerOptions": {
|
|
6
|
-
"rootDir": "./src/",
|
|
7
|
-
"outDir": "./build/"
|
|
6
|
+
"rootDir": "./src/",
|
|
7
|
+
"outDir": "./build/"
|
|
8
8
|
},
|
|
9
|
-
"exclude": [
|
|
10
|
-
|
|
11
|
-
"./build/**/*",
|
|
12
|
-
"./*.ts"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
9
|
+
"exclude": ["./dist/**/*", "./build/**/*", "./*.ts"]
|
|
10
|
+
}
|