@dxos/errors 0.8.4-main.84f28bd → 0.8.4-main.937b3ca
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/dist/lib/browser/index.mjs +56 -29
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +56 -29
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/base.d.ts +43 -20
- package/dist/types/src/base.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +331 -66
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -2
- package/src/base.ts +49 -25
- package/src/errors.test.ts +25 -5
- package/src/errors.ts +8 -6
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/errors",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.937b3ca",
|
|
4
4
|
"description": "Error definitions",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": false,
|
|
10
14
|
"type": "module",
|
|
11
15
|
"exports": {
|
|
12
16
|
".": {
|
|
17
|
+
"source": "./src/index.ts",
|
|
13
18
|
"types": "./dist/types/src/index.d.ts",
|
|
14
19
|
"browser": "./dist/lib/browser/index.mjs",
|
|
15
20
|
"node": "./dist/lib/node-esm/index.mjs"
|
package/src/base.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Options for creating a BaseError.
|
|
7
|
+
*/
|
|
8
|
+
export type BaseErrorOptions = ErrorOptions & {
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
8
|
-
* An instance of Error.
|
|
10
|
+
* Override base message.
|
|
9
11
|
*/
|
|
10
|
-
|
|
12
|
+
message?: string;
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Structured details about the error.
|
|
@@ -15,41 +17,63 @@ export type BaseErrorOptions = {
|
|
|
15
17
|
context?: Record<string, unknown>;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Base class for all DXOS errors.
|
|
22
|
+
*/
|
|
23
|
+
export class BaseError<Name extends string = string> extends Error {
|
|
24
|
+
/**
|
|
25
|
+
* Primary way of defining new error classes.
|
|
26
|
+
* Extended class may specialize constructor for required context params.
|
|
27
|
+
* @param name - Error name.
|
|
28
|
+
* @param message - Default error message.
|
|
29
|
+
*/
|
|
30
|
+
static extend<Name extends string = string>(name: Name, message?: string) {
|
|
31
|
+
return class ExtendedError extends BaseError<Name> {
|
|
32
|
+
static override name: Name = name;
|
|
22
33
|
|
|
23
34
|
static is(error: unknown): error is BaseError {
|
|
24
|
-
return typeof error === 'object' && error !== null && '
|
|
35
|
+
return typeof error === 'object' && error !== null && 'name' in error && error.name === name;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static wrap(
|
|
39
|
+
options?: Omit<BaseErrorOptions, 'cause'> & { ifTypeDiffers?: boolean },
|
|
40
|
+
): (error: unknown) => ExtendedError {
|
|
41
|
+
const wrapFn = (error: unknown) => {
|
|
42
|
+
if (options?.ifTypeDiffers === true && this.is(error)) {
|
|
43
|
+
return error as ExtendedError;
|
|
44
|
+
}
|
|
45
|
+
const newError: ExtendedError = new this({ message, ...options, cause: error });
|
|
46
|
+
Error.captureStackTrace(newError, wrapFn); // Position stack-trace to start from the caller of `wrap`.
|
|
47
|
+
return newError;
|
|
48
|
+
};
|
|
49
|
+
return wrapFn;
|
|
25
50
|
}
|
|
26
51
|
|
|
27
|
-
constructor(
|
|
28
|
-
super(
|
|
52
|
+
constructor(options?: BaseErrorOptions) {
|
|
53
|
+
super(name, { message: options?.message ?? message, ...options });
|
|
29
54
|
}
|
|
30
55
|
};
|
|
31
56
|
}
|
|
32
57
|
|
|
33
|
-
|
|
34
|
-
|
|
58
|
+
// NOTE: Errors go through odd transformations and the private fields seem to break.
|
|
59
|
+
override name: Name;
|
|
60
|
+
context: Record<string, unknown>;
|
|
35
61
|
|
|
36
|
-
constructor(
|
|
37
|
-
super(message, options);
|
|
62
|
+
constructor(name: Name, options?: BaseErrorOptions) {
|
|
63
|
+
super(options?.message, { cause: options?.cause });
|
|
38
64
|
|
|
39
|
-
this
|
|
40
|
-
this
|
|
65
|
+
this.name = name;
|
|
66
|
+
this.context = options?.context ?? {};
|
|
41
67
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
42
68
|
}
|
|
43
69
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
get code() {
|
|
49
|
-
return this.#code;
|
|
70
|
+
/** Fallback message. */
|
|
71
|
+
override get message() {
|
|
72
|
+
return this.constructor.name;
|
|
50
73
|
}
|
|
51
74
|
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
// For effect error matching.
|
|
76
|
+
get _tag(): Name {
|
|
77
|
+
return this.name;
|
|
54
78
|
}
|
|
55
79
|
}
|
package/src/errors.test.ts
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
|
+
import { BaseError, type BaseErrorOptions } from './base';
|
|
7
8
|
import { SystemError } from './errors';
|
|
8
9
|
|
|
9
10
|
describe('errors', () => {
|
|
10
11
|
test('error code and message, cause', () => {
|
|
11
|
-
const error = new SystemError('Test message',
|
|
12
|
+
const error = new SystemError({ message: 'Test message', cause: new Error('Test cause'), context: { a: 1, b: 2 } });
|
|
12
13
|
expect(error).toBeInstanceOf(SystemError);
|
|
13
14
|
expect(error).toBeInstanceOf(SystemError);
|
|
14
|
-
expect(error.
|
|
15
|
+
expect(error.name).toBe(SystemError.name);
|
|
16
|
+
expect(error._tag).toBe(SystemError.name);
|
|
15
17
|
expect(error.message).toBe('Test message');
|
|
16
18
|
expect(error.cause).toBeInstanceOf(Error);
|
|
17
19
|
expect((error.cause as Error).message).toBe('Test cause');
|
|
@@ -24,19 +26,37 @@ describe('errors', () => {
|
|
|
24
26
|
expect.fail('Expected error to be thrown');
|
|
25
27
|
} catch (error: any) {
|
|
26
28
|
expect(error).toBeInstanceOf(SystemError);
|
|
27
|
-
expect(String(error)).toEqual('
|
|
29
|
+
expect(String(error)).toEqual('SystemError: Test message');
|
|
28
30
|
const stackLines = error.stack!.split('\n');
|
|
29
|
-
expect(stackLines?.[0]).toEqual('
|
|
31
|
+
expect(stackLines?.[0]).toEqual('SystemError: Test message');
|
|
30
32
|
expect(stackLines?.[1]).toMatch(/^ {4}at two \(.*$/);
|
|
31
33
|
expect(stackLines?.[2]).toMatch(/^ {4}at one \(.*$/);
|
|
32
34
|
}
|
|
33
35
|
});
|
|
36
|
+
|
|
37
|
+
test('custom message', () => {
|
|
38
|
+
class CustomError extends BaseError.extend('CustomError', 'Custom message') {
|
|
39
|
+
constructor(value: number, options?: Omit<BaseErrorOptions, 'context'>) {
|
|
40
|
+
super({ context: { value }, ...options });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const error = new CustomError(1);
|
|
45
|
+
expect(error).toBeInstanceOf(CustomError);
|
|
46
|
+
expect(error.message).toBe('Custom message');
|
|
47
|
+
expect(error.context).toEqual({ value: 1 });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('is', () => {
|
|
51
|
+
const error = new SystemError({ message: 'Test message' });
|
|
52
|
+
expect(SystemError.is(error)).toBe(true);
|
|
53
|
+
});
|
|
34
54
|
});
|
|
35
55
|
|
|
36
56
|
const throwError = () => {
|
|
37
57
|
const one = () => {
|
|
38
58
|
const two = () => {
|
|
39
|
-
throw new SystemError('Test message');
|
|
59
|
+
throw new SystemError({ message: 'Test message' });
|
|
40
60
|
};
|
|
41
61
|
two();
|
|
42
62
|
};
|
package/src/errors.ts
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { BaseError } from './base';
|
|
6
6
|
|
|
7
|
-
export class
|
|
7
|
+
export class ApiError extends BaseError.extend('ApiError', 'API error') {}
|
|
8
8
|
|
|
9
|
-
export class
|
|
9
|
+
export class SystemError extends BaseError.extend('SystemError', 'System error') {}
|
|
10
10
|
|
|
11
|
-
export class
|
|
11
|
+
export class InternalError extends BaseError.extend('InternalError', 'Internal error') {}
|
|
12
12
|
|
|
13
|
-
export class
|
|
13
|
+
export class TimeoutError extends BaseError.extend('TimeoutError', 'Timeout') {}
|
|
14
14
|
|
|
15
|
-
export class
|
|
15
|
+
export class AbortedError extends BaseError.extend('AbortedError', 'Aborted') {}
|
|
16
16
|
|
|
17
|
-
export class
|
|
17
|
+
export class NotImplementedError extends BaseError.extend('NotImplementedError', 'Not implemented') {}
|
|
18
|
+
|
|
19
|
+
export class RuntimeServiceError extends BaseError.extend('RuntimeServiceError', 'Runtime service error') {}
|