@veloxts/core 0.8.0 → 0.8.1
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/CHANGELOG.md +6 -0
- package/dist/errors/domain-error.d.ts +98 -0
- package/dist/errors/domain-error.js +101 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain error base class for business logic errors
|
|
3
|
+
*
|
|
4
|
+
* Provides a typed, abstract error class that user-land code extends to define
|
|
5
|
+
* domain-specific error types with structured data payloads. Extends VeloxError
|
|
6
|
+
* so Fastify's error handler can serialize them automatically.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* class InsufficientStock extends DomainError<{ sku: string; requested: number; available: number }> {
|
|
11
|
+
* readonly code = 'INSUFFICIENT_STOCK' as const;
|
|
12
|
+
* readonly status = 422;
|
|
13
|
+
* readonly message = 'Not enough inventory';
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* throw new InsufficientStock({ sku: 'ABC-123', requested: 10, available: 3 });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @module errors/domain-error
|
|
20
|
+
*/
|
|
21
|
+
import { VeloxError } from '../errors.js';
|
|
22
|
+
/**
|
|
23
|
+
* Branded symbol for cross-package type guard checks.
|
|
24
|
+
* Uses `Symbol.for` so the same symbol is shared across package boundaries.
|
|
25
|
+
*/
|
|
26
|
+
declare const DOMAIN_ERROR_BRAND: unique symbol;
|
|
27
|
+
/**
|
|
28
|
+
* JSON representation of a domain error for API responses.
|
|
29
|
+
*/
|
|
30
|
+
export interface DomainErrorJSON {
|
|
31
|
+
/** Error class name (e.g. "InsufficientStock") */
|
|
32
|
+
error: string;
|
|
33
|
+
/** Human-readable error message */
|
|
34
|
+
message: string;
|
|
35
|
+
/** HTTP status code */
|
|
36
|
+
statusCode: number;
|
|
37
|
+
/** Machine-readable error code (e.g. "INSUFFICIENT_STOCK") */
|
|
38
|
+
code: string;
|
|
39
|
+
/** Structured error data payload */
|
|
40
|
+
data: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Abstract base class for domain-specific business logic errors.
|
|
44
|
+
*
|
|
45
|
+
* Subclasses declare `code`, `status`, and `message` as readonly class fields.
|
|
46
|
+
* The constructor accepts only the typed `data` payload.
|
|
47
|
+
*
|
|
48
|
+
* @template TData - Shape of the structured data payload
|
|
49
|
+
*/
|
|
50
|
+
export declare abstract class DomainError<TData extends Record<string, unknown>> extends VeloxError {
|
|
51
|
+
/**
|
|
52
|
+
* Machine-readable error code (e.g. "INSUFFICIENT_STOCK").
|
|
53
|
+
* Defined by each concrete subclass.
|
|
54
|
+
*/
|
|
55
|
+
abstract readonly code: string;
|
|
56
|
+
/**
|
|
57
|
+
* HTTP status code for this domain error.
|
|
58
|
+
* Defined by each concrete subclass (e.g. 422, 403).
|
|
59
|
+
*/
|
|
60
|
+
abstract readonly status: number;
|
|
61
|
+
/**
|
|
62
|
+
* Human-readable error message.
|
|
63
|
+
* Defined by each concrete subclass as a readonly class field.
|
|
64
|
+
*/
|
|
65
|
+
abstract readonly message: string;
|
|
66
|
+
/**
|
|
67
|
+
* Structured data payload describing the error context.
|
|
68
|
+
*/
|
|
69
|
+
readonly data: TData;
|
|
70
|
+
/**
|
|
71
|
+
* Brand marker for cross-package `isDomainError()` checks.
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
readonly [DOMAIN_ERROR_BRAND]: true;
|
|
75
|
+
/**
|
|
76
|
+
* Creates a new DomainError instance.
|
|
77
|
+
*
|
|
78
|
+
* @param data - Typed data payload for the error
|
|
79
|
+
*/
|
|
80
|
+
constructor(data: TData);
|
|
81
|
+
/**
|
|
82
|
+
* Converts domain error to JSON format for API responses.
|
|
83
|
+
* Includes `code` and `data` alongside the standard VeloxError fields.
|
|
84
|
+
*/
|
|
85
|
+
toJSON(): DomainErrorJSON;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Type guard to check whether an unknown value is a DomainError.
|
|
89
|
+
*
|
|
90
|
+
* Uses a branded symbol (`Symbol.for('velox.domain-error')`) so the check
|
|
91
|
+
* works across package boundaries even when multiple copies of `@veloxts/core`
|
|
92
|
+
* are installed.
|
|
93
|
+
*
|
|
94
|
+
* @param value - Value to check
|
|
95
|
+
* @returns `true` if `value` is a DomainError instance
|
|
96
|
+
*/
|
|
97
|
+
export declare function isDomainError(value: unknown): value is DomainError<Record<string, unknown>>;
|
|
98
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain error base class for business logic errors
|
|
3
|
+
*
|
|
4
|
+
* Provides a typed, abstract error class that user-land code extends to define
|
|
5
|
+
* domain-specific error types with structured data payloads. Extends VeloxError
|
|
6
|
+
* so Fastify's error handler can serialize them automatically.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* class InsufficientStock extends DomainError<{ sku: string; requested: number; available: number }> {
|
|
11
|
+
* readonly code = 'INSUFFICIENT_STOCK' as const;
|
|
12
|
+
* readonly status = 422;
|
|
13
|
+
* readonly message = 'Not enough inventory';
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* throw new InsufficientStock({ sku: 'ABC-123', requested: 10, available: 3 });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @module errors/domain-error
|
|
20
|
+
*/
|
|
21
|
+
import { VeloxError } from '../errors.js';
|
|
22
|
+
/**
|
|
23
|
+
* Branded symbol for cross-package type guard checks.
|
|
24
|
+
* Uses `Symbol.for` so the same symbol is shared across package boundaries.
|
|
25
|
+
*/
|
|
26
|
+
const DOMAIN_ERROR_BRAND = Symbol.for('velox.domain-error');
|
|
27
|
+
/**
|
|
28
|
+
* Abstract base class for domain-specific business logic errors.
|
|
29
|
+
*
|
|
30
|
+
* Subclasses declare `code`, `status`, and `message` as readonly class fields.
|
|
31
|
+
* The constructor accepts only the typed `data` payload.
|
|
32
|
+
*
|
|
33
|
+
* @template TData - Shape of the structured data payload
|
|
34
|
+
*/
|
|
35
|
+
export class DomainError extends VeloxError {
|
|
36
|
+
/**
|
|
37
|
+
* Structured data payload describing the error context.
|
|
38
|
+
*/
|
|
39
|
+
data;
|
|
40
|
+
/**
|
|
41
|
+
* Brand marker for cross-package `isDomainError()` checks.
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
[DOMAIN_ERROR_BRAND] = true;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new DomainError instance.
|
|
47
|
+
*
|
|
48
|
+
* @param data - Typed data payload for the error
|
|
49
|
+
*/
|
|
50
|
+
constructor(data) {
|
|
51
|
+
// Pass placeholder values; subclass field initializers override them after super returns.
|
|
52
|
+
super('', 0);
|
|
53
|
+
this.data = data;
|
|
54
|
+
// Defer property synchronisation to a microtask-free post-init trick:
|
|
55
|
+
// We redefine `statusCode` as a getter so it always reflects the subclass's
|
|
56
|
+
// `status` field, which is set by the subclass's field initializers AFTER
|
|
57
|
+
// this constructor returns.
|
|
58
|
+
Object.defineProperty(this, 'statusCode', {
|
|
59
|
+
get() {
|
|
60
|
+
return this.status;
|
|
61
|
+
},
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
});
|
|
65
|
+
// `name` should reflect the concrete subclass for stack traces and toJSON().
|
|
66
|
+
// Subclass field initializers haven't run yet, so we read from the constructor.
|
|
67
|
+
this.name = this.constructor.name;
|
|
68
|
+
if (Error.captureStackTrace) {
|
|
69
|
+
Error.captureStackTrace(this, this.constructor);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Converts domain error to JSON format for API responses.
|
|
74
|
+
* Includes `code` and `data` alongside the standard VeloxError fields.
|
|
75
|
+
*/
|
|
76
|
+
toJSON() {
|
|
77
|
+
return {
|
|
78
|
+
error: this.name,
|
|
79
|
+
message: this.message,
|
|
80
|
+
statusCode: this.statusCode,
|
|
81
|
+
code: this.code,
|
|
82
|
+
data: this.data,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Type guard to check whether an unknown value is a DomainError.
|
|
88
|
+
*
|
|
89
|
+
* Uses a branded symbol (`Symbol.for('velox.domain-error')`) so the check
|
|
90
|
+
* works across package boundaries even when multiple copies of `@veloxts/core`
|
|
91
|
+
* are installed.
|
|
92
|
+
*
|
|
93
|
+
* @param value - Value to check
|
|
94
|
+
* @returns `true` if `value` is a DomainError instance
|
|
95
|
+
*/
|
|
96
|
+
export function isDomainError(value) {
|
|
97
|
+
if (value == null || typeof value !== 'object') {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return value[DOMAIN_ERROR_BRAND] === true;
|
|
101
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export type { StartOptions } from './app.js';
|
|
|
21
21
|
export { VeloxApp, velox, veloxApp } from './app.js';
|
|
22
22
|
export type { BaseContext } from './context.js';
|
|
23
23
|
export { createContext, isContext, setupContextHook, setupTestContext } from './context.js';
|
|
24
|
+
export type { DomainErrorJSON } from './errors/domain-error.js';
|
|
25
|
+
export { DomainError, isDomainError } from './errors/domain-error.js';
|
|
24
26
|
export type { ConflictErrorResponse, ErrorCode, ErrorResponse, ForbiddenErrorResponse, GenericErrorResponse, InterpolationVars, NotFoundErrorResponse, ServiceUnavailableErrorResponse, TooManyRequestsErrorResponse, UnauthorizedErrorResponse, UnprocessableEntityErrorResponse, ValidationErrorResponse, VeloxCoreErrorCode, VeloxErrorCode, VeloxErrorCodeRegistry, } from './errors.js';
|
|
25
27
|
export { assertNever, ConfigurationError, ConflictError, ForbiddenError, fail, isConfigurationError, isConflictError, isForbiddenError, isNotFoundError, isNotFoundErrorResponse, isServiceUnavailableError, isTooManyRequestsError, isUnauthorizedError, isUnprocessableEntityError, isValidationError, isValidationErrorResponse, isVeloxError, isVeloxFailure, logDeprecation, logWarning, NotFoundError, ServiceUnavailableError, TooManyRequestsError, UnauthorizedError, UnprocessableEntityError, ValidationError, VeloxError, VeloxFailure, } from './errors.js';
|
|
26
28
|
export type { ContextPluginConfig, InferPluginOptions, PluginMetadata, PluginOptions, VeloxPlugin, } from './plugin.js';
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const packageJson = require('../package.json');
|
|
|
21
21
|
export const VELOX_VERSION = packageJson.version ?? '0.0.0-unknown';
|
|
22
22
|
export { VeloxApp, velox, veloxApp } from './app.js';
|
|
23
23
|
export { createContext, isContext, setupContextHook, setupTestContext } from './context.js';
|
|
24
|
+
export { DomainError, isDomainError } from './errors/domain-error.js';
|
|
24
25
|
export { assertNever, ConfigurationError, ConflictError, ForbiddenError, fail, isConfigurationError, isConflictError, isForbiddenError, isNotFoundError, isNotFoundErrorResponse, isServiceUnavailableError, isTooManyRequestsError, isUnauthorizedError, isUnprocessableEntityError, isValidationError, isValidationErrorResponse, isVeloxError, isVeloxFailure, logDeprecation, logWarning, NotFoundError, ServiceUnavailableError, TooManyRequestsError, UnauthorizedError, UnprocessableEntityError, ValidationError, VeloxError, VeloxFailure, } from './errors.js';
|
|
25
26
|
export { defineContextPlugin, definePlugin, isFastifyPlugin, isVeloxPlugin, validatePluginMetadata, } from './plugin.js';
|
|
26
27
|
export { isValidHost, isValidPort } from './utils/config.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Fastify wrapper and plugin system for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"fastify": "5.
|
|
32
|
+
"fastify": "5.8.2",
|
|
33
33
|
"fastify-plugin": "5.1.0",
|
|
34
34
|
"picocolors": "1.1.1"
|
|
35
35
|
},
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@fastify/static": "9.0.0",
|
|
46
|
-
"@types/node": "25.
|
|
47
|
-
"@vitest/coverage-v8": "4.0
|
|
46
|
+
"@types/node": "25.5.0",
|
|
47
|
+
"@vitest/coverage-v8": "4.1.0",
|
|
48
48
|
"typescript": "5.9.3",
|
|
49
|
-
"vitest": "4.0
|
|
49
|
+
"vitest": "4.1.0"
|
|
50
50
|
},
|
|
51
51
|
"keywords": [
|
|
52
52
|
"velox",
|