@zudojs/errors 1.1.0 → 1.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 +1 -1
- package/dist/base/core/errorCause.redact.d.ts +8 -3
- package/dist/base/core/errorCause.redact.js +18 -7
- package/dist/base/types/errorCode.type.d.ts +9 -0
- package/dist/base/types/errorCode.type.js +9 -0
- package/dist/domain/cqrs/cqrsError.result.d.ts +27 -0
- package/dist/domain/cqrs/cqrsError.result.js +50 -0
- package/dist/domain/cqrs/index.d.ts +1 -0
- package/dist/domain/cqrs/index.js +1 -0
- package/dist/domain/event/event.error.d.ts +1 -1
- package/dist/domain/event/event.error.js +1 -1
- package/dist/domain/event/eventError.lifecycle.d.ts +24 -0
- package/dist/domain/event/eventError.lifecycle.js +48 -0
- package/dist/domain/rpc/rpcError.base.d.ts +10 -0
- package/dist/domain/rpc/rpcError.base.js +8 -0
- package/dist/domain/schema/schemaError.base.d.ts +14 -8
- package/dist/domain/serialization/serializationError.types.d.ts +9 -2
- package/dist/domain/serialization/serializationError.types.js +8 -4
- package/dist/domain/transaction/transactionError.types.d.ts +15 -0
- package/dist/domain/transaction/transactionError.types.js +19 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ try {
|
|
|
47
47
|
- `BaseError` with stable `code`, `category`, `severity`, `statusCode`, `expose`, `isOperational`, deep-frozen `metadata` and `cause`
|
|
48
48
|
- `ErrorCode`, `ErrorCategory` and `ErrorSeverity` enums with guards (`isErrorCode`, ...)
|
|
49
49
|
- Domain, infrastructure and system error families (access, state, HTTP, database, network, container, adapter, crypto, ...) with factories and type guards
|
|
50
|
-
- Base classes for other packages' error families, so their `instanceof` checks match: `TransactionError` (+ 10 subclasses), `MiddlewareLimitExceededError` / `MiddlewareDepthExceededError` / `MiddlewareRateLimitError` / `MiddlewareAbortedError`, `TraversalLimitError`, `HttpMiddlewareError` / `HttpMiddlewarePipelineError` / `HttpRequestGuardError`, `OpenAPIError`, `AuthError`, `OAuthError` (with `ErrorCode.OAUTH_*`), `CqrsError`, `ObservabilityError`, `InvalidConstantError` / `ConstantContextError`, and the `zudojs-cli` errors `CLIValidationError` / `CLIGenerationError` / `CLINotInProjectError` / `CLITemplateError`
|
|
50
|
+
- Base classes for other packages' error families, so their `instanceof` checks match: `TransactionError` (+ 10 subclasses), `MiddlewareLimitExceededError` / `MiddlewareDepthExceededError` / `MiddlewareRateLimitError` / `MiddlewareAbortedError`, `TraversalLimitError`, `HttpMiddlewareError` / `HttpMiddlewarePipelineError` / `HttpRequestGuardError`, `OpenAPIError`, `AuthError`, `OAuthError` (with `ErrorCode.OAUTH_*`), `CqrsError` (+ `CommandFailedError` / `QueryFailedError`, thrown when a failed command or query result is unwrapped), `EventBusStoppedError` / `EventBusDisposedError` (re-exported by `@zudojs/events`), `ObservabilityError`, `InvalidConstantError` / `ConstantContextError`, and the `zudojs-cli` errors `CLIValidationError` / `CLIGenerationError` / `CLINotInProjectError` / `CLITemplateError`
|
|
51
51
|
- `withMetadata()` copies any error (including subclasses with custom constructors) with extra metadata
|
|
52
52
|
- Serialization: `toJSON()`/`toLogObject()` for trusted logs (cycle-safe cause chains truncated with `"[MaxDepth]"` after 8 levels across the whole chain; metadata under sensitive keys, sensitive keys in object causes and submitted issue values are redacted, so `JSON.stringify(error)` is safe to log), `serializePublicError` / `ErrorSerializer` / `ErrorHandler.toPublicResult` for untrusted clients (recursive redaction, metadata allow-list)
|
|
53
53
|
- Metadata utilities: `createErrorMetadata`, `mergeErrorMetadata`, `sanitizeErrorMetadata` (drops unsupported values) and `redactErrorMetadata` (removes secrets)
|
|
@@ -10,11 +10,16 @@
|
|
|
10
10
|
* Redacts sensitive keys inside a record without changing its shape:
|
|
11
11
|
* primitives, dates and class instances are kept, plain objects and arrays
|
|
12
12
|
* are walked, cycles stop at `"[Circular]"`, prototype keys are dropped.
|
|
13
|
+
*
|
|
14
|
+
* The walk is depth-bounded exactly as metadata cloning is: a subtree past
|
|
15
|
+
* {@link MAX_METADATA_DEPTH} becomes `"[MaxDepth]"`. Without that bound a
|
|
16
|
+
* parsed request body attached as a cause could overflow the stack *inside*
|
|
17
|
+
* the serializer, turning a logged error into an uncaught `RangeError`.
|
|
13
18
|
*/
|
|
14
|
-
export declare function redactCauseFields(fields: Record<string, unknown>, pattern: RegExp | undefined, seen?: WeakSet<object
|
|
19
|
+
export declare function redactCauseFields(fields: Record<string, unknown>, pattern: RegExp | undefined, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
|
|
15
20
|
/**
|
|
16
21
|
* Redacts one cause value: arrays and plain objects are walked, every other
|
|
17
|
-
* value is returned unchanged.
|
|
22
|
+
* value is returned unchanged. Walking stops at {@link MAX_METADATA_DEPTH}.
|
|
18
23
|
*/
|
|
19
|
-
export declare function redactCauseValue(value: unknown, pattern: RegExp | undefined, seen?: WeakSet<object
|
|
24
|
+
export declare function redactCauseValue(value: unknown, pattern: RegExp | undefined, seen?: WeakSet<object>, depth?: number): unknown;
|
|
20
25
|
//# sourceMappingURL=errorCause.redact.d.ts.map
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module base/core/errorCause.redact
|
|
8
8
|
*/
|
|
9
|
-
import { isForbiddenMetadataKey, isSensitiveMetadataKey, REDACTED_METADATA_VALUE, } from "./errorMetadata.core.js";
|
|
9
|
+
import { isForbiddenMetadataKey, isSensitiveMetadataKey, MAX_METADATA_DEPTH, REDACTED_METADATA_VALUE, } from "./errorMetadata.core.js";
|
|
10
|
+
/** Marker substituted for a cause subtree deeper than {@link MAX_METADATA_DEPTH}. */
|
|
11
|
+
const MAX_DEPTH_VALUE = "[MaxDepth]";
|
|
10
12
|
/** Plain objects (Object.prototype or null prototype) are walked; anything else is kept as-is. */
|
|
11
13
|
function isPlainRecord(value) {
|
|
12
14
|
if (value === null || typeof value !== "object")
|
|
@@ -18,8 +20,13 @@ function isPlainRecord(value) {
|
|
|
18
20
|
* Redacts sensitive keys inside a record without changing its shape:
|
|
19
21
|
* primitives, dates and class instances are kept, plain objects and arrays
|
|
20
22
|
* are walked, cycles stop at `"[Circular]"`, prototype keys are dropped.
|
|
23
|
+
*
|
|
24
|
+
* The walk is depth-bounded exactly as metadata cloning is: a subtree past
|
|
25
|
+
* {@link MAX_METADATA_DEPTH} becomes `"[MaxDepth]"`. Without that bound a
|
|
26
|
+
* parsed request body attached as a cause could overflow the stack *inside*
|
|
27
|
+
* the serializer, turning a logged error into an uncaught `RangeError`.
|
|
21
28
|
*/
|
|
22
|
-
export function redactCauseFields(fields, pattern, seen = new WeakSet()) {
|
|
29
|
+
export function redactCauseFields(fields, pattern, seen = new WeakSet(), depth = 0) {
|
|
23
30
|
const result = {};
|
|
24
31
|
for (const key of Object.keys(fields)) {
|
|
25
32
|
if (isForbiddenMetadataKey(key))
|
|
@@ -29,21 +36,23 @@ export function redactCauseFields(fields, pattern, seen = new WeakSet()) {
|
|
|
29
36
|
: isSensitiveMetadataKey(key, pattern);
|
|
30
37
|
result[key] = sensitive
|
|
31
38
|
? REDACTED_METADATA_VALUE
|
|
32
|
-
: redactCauseValue(fields[key], pattern, seen);
|
|
39
|
+
: redactCauseValue(fields[key], pattern, seen, depth + 1);
|
|
33
40
|
}
|
|
34
41
|
return result;
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
37
44
|
* Redacts one cause value: arrays and plain objects are walked, every other
|
|
38
|
-
* value is returned unchanged.
|
|
45
|
+
* value is returned unchanged. Walking stops at {@link MAX_METADATA_DEPTH}.
|
|
39
46
|
*/
|
|
40
|
-
export function redactCauseValue(value, pattern, seen = new WeakSet()) {
|
|
47
|
+
export function redactCauseValue(value, pattern, seen = new WeakSet(), depth = 0) {
|
|
41
48
|
if (Array.isArray(value)) {
|
|
49
|
+
if (depth > MAX_METADATA_DEPTH)
|
|
50
|
+
return MAX_DEPTH_VALUE;
|
|
42
51
|
if (seen.has(value))
|
|
43
52
|
return "[Circular]";
|
|
44
53
|
seen.add(value);
|
|
45
54
|
try {
|
|
46
|
-
return value.map((entry) => redactCauseValue(entry, pattern, seen));
|
|
55
|
+
return value.map((entry) => redactCauseValue(entry, pattern, seen, depth + 1));
|
|
47
56
|
}
|
|
48
57
|
finally {
|
|
49
58
|
seen.delete(value);
|
|
@@ -51,11 +60,13 @@ export function redactCauseValue(value, pattern, seen = new WeakSet()) {
|
|
|
51
60
|
}
|
|
52
61
|
if (!isPlainRecord(value))
|
|
53
62
|
return value;
|
|
63
|
+
if (depth > MAX_METADATA_DEPTH)
|
|
64
|
+
return MAX_DEPTH_VALUE;
|
|
54
65
|
if (seen.has(value))
|
|
55
66
|
return "[Circular]";
|
|
56
67
|
seen.add(value);
|
|
57
68
|
try {
|
|
58
|
-
return redactCauseFields(value, pattern, seen);
|
|
69
|
+
return redactCauseFields(value, pattern, seen, depth);
|
|
59
70
|
}
|
|
60
71
|
finally {
|
|
61
72
|
seen.delete(value);
|
|
@@ -43,6 +43,12 @@ export declare enum ErrorCode {
|
|
|
43
43
|
SESSION_EXPIRED = "ERR_SESSION_EXPIRED",
|
|
44
44
|
TOKEN_INVALID = "ERR_TOKEN_INVALID",
|
|
45
45
|
TOKEN_EXPIRED = "ERR_TOKEN_EXPIRED",
|
|
46
|
+
/** A token that verified but has been revoked (logout, rotation replay). */
|
|
47
|
+
TOKEN_REVOKED = "ERR_TOKEN_REVOKED",
|
|
48
|
+
/** The account is temporarily locked after repeated failed sign-ins. */
|
|
49
|
+
ACCOUNT_LOCKED = "ERR_ACCOUNT_LOCKED",
|
|
50
|
+
/** The account exists but has been deactivated. */
|
|
51
|
+
ACCOUNT_DEACTIVATED = "ERR_ACCOUNT_DEACTIVATED",
|
|
46
52
|
CRYPTO = "ERR_CRYPTO",
|
|
47
53
|
CRYPTO_KEY = "ERR_CRYPTO_KEY",
|
|
48
54
|
CRYPTO_HASH = "ERR_CRYPTO_HASH",
|
|
@@ -84,6 +90,8 @@ export declare enum ErrorCode {
|
|
|
84
90
|
QUERY_HANDLER_NOT_FOUND = "ERR_QUERY_HANDLER_NOT_FOUND",
|
|
85
91
|
INVALID_COMMAND = "ERR_INVALID_COMMAND",
|
|
86
92
|
INVALID_QUERY = "ERR_INVALID_QUERY",
|
|
93
|
+
COMMAND_FAILED = "ERR_COMMAND_FAILED",
|
|
94
|
+
QUERY_FAILED = "ERR_QUERY_FAILED",
|
|
87
95
|
EVENT_HANDLER_FAILED = "ERR_EVENT_HANDLER_FAILED",
|
|
88
96
|
CONFIGURATION_ERROR = "ERR_CONFIGURATION_ERROR",
|
|
89
97
|
CONTAINER_DUPLICATE_REGISTRATION = "ERR_CONTAINER_DUPLICATE_REGISTRATION",
|
|
@@ -114,6 +122,7 @@ export declare enum ErrorCode {
|
|
|
114
122
|
EVENT_REGISTRY_DISPOSED = "ERR_EVENT_REGISTRY_DISPOSED",
|
|
115
123
|
EVENT_BUS_DISPOSED = "ERR_EVENT_BUS_DISPOSED",
|
|
116
124
|
EVENT_SUBSCRIPTION_CLOSED = "ERR_EVENT_SUBSCRIPTION_CLOSED",
|
|
125
|
+
EVENT_LISTENER_LIMIT_EXCEEDED = "ERR_EVENT_LISTENER_LIMIT_EXCEEDED",
|
|
117
126
|
EVENT_TIMEOUT = "ERR_EVENT_TIMEOUT",
|
|
118
127
|
EVENT_SERIALIZATION_FAILED = "ERR_EVENT_SERIALIZATION_FAILED",
|
|
119
128
|
EVENT_DESERIALIZATION_FAILED = "ERR_EVENT_DESERIALIZATION_FAILED",
|
|
@@ -44,6 +44,12 @@ export var ErrorCode;
|
|
|
44
44
|
ErrorCode["SESSION_EXPIRED"] = "ERR_SESSION_EXPIRED";
|
|
45
45
|
ErrorCode["TOKEN_INVALID"] = "ERR_TOKEN_INVALID";
|
|
46
46
|
ErrorCode["TOKEN_EXPIRED"] = "ERR_TOKEN_EXPIRED";
|
|
47
|
+
/** A token that verified but has been revoked (logout, rotation replay). */
|
|
48
|
+
ErrorCode["TOKEN_REVOKED"] = "ERR_TOKEN_REVOKED";
|
|
49
|
+
/** The account is temporarily locked after repeated failed sign-ins. */
|
|
50
|
+
ErrorCode["ACCOUNT_LOCKED"] = "ERR_ACCOUNT_LOCKED";
|
|
51
|
+
/** The account exists but has been deactivated. */
|
|
52
|
+
ErrorCode["ACCOUNT_DEACTIVATED"] = "ERR_ACCOUNT_DEACTIVATED";
|
|
47
53
|
ErrorCode["CRYPTO"] = "ERR_CRYPTO";
|
|
48
54
|
ErrorCode["CRYPTO_KEY"] = "ERR_CRYPTO_KEY";
|
|
49
55
|
ErrorCode["CRYPTO_HASH"] = "ERR_CRYPTO_HASH";
|
|
@@ -86,6 +92,8 @@ export var ErrorCode;
|
|
|
86
92
|
ErrorCode["QUERY_HANDLER_NOT_FOUND"] = "ERR_QUERY_HANDLER_NOT_FOUND";
|
|
87
93
|
ErrorCode["INVALID_COMMAND"] = "ERR_INVALID_COMMAND";
|
|
88
94
|
ErrorCode["INVALID_QUERY"] = "ERR_INVALID_QUERY";
|
|
95
|
+
ErrorCode["COMMAND_FAILED"] = "ERR_COMMAND_FAILED";
|
|
96
|
+
ErrorCode["QUERY_FAILED"] = "ERR_QUERY_FAILED";
|
|
89
97
|
ErrorCode["EVENT_HANDLER_FAILED"] = "ERR_EVENT_HANDLER_FAILED";
|
|
90
98
|
ErrorCode["CONFIGURATION_ERROR"] = "ERR_CONFIGURATION_ERROR";
|
|
91
99
|
// Container
|
|
@@ -120,6 +128,7 @@ export var ErrorCode;
|
|
|
120
128
|
ErrorCode["EVENT_REGISTRY_DISPOSED"] = "ERR_EVENT_REGISTRY_DISPOSED";
|
|
121
129
|
ErrorCode["EVENT_BUS_DISPOSED"] = "ERR_EVENT_BUS_DISPOSED";
|
|
122
130
|
ErrorCode["EVENT_SUBSCRIPTION_CLOSED"] = "ERR_EVENT_SUBSCRIPTION_CLOSED";
|
|
131
|
+
ErrorCode["EVENT_LISTENER_LIMIT_EXCEEDED"] = "ERR_EVENT_LISTENER_LIMIT_EXCEEDED";
|
|
123
132
|
ErrorCode["EVENT_TIMEOUT"] = "ERR_EVENT_TIMEOUT";
|
|
124
133
|
ErrorCode["EVENT_SERIALIZATION_FAILED"] = "ERR_EVENT_SERIALIZATION_FAILED";
|
|
125
134
|
ErrorCode["EVENT_DESERIALIZATION_FAILED"] = "ERR_EVENT_DESERIALIZATION_FAILED";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors raised when a failed command or query result is unwrapped.
|
|
3
|
+
*/
|
|
4
|
+
import { CqrsError } from "./cqrsError.base.js";
|
|
5
|
+
/**
|
|
6
|
+
* Thrown by `unwrapCommandResult` for a result whose status is `"failure"`.
|
|
7
|
+
*
|
|
8
|
+
* `failure` holds the failure payload the result carried, which is also the
|
|
9
|
+
* error's `cause`. Not exposed to clients: the payload is an internal value.
|
|
10
|
+
*/
|
|
11
|
+
export declare class CommandFailedError extends CqrsError {
|
|
12
|
+
readonly commandType: string;
|
|
13
|
+
readonly failure: unknown;
|
|
14
|
+
constructor(commandType: string, failure: unknown);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Thrown by `unwrapQueryResult` for a result whose status is `"failure"`.
|
|
18
|
+
*
|
|
19
|
+
* `failure` holds the failure payload the result carried, which is also the
|
|
20
|
+
* error's `cause`. Not exposed to clients: the payload is an internal value.
|
|
21
|
+
*/
|
|
22
|
+
export declare class QueryFailedError extends CqrsError {
|
|
23
|
+
readonly queryType: string;
|
|
24
|
+
readonly failure: unknown;
|
|
25
|
+
constructor(queryType: string, failure: unknown);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=cqrsError.result.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors raised when a failed command or query result is unwrapped.
|
|
3
|
+
*/
|
|
4
|
+
import { ErrorCode } from "../../base/types/errorCode.type.js";
|
|
5
|
+
import { CqrsError } from "./cqrsError.base.js";
|
|
6
|
+
/**
|
|
7
|
+
* Thrown by `unwrapCommandResult` for a result whose status is `"failure"`.
|
|
8
|
+
*
|
|
9
|
+
* `failure` holds the failure payload the result carried, which is also the
|
|
10
|
+
* error's `cause`. Not exposed to clients: the payload is an internal value.
|
|
11
|
+
*/
|
|
12
|
+
export class CommandFailedError extends CqrsError {
|
|
13
|
+
commandType;
|
|
14
|
+
failure;
|
|
15
|
+
constructor(commandType, failure) {
|
|
16
|
+
super(`Command "${commandType}" failed.`, {
|
|
17
|
+
code: ErrorCode.COMMAND_FAILED,
|
|
18
|
+
statusCode: 500,
|
|
19
|
+
expose: false,
|
|
20
|
+
isOperational: true,
|
|
21
|
+
cause: failure,
|
|
22
|
+
metadata: { commandType },
|
|
23
|
+
});
|
|
24
|
+
this.commandType = commandType;
|
|
25
|
+
this.failure = failure;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Thrown by `unwrapQueryResult` for a result whose status is `"failure"`.
|
|
30
|
+
*
|
|
31
|
+
* `failure` holds the failure payload the result carried, which is also the
|
|
32
|
+
* error's `cause`. Not exposed to clients: the payload is an internal value.
|
|
33
|
+
*/
|
|
34
|
+
export class QueryFailedError extends CqrsError {
|
|
35
|
+
queryType;
|
|
36
|
+
failure;
|
|
37
|
+
constructor(queryType, failure) {
|
|
38
|
+
super(`Query "${queryType}" failed.`, {
|
|
39
|
+
code: ErrorCode.QUERY_FAILED,
|
|
40
|
+
statusCode: 500,
|
|
41
|
+
expose: false,
|
|
42
|
+
isOperational: true,
|
|
43
|
+
cause: failure,
|
|
44
|
+
metadata: { queryType },
|
|
45
|
+
});
|
|
46
|
+
this.queryType = queryType;
|
|
47
|
+
this.failure = failure;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=cqrsError.result.js.map
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
export { EventError, createEventError, isEventError, toEventError, } from "./eventError.base.js";
|
|
5
5
|
export type { EventErrorOptions } from "./eventError.base.js";
|
|
6
6
|
export { EventHandlerError, createEventHandlerError, EventHandlerNotFoundError, DuplicateEventHandlerError, EventMiddlewareError, } from "./eventError.handler.js";
|
|
7
|
-
export { EventPublishError, InvalidEventError, EventTypeNotFoundError, DuplicateEventDefinitionError, EventDefinitionNotFoundError, EventDispatchAbortedError, EventEmitterDisposedError, EventRegistryDisposedError, EventSubscriptionClosedError, EventBusDisposedError, EventTimeoutError, } from "./eventError.lifecycle.js";
|
|
7
|
+
export { EventPublishError, InvalidEventError, EventTypeNotFoundError, DuplicateEventDefinitionError, EventDefinitionNotFoundError, EventDispatchAbortedError, EventEmitterDisposedError, EventRegistryDisposedError, EventSubscriptionClosedError, EventBusDisposedError, EventBusStoppedError, EventListenerLimitExceededError, EventTimeoutError, } from "./eventError.lifecycle.js";
|
|
8
8
|
export { EventSerializationError, EventDeserializationError, } from "./eventError.serialization.js";
|
|
9
9
|
//# sourceMappingURL=event.error.d.ts.map
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { EventError, createEventError, isEventError, toEventError, } from "./eventError.base.js";
|
|
5
5
|
export { EventHandlerError, createEventHandlerError, EventHandlerNotFoundError, DuplicateEventHandlerError, EventMiddlewareError, } from "./eventError.handler.js";
|
|
6
|
-
export { EventPublishError, InvalidEventError, EventTypeNotFoundError, DuplicateEventDefinitionError, EventDefinitionNotFoundError, EventDispatchAbortedError, EventEmitterDisposedError, EventRegistryDisposedError, EventSubscriptionClosedError, EventBusDisposedError, EventTimeoutError, } from "./eventError.lifecycle.js";
|
|
6
|
+
export { EventPublishError, InvalidEventError, EventTypeNotFoundError, DuplicateEventDefinitionError, EventDefinitionNotFoundError, EventDispatchAbortedError, EventEmitterDisposedError, EventRegistryDisposedError, EventSubscriptionClosedError, EventBusDisposedError, EventBusStoppedError, EventListenerLimitExceededError, EventTimeoutError, } from "./eventError.lifecycle.js";
|
|
7
7
|
export { EventSerializationError, EventDeserializationError, } from "./eventError.serialization.js";
|
|
8
8
|
//# sourceMappingURL=event.error.js.map
|
|
@@ -62,6 +62,30 @@ export declare class EventSubscriptionClosedError extends EventError {
|
|
|
62
62
|
export declare class EventBusDisposedError extends EventError {
|
|
63
63
|
constructor();
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Error thrown when publishing or subscribing on a stopped event bus.
|
|
67
|
+
* Call `start()` to resume.
|
|
68
|
+
*/
|
|
69
|
+
export declare class EventBusStoppedError extends EventError {
|
|
70
|
+
readonly operation: string;
|
|
71
|
+
constructor(operation: string);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Error thrown when a pattern exceeds its configured handler limit.
|
|
75
|
+
*
|
|
76
|
+
* The limit exists to catch a subscribe-without-unsubscribe leak. Registering
|
|
77
|
+
* past it is a programming fault rather than bad input, so this is reported as
|
|
78
|
+
* internal and is never exposed to a caller.
|
|
79
|
+
*
|
|
80
|
+
* A registry only raises this when it is configured to enforce the limit;
|
|
81
|
+
* the default is a one-shot warning, which does not interrupt registration.
|
|
82
|
+
*/
|
|
83
|
+
export declare class EventListenerLimitExceededError extends EventError {
|
|
84
|
+
readonly pattern: string;
|
|
85
|
+
readonly count: number;
|
|
86
|
+
readonly limit: number;
|
|
87
|
+
constructor(pattern: string, count: number, limit: number);
|
|
88
|
+
}
|
|
65
89
|
/** Error thrown when an event operation times out. */
|
|
66
90
|
export declare class EventTimeoutError extends EventError {
|
|
67
91
|
readonly timeoutMs: number;
|
|
@@ -130,6 +130,54 @@ export class EventBusDisposedError extends EventError {
|
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Error thrown when publishing or subscribing on a stopped event bus.
|
|
135
|
+
* Call `start()` to resume.
|
|
136
|
+
*/
|
|
137
|
+
export class EventBusStoppedError extends EventError {
|
|
138
|
+
operation;
|
|
139
|
+
constructor(operation) {
|
|
140
|
+
super(`Cannot ${operation} on a stopped event bus. Call start() first.`, {
|
|
141
|
+
code: ErrorCode.LIFECYCLE_STATE,
|
|
142
|
+
statusCode: 500,
|
|
143
|
+
expose: false,
|
|
144
|
+
isOperational: true,
|
|
145
|
+
metadata: { operation },
|
|
146
|
+
});
|
|
147
|
+
this.operation = operation;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Error thrown when a pattern exceeds its configured handler limit.
|
|
152
|
+
*
|
|
153
|
+
* The limit exists to catch a subscribe-without-unsubscribe leak. Registering
|
|
154
|
+
* past it is a programming fault rather than bad input, so this is reported as
|
|
155
|
+
* internal and is never exposed to a caller.
|
|
156
|
+
*
|
|
157
|
+
* A registry only raises this when it is configured to enforce the limit;
|
|
158
|
+
* the default is a one-shot warning, which does not interrupt registration.
|
|
159
|
+
*/
|
|
160
|
+
export class EventListenerLimitExceededError extends EventError {
|
|
161
|
+
pattern;
|
|
162
|
+
count;
|
|
163
|
+
limit;
|
|
164
|
+
constructor(pattern, count, limit) {
|
|
165
|
+
assertFiniteNonNegative("count", count);
|
|
166
|
+
assertFiniteNonNegative("limit", limit);
|
|
167
|
+
super(`Possible event handler leak: ${count} handlers registered for ` +
|
|
168
|
+
`"${pattern}" (limit ${limit}). Unsubscribe handlers you no longer ` +
|
|
169
|
+
"need or raise maxHandlersPerPattern / maxListeners.", {
|
|
170
|
+
code: ErrorCode.EVENT_LISTENER_LIMIT_EXCEEDED,
|
|
171
|
+
metadata: { pattern, count, limit },
|
|
172
|
+
statusCode: 500,
|
|
173
|
+
expose: false,
|
|
174
|
+
isOperational: false,
|
|
175
|
+
});
|
|
176
|
+
this.pattern = pattern;
|
|
177
|
+
this.count = count;
|
|
178
|
+
this.limit = limit;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
133
181
|
/** Error thrown when an event operation times out. */
|
|
134
182
|
export class EventTimeoutError extends EventError {
|
|
135
183
|
timeoutMs;
|
|
@@ -9,10 +9,19 @@ import { ErrorSeverity } from "../../base/types/errorSeverity.type.js";
|
|
|
9
9
|
export interface RPCErrorOptions extends Omit<BaseErrorOptions, "category"> {
|
|
10
10
|
readonly category?: ErrorCategory;
|
|
11
11
|
readonly procedureName?: string;
|
|
12
|
+
/** Structured, caller-safe detail sent with the error's wire payload. */
|
|
13
|
+
readonly details?: unknown;
|
|
12
14
|
}
|
|
13
15
|
/** Base error for all RPC failures. */
|
|
14
16
|
export declare class RPCError extends BaseError {
|
|
15
17
|
readonly procedureName?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Structured, caller-safe detail carried by the wire payload — validation
|
|
20
|
+
* issues, `{ retryAfter }` for a rate limit, or whatever a custom error
|
|
21
|
+
* sent. Set on errors an RPC client rebuilds from a response; `undefined`
|
|
22
|
+
* when the payload had none.
|
|
23
|
+
*/
|
|
24
|
+
readonly details?: unknown;
|
|
16
25
|
constructor(message: string, options?: RPCErrorOptions);
|
|
17
26
|
toJSON(): {
|
|
18
27
|
name: string;
|
|
@@ -27,6 +36,7 @@ export declare class RPCError extends BaseError {
|
|
|
27
36
|
stack?: string;
|
|
28
37
|
cause?: import("../../base/types/baseError.type.js").SerializedBaseError | unknown;
|
|
29
38
|
procedureName?: string | undefined;
|
|
39
|
+
details?: {} | null | undefined;
|
|
30
40
|
};
|
|
31
41
|
}
|
|
32
42
|
/** Creates an RPC error. */
|
|
@@ -19,6 +19,13 @@ export class RPCError extends BaseError {
|
|
|
19
19
|
isOperational: options.isOperational ?? true,
|
|
20
20
|
});
|
|
21
21
|
this.procedureName = options.procedureName;
|
|
22
|
+
if (options.details !== undefined) {
|
|
23
|
+
Object.defineProperty(this, "details", {
|
|
24
|
+
value: options.details,
|
|
25
|
+
enumerable: true,
|
|
26
|
+
configurable: true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
22
29
|
}
|
|
23
30
|
toJSON() {
|
|
24
31
|
return {
|
|
@@ -26,6 +33,7 @@ export class RPCError extends BaseError {
|
|
|
26
33
|
...(this.procedureName !== undefined
|
|
27
34
|
? { procedureName: this.procedureName }
|
|
28
35
|
: {}),
|
|
36
|
+
...(this.details !== undefined ? { details: this.details } : {}),
|
|
29
37
|
};
|
|
30
38
|
}
|
|
31
39
|
}
|
|
@@ -5,10 +5,16 @@ import { BaseError } from "../../base/core/baseError.core.js";
|
|
|
5
5
|
import type { BaseErrorOptions } from "../../base/types/baseError.type.js";
|
|
6
6
|
import { ErrorCategory } from "../../base/types/errorCategory.type.js";
|
|
7
7
|
import { ErrorSeverity } from "../../base/types/errorSeverity.type.js";
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Options for constructing a SchemaError.
|
|
10
|
+
*
|
|
11
|
+
* @typeParam TIssue - Shape of one issue. `@zudojs/errors` cannot know it
|
|
12
|
+
* (the schema package sits above it), so it defaults to `unknown`;
|
|
13
|
+
* `@zudojs/schema` throws `SchemaError<SchemaIssue>`.
|
|
14
|
+
*/
|
|
15
|
+
export interface SchemaErrorOptions<TIssue = unknown> extends Omit<BaseErrorOptions, "category"> {
|
|
10
16
|
readonly category?: ErrorCategory;
|
|
11
|
-
readonly issues?: readonly
|
|
17
|
+
readonly issues?: readonly TIssue[];
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* Base error for all schema validation failures.
|
|
@@ -19,9 +25,9 @@ export interface SchemaErrorOptions extends Omit<BaseErrorOptions, "category"> {
|
|
|
19
25
|
* (`value`, `received`, `input`, `actual`) with a type/size description so
|
|
20
26
|
* that secrets submitted by a client are never echoed back or logged.
|
|
21
27
|
*/
|
|
22
|
-
export declare class SchemaError extends BaseError {
|
|
23
|
-
readonly issues: readonly
|
|
24
|
-
constructor(message: string, options?: SchemaErrorOptions);
|
|
28
|
+
export declare class SchemaError<TIssue = unknown> extends BaseError {
|
|
29
|
+
readonly issues: readonly TIssue[];
|
|
30
|
+
constructor(message: string, options?: SchemaErrorOptions<TIssue>);
|
|
25
31
|
/** Returns whether any issues were recorded. */
|
|
26
32
|
hasIssues(): boolean;
|
|
27
33
|
/** Returns a serialized representation including (redacted) issues. */
|
|
@@ -37,11 +43,11 @@ export declare class SchemaError extends BaseError {
|
|
|
37
43
|
metadata: Readonly<import("../../index.js").ErrorMetadata>;
|
|
38
44
|
stack?: string;
|
|
39
45
|
cause?: import("../../base/types/baseError.type.js").SerializedBaseError | unknown;
|
|
40
|
-
issues: readonly
|
|
46
|
+
issues: readonly TIssue[];
|
|
41
47
|
};
|
|
42
48
|
}
|
|
43
49
|
/** Creates a schema error. */
|
|
44
|
-
export declare function createSchemaError(message: string, options?: SchemaErrorOptions): SchemaError
|
|
50
|
+
export declare function createSchemaError<TIssue = unknown>(message: string, options?: SchemaErrorOptions<TIssue>): SchemaError<TIssue>;
|
|
45
51
|
/** Determines whether an unknown value is a SchemaError. */
|
|
46
52
|
export declare function isSchemaError(value: unknown): value is SchemaError;
|
|
47
53
|
//# sourceMappingURL=schemaError.base.d.ts.map
|
|
@@ -42,14 +42,21 @@ export declare class CircularReferenceError extends SerializationError {
|
|
|
42
42
|
/**
|
|
43
43
|
* Error thrown when maximum serialization depth is exceeded.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
45
|
+
* By default over-deep data is a server-side data bug, so this is an
|
|
46
|
+
* internal (500) error. Code that checks UNTRUSTED input (for example
|
|
47
|
+
* `assertDepthWithinLimit` in `@zudojs/validation`) passes
|
|
48
|
+
* `{ statusCode: 400, expose: true }`: too-deep client input is a client
|
|
49
|
+
* error. The message holds only the two numbers, so it is safe to expose.
|
|
46
50
|
*/
|
|
47
51
|
export declare class SerializationDepthError extends SerializationError {
|
|
48
52
|
readonly depth: number;
|
|
49
53
|
readonly maxDepth: number;
|
|
50
54
|
/** @deprecated Use `maxDepth`. */
|
|
51
55
|
readonly maxDepthValue: number;
|
|
52
|
-
constructor(depth: number, maxDepth: number
|
|
56
|
+
constructor(depth: number, maxDepth: number, options?: {
|
|
57
|
+
readonly statusCode?: number;
|
|
58
|
+
readonly expose?: boolean;
|
|
59
|
+
});
|
|
53
60
|
}
|
|
54
61
|
/** Error thrown when a serialized payload exceeds the size limit. */
|
|
55
62
|
export declare class SerializationPayloadTooLargeError extends SerializationError {
|
|
@@ -74,20 +74,24 @@ export class CircularReferenceError extends SerializationError {
|
|
|
74
74
|
/**
|
|
75
75
|
* Error thrown when maximum serialization depth is exceeded.
|
|
76
76
|
*
|
|
77
|
-
*
|
|
77
|
+
* By default over-deep data is a server-side data bug, so this is an
|
|
78
|
+
* internal (500) error. Code that checks UNTRUSTED input (for example
|
|
79
|
+
* `assertDepthWithinLimit` in `@zudojs/validation`) passes
|
|
80
|
+
* `{ statusCode: 400, expose: true }`: too-deep client input is a client
|
|
81
|
+
* error. The message holds only the two numbers, so it is safe to expose.
|
|
78
82
|
*/
|
|
79
83
|
export class SerializationDepthError extends SerializationError {
|
|
80
84
|
depth;
|
|
81
85
|
maxDepth;
|
|
82
86
|
/** @deprecated Use `maxDepth`. */
|
|
83
87
|
maxDepthValue;
|
|
84
|
-
constructor(depth, maxDepth) {
|
|
88
|
+
constructor(depth, maxDepth, options = {}) {
|
|
85
89
|
super(`Maximum serialization depth exceeded: ${depth} > ${maxDepth}`, {
|
|
86
90
|
code: ErrorCode.MAX_DEPTH_EXCEEDED,
|
|
87
91
|
depth,
|
|
88
92
|
maxDepth,
|
|
89
|
-
statusCode: 500,
|
|
90
|
-
expose: false,
|
|
93
|
+
statusCode: options.statusCode ?? 500,
|
|
94
|
+
expose: options.expose ?? false,
|
|
91
95
|
});
|
|
92
96
|
this.depth = depth;
|
|
93
97
|
this.maxDepth = maxDepth;
|
|
@@ -20,8 +20,23 @@ export declare class TransactionRollbackError extends TransactionError {
|
|
|
20
20
|
constructor(transactionId: string, options?: {
|
|
21
21
|
readonly cause?: unknown;
|
|
22
22
|
readonly originalError?: unknown;
|
|
23
|
+
/** Overrides the default "rollback failed" message (for subclasses). */
|
|
24
|
+
readonly message?: string;
|
|
23
25
|
});
|
|
24
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A commit was refused because the transaction was marked rollback-only;
|
|
29
|
+
* the transaction was rolled back instead.
|
|
30
|
+
*
|
|
31
|
+
* Distinct from a rollback that *failed*. It extends
|
|
32
|
+
* `TransactionRollbackError`, so existing `instanceof` checks and the
|
|
33
|
+
* `ERR_DATABASE_TRANSACTION` code still match, while the message and
|
|
34
|
+
* class say what actually happened. `metadata.originalError` carries the
|
|
35
|
+
* reason passed to `markRollbackOnly`.
|
|
36
|
+
*/
|
|
37
|
+
export declare class TransactionRollbackOnlyError extends TransactionRollbackError {
|
|
38
|
+
constructor(transactionId: string, reason?: unknown);
|
|
39
|
+
}
|
|
25
40
|
/** The underlying adapter threw an error. */
|
|
26
41
|
export declare class TransactionAdapterError extends TransactionError {
|
|
27
42
|
constructor(message: string, cause?: unknown);
|
|
@@ -35,7 +35,7 @@ export class TransactionCommitError extends TransactionError {
|
|
|
35
35
|
/** Transaction rollback failed. */
|
|
36
36
|
export class TransactionRollbackError extends TransactionError {
|
|
37
37
|
constructor(transactionId, options) {
|
|
38
|
-
super(`Transaction "${transactionId}" rollback failed`, {
|
|
38
|
+
super(options?.message ?? `Transaction "${transactionId}" rollback failed`, {
|
|
39
39
|
code: ErrorCode.DATABASE_TRANSACTION,
|
|
40
40
|
cause: options?.cause,
|
|
41
41
|
metadata: {
|
|
@@ -47,6 +47,24 @@ export class TransactionRollbackError extends TransactionError {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* A commit was refused because the transaction was marked rollback-only;
|
|
52
|
+
* the transaction was rolled back instead.
|
|
53
|
+
*
|
|
54
|
+
* Distinct from a rollback that *failed*. It extends
|
|
55
|
+
* `TransactionRollbackError`, so existing `instanceof` checks and the
|
|
56
|
+
* `ERR_DATABASE_TRANSACTION` code still match, while the message and
|
|
57
|
+
* class say what actually happened. `metadata.originalError` carries the
|
|
58
|
+
* reason passed to `markRollbackOnly`.
|
|
59
|
+
*/
|
|
60
|
+
export class TransactionRollbackOnlyError extends TransactionRollbackError {
|
|
61
|
+
constructor(transactionId, reason) {
|
|
62
|
+
super(transactionId, {
|
|
63
|
+
originalError: reason ?? "marked rollback-only",
|
|
64
|
+
message: `Transaction "${transactionId}" commit refused: transaction marked rollback-only`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
50
68
|
/** The underlying adapter threw an error. */
|
|
51
69
|
export class TransactionAdapterError extends TransactionError {
|
|
52
70
|
constructor(message, cause) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/errors",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Shared error base class, error codes, and error handling utilities for the Zudojs framework.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"typescript": "7.0.2",
|
|
25
|
-
"vitest": "^
|
|
25
|
+
"vitest": "^5.0.1"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
28
|
"node": ">=24.0.0"
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"errors",
|
|
41
41
|
"error-handling"
|
|
42
42
|
],
|
|
43
|
-
"homepage": "https://
|
|
43
|
+
"homepage": "https://zudojs.oyinlola.site/docs/packages-errors",
|
|
44
44
|
"bugs": {
|
|
45
45
|
"url": "https://github.com/oyinlola-tech/zudo/issues"
|
|
46
46
|
},
|