@boo-labs/server 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +287 -2
- package/index.mjs +23 -0
- package/package.json +71 -4
- package/source/application/Kernel/index.mjs +1137 -0
- package/source/application/Server/index.mjs +1201 -0
- package/source/application/configurations/Http2CleartextServerConfiguration/index.mjs +168 -0
- package/source/application/configurations/Http2SecureServerConfiguration/index.mjs +172 -0
- package/source/application/configurations/HttpServerConfiguration/index.mjs +169 -0
- package/source/application/configurations/HttpsServerConfiguration/index.mjs +172 -0
- package/source/application/configurations/ServerConfiguration/Options/CORSOptions/CORSOptionsValue.mjs +158 -0
- package/source/application/configurations/ServerConfiguration/Options/CORSOptions/index.mjs +87 -0
- package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/CSRFOptionsValue.mjs +178 -0
- package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/index.mjs +80 -0
- package/source/application/configurations/ServerConfiguration/Options/CompressOptions/CompressOptionsValue.mjs +126 -0
- package/source/application/configurations/ServerConfiguration/Options/CompressOptions/index.mjs +81 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/CookieParserOptionsValue.mjs +107 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/index.mjs +82 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/CookieSessionOptionsValue.mjs +182 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/index.mjs +86 -0
- package/source/application/configurations/ServerConfiguration/Options/ListenOptions/ListenOptionsValue.mjs +95 -0
- package/source/application/configurations/ServerConfiguration/Options/ListenOptions/index.mjs +47 -0
- package/source/application/configurations/ServerConfiguration/Options/MiddlewareOption.mjs +102 -0
- package/source/application/configurations/ServerConfiguration/Options/Options.mjs +105 -0
- package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/RateLimitOptionsValue.mjs +164 -0
- package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/index.mjs +84 -0
- package/source/application/configurations/ServerConfiguration/Options/RequestOptions/RequestOptionsValue.mjs +108 -0
- package/source/application/configurations/ServerConfiguration/Options/RequestOptions/index.mjs +47 -0
- package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/ResponseOptionsValue.mjs +101 -0
- package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/index.mjs +47 -0
- package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/SecurityHeadersOptionsValue.mjs +272 -0
- package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/index.mjs +85 -0
- package/source/application/configurations/ServerConfiguration/Options/ServerOption.mjs +50 -0
- package/source/application/configurations/ServerConfiguration/Options/StaticOptions/StaticOptionsValue.mjs +164 -0
- package/source/application/configurations/ServerConfiguration/Options/StaticOptions/index.mjs +89 -0
- package/source/application/configurations/ServerConfiguration/index.mjs +781 -0
- package/source/application/resolvers/TransportResolver/index.mjs +119 -0
- package/source/application/use-cases/CloseServer/index.mjs +85 -0
- package/source/application/use-cases/ListenServer/index.mjs +98 -0
- package/source/core/EventSystem/index.mjs +110 -0
- package/source/core/Exchange/ExchangeContext.mjs +291 -0
- package/source/core/Exchange/Telemetry.mjs +193 -0
- package/source/core/Exchange/index.mjs +604 -0
- package/source/core/ExchangeLayerBuilder/index.mjs +133 -0
- package/source/core/IPCMain/IPCMain.mjs +507 -0
- package/source/core/IPCMain/IPCProtocol.mjs +441 -0
- package/source/core/IPCMain/IPCServerChannel.mjs +331 -0
- package/source/core/IPCMain/WebSocketAdapter.mjs +189 -0
- package/source/core/Request/BodyParser/BodyParser.mjs +197 -0
- package/source/core/Request/BodyParser/JSONParser.mjs +70 -0
- package/source/core/Request/BodyParser/MultipartParser.mjs +612 -0
- package/source/core/Request/BodyParser/URLEncodedParser.mjs +71 -0
- package/source/core/Request/RequestHeaders.mjs +177 -0
- package/source/core/Request/index.mjs +805 -0
- package/source/core/Response/ResponseHeaders.mjs +402 -0
- package/source/core/Response/index.mjs +1370 -0
- package/source/core/middlewares/CORSMiddleware/index.mjs +289 -0
- package/source/core/middlewares/CSRFMiddleware/index.mjs +284 -0
- package/source/core/middlewares/CompressMiddleware/index.mjs +460 -0
- package/source/core/middlewares/CookieParserMiddleware/index.mjs +194 -0
- package/source/core/middlewares/CookieSessionMiddleware/index.mjs +460 -0
- package/source/core/middlewares/RateLimitMiddleware/index.mjs +245 -0
- package/source/core/middlewares/SecurityHeadersMiddleware/index.mjs +151 -0
- package/source/core/middlewares/StaticMiddleware/index.mjs +628 -0
- package/source/core/routing/ExchangeLayer/ExchangeMatcher.mjs +127 -0
- package/source/core/routing/ExchangeLayer/index.mjs +254 -0
- package/source/core/routing/Pipeline/index.mjs +157 -0
- package/source/core/routing/Router/Route.mjs +184 -0
- package/source/core/routing/Router/index.mjs +523 -0
- package/source/core/routing/RouterRegister/OptionsMiddleware.mjs +147 -0
- package/source/core/routing/RouterRegister/index.mjs +150 -0
- package/source/core/routing/RouterSystem/index.mjs +225 -0
- package/source/core/value-objects/Address/index.mjs +281 -0
- package/source/core/value-objects/Endpoint/index.mjs +293 -0
- package/source/index.mjs +62 -0
- package/source/infrastructure/adapters/Http2Adapter/index.mjs +144 -0
- package/source/infrastructure/adapters/Http2CleartextAdapter/index.mjs +147 -0
- package/source/infrastructure/adapters/HttpAdapter/index.mjs +124 -0
- package/source/infrastructure/adapters/HttpsAdapter/index.mjs +124 -0
- package/source/infrastructure/adapters/TransportAdapter/createWebSocketOpenRequest.mjs +843 -0
- package/source/infrastructure/adapters/TransportAdapter/index.mjs +555 -0
- package/source/shared/Identifier/index.mjs +671 -0
- package/source/shared/constants/symbols/brands/index.mjs +45 -0
- package/source/shared/domain/UUIDV7/index.mjs +346 -0
- package/source/shared/errors/BaseError/index.mjs +157 -0
- package/source/shared/errors/IPCError/index.mjs +97 -0
- package/source/shared/errors/MiddlewareError/index.mjs +106 -0
- package/source/shared/errors/PathnamePatternError/index.mjs +103 -0
- package/source/shared/errors/RequestError/index.mjs +116 -0
- package/source/shared/errors/ResponseError/index.mjs +140 -0
- package/source/shared/errors/RouterError/index.mjs +90 -0
- package/source/shared/errors/ServerConfigurationError/index.mjs +551 -0
- package/source/shared/errors/ServerError/index.mjs +127 -0
- package/source/shared/errors/WebSocketError/index.mjs +58 -0
- package/source/shared/outcome/ErrorSchema.mjs +361 -0
- package/source/shared/outcome/Result/index.mjs +239 -0
- package/source/shared/outcome/Validation/index.mjs +208 -0
- package/source/shared/validations/Middleware/index.mjs +160 -0
- package/source/shared/validations/PathnamePattern/index.mjs +256 -0
- package/source/shared/validations/Server/NotFoundHandler/index.mjs +94 -0
- package/source/shared/validations/Server/Router/index.mjs +68 -0
- package/source/shared/validations/Server/ServerConfiguration/index.mjs +68 -0
- package/source/shared/validations/Server/SystemErrorHandler/index.mjs +94 -0
- package/source/shared/validations/ServerConfiguration/CORSOptions/index.mjs +310 -0
- package/source/shared/validations/ServerConfiguration/CSRFOptions/index.mjs +299 -0
- package/source/shared/validations/ServerConfiguration/CompressOptions/index.mjs +204 -0
- package/source/shared/validations/ServerConfiguration/CookieParserOptions/index.mjs +102 -0
- package/source/shared/validations/ServerConfiguration/CookieSessionOptions/index.mjs +332 -0
- package/source/shared/validations/ServerConfiguration/ListenOptions/index.mjs +178 -0
- package/source/shared/validations/ServerConfiguration/RateLimitOptions/index.mjs +229 -0
- package/source/shared/validations/ServerConfiguration/RequestOptions/index.mjs +132 -0
- package/source/shared/validations/ServerConfiguration/ResponseOptions/index.mjs +122 -0
- package/source/shared/validations/ServerConfiguration/SecurityHeadersOptions/index.mjs +137 -0
- package/source/shared/validations/ServerConfiguration/StaticOptions/index.mjs +248 -0
- package/types/index.d.ts +719 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @file Provides a UUID version 7 implementation.
|
|
4
|
+
*
|
|
5
|
+
* @description Defines the UUIDV7 class for creating, validating, and working
|
|
6
|
+
* with RFC 9562-compliant UUID version 7 identifiers.
|
|
7
|
+
*
|
|
8
|
+
* UUID v7 embeds a 48-bit Unix timestamp in milliseconds in the first
|
|
9
|
+
* six bytes of the identifier, followed by randomly generated bits.
|
|
10
|
+
* This provides identifiers that are practically unique and naturally
|
|
11
|
+
* sortable by creation time.
|
|
12
|
+
*
|
|
13
|
+
* @module UUIDV7
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
17
|
+
// » IMPORT NATIVE NODEJS MODULES
|
|
18
|
+
import { randomBytes } from 'node:crypto';
|
|
19
|
+
|
|
20
|
+
// » IMPORT THIRD PARTY MODULES
|
|
21
|
+
|
|
22
|
+
// » IMPORT LOCAL MODULES
|
|
23
|
+
import Validation from '#shared/outcome/Validation';
|
|
24
|
+
|
|
25
|
+
// ━━ CONSTANTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
26
|
+
/**
|
|
27
|
+
* Matches the canonical hexadecimal representation of a UUID version 7.
|
|
28
|
+
*
|
|
29
|
+
* The expression validates the UUID structure, version field, and RFC 9562
|
|
30
|
+
* variant bits.
|
|
31
|
+
*
|
|
32
|
+
* @type {RegExp}
|
|
33
|
+
*/
|
|
34
|
+
const UUIDV7_REGEXP = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
35
|
+
|
|
36
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
37
|
+
/**
|
|
38
|
+
* Represents a UUID version 7.
|
|
39
|
+
*
|
|
40
|
+
* UUID v7 combines a Unix timestamp in milliseconds with randomly generated
|
|
41
|
+
* bits, producing identifiers that are practically unique and chronologically
|
|
42
|
+
* sortable.
|
|
43
|
+
*/
|
|
44
|
+
class UUIDV7 {
|
|
45
|
+
#uuid;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates a UUID v7 instance.
|
|
49
|
+
*
|
|
50
|
+
* When no timestamp is provided, the current time is used. A `Date` instance
|
|
51
|
+
* uses its Unix timestamp, while an existing UUID v7 uses the timestamp
|
|
52
|
+
* encoded in its first 48 bits.
|
|
53
|
+
*
|
|
54
|
+
* @param {Date|string|undefined} inputId - Timestamp source or existing UUID v7.
|
|
55
|
+
* @throws {TypeError} If the input type is invalid.
|
|
56
|
+
* @throws {RangeError} If the input value is invalid.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```js
|
|
60
|
+
* const id = new UUIDV7();
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```js
|
|
65
|
+
* const id = new UUIDV7(new Date('2026-09-07T10:00:00Z'));
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```js
|
|
70
|
+
* const source = new UUIDV7();
|
|
71
|
+
* const id = new UUIDV7(source.value);
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
constructor(inputId = undefined) {
|
|
75
|
+
UUIDV7.assert(inputId);
|
|
76
|
+
|
|
77
|
+
const milliseconds = UUIDV7.#normalizeTimestamp(inputId);
|
|
78
|
+
|
|
79
|
+
this.#uuid = UUIDV7.#generateUUID(milliseconds);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The UUID value.
|
|
84
|
+
*
|
|
85
|
+
* @readonly
|
|
86
|
+
* @type {string}
|
|
87
|
+
*/
|
|
88
|
+
get value() {
|
|
89
|
+
return this.#uuid;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The UUID value without separators.
|
|
94
|
+
*
|
|
95
|
+
* @readonly
|
|
96
|
+
* @type {string}
|
|
97
|
+
*/
|
|
98
|
+
get hexadecimal() {
|
|
99
|
+
return this.#uuid.replace(/-/g, '');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The Unix timestamp encoded in the UUID.
|
|
104
|
+
*
|
|
105
|
+
* @readonly
|
|
106
|
+
* @type {number}
|
|
107
|
+
*/
|
|
108
|
+
get timestamp() {
|
|
109
|
+
return Number.parseInt(this.hexadecimal.slice(0, 12), 16);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns the Unix timestamp encoded in the UUID as a Date instance.
|
|
114
|
+
*
|
|
115
|
+
* @returns {Date} Date represented by the UUID timestamp.
|
|
116
|
+
* @example
|
|
117
|
+
* ```js
|
|
118
|
+
* const id = new UUIDV7();
|
|
119
|
+
* const date = id.toDate();
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
toDate() {
|
|
123
|
+
return new Date(this.timestamp);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Returns the UUID as a string.
|
|
128
|
+
*
|
|
129
|
+
* @returns {string} UUID in canonical hexadecimal format.
|
|
130
|
+
* @example
|
|
131
|
+
* ```js
|
|
132
|
+
* const id = new UUIDV7();
|
|
133
|
+
* console.log(id.toString());
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
toString() {
|
|
137
|
+
return this.#uuid;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Returns the UUID as a JSON value.
|
|
142
|
+
*
|
|
143
|
+
* @returns {string} UUID in canonical hexadecimal format.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```js
|
|
147
|
+
* const id = new UUIDV7();
|
|
148
|
+
* console.log(JSON.stringify(id));
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
toJSON() {
|
|
152
|
+
return this.#uuid;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Normalizes a timestamp source into Unix milliseconds.
|
|
157
|
+
*
|
|
158
|
+
* Accepted values are:
|
|
159
|
+
* - `undefined`, which resolves to the current time.
|
|
160
|
+
* - A `Date` instance, which resolves to its Unix timestamp.
|
|
161
|
+
* - A valid UUID v7 string, from which the embedded timestamp is extracted.
|
|
162
|
+
*
|
|
163
|
+
* @param {Date|string|undefined} inputId - Timestamp source.
|
|
164
|
+
* @returns {number} Unix timestamp in milliseconds.
|
|
165
|
+
*/
|
|
166
|
+
static #normalizeTimestamp(inputId) {
|
|
167
|
+
if (inputId === undefined) {
|
|
168
|
+
return Date.now();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (inputId instanceof Date) {
|
|
172
|
+
return inputId.getTime();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const hexadecimal = inputId.replace(/-/g, '');
|
|
176
|
+
|
|
177
|
+
return Number.parseInt(hexadecimal.substring(0, 12), 16);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Generates a UUID version 7 from a Unix timestamp.
|
|
182
|
+
*
|
|
183
|
+
* The generated identifier contains:
|
|
184
|
+
* - A 48-bit Unix timestamp in milliseconds.
|
|
185
|
+
* - The UUID version 7 field.
|
|
186
|
+
* - The RFC 9562 variant field.
|
|
187
|
+
* - Random bits filling the remaining identifier space.
|
|
188
|
+
*
|
|
189
|
+
* @param {number} milliseconds - Unix timestamp in milliseconds.
|
|
190
|
+
* @returns {string} UUID v7 in canonical hexadecimal format.
|
|
191
|
+
*/
|
|
192
|
+
static #generateUUID(milliseconds) {
|
|
193
|
+
const bytes = randomBytes(16);
|
|
194
|
+
|
|
195
|
+
// ━━ 48-bit Unix timestamp (bytes 0-5) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
196
|
+
bytes[0] = Math.floor(milliseconds / 0x10000000000) & 0xff;
|
|
197
|
+
bytes[1] = Math.floor(milliseconds / 0x100000000) & 0xff;
|
|
198
|
+
bytes[2] = Math.floor(milliseconds / 0x1000000) & 0xff;
|
|
199
|
+
bytes[3] = Math.floor(milliseconds / 0x10000) & 0xff;
|
|
200
|
+
bytes[4] = Math.floor(milliseconds / 0x100) & 0xff;
|
|
201
|
+
bytes[5] = milliseconds & 0xff;
|
|
202
|
+
|
|
203
|
+
// ━━ Version 7 + random bits ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
204
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x70;
|
|
205
|
+
|
|
206
|
+
// ━━ RFC 9562 variant + random bits ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
208
|
+
|
|
209
|
+
// ━━ Canonical format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
210
|
+
const hexadecimal = bytes.toString('hex');
|
|
211
|
+
|
|
212
|
+
return `${hexadecimal.slice(0, 8)}-${hexadecimal.slice(8, 12)}-${hexadecimal.slice(12, 16)}-${hexadecimal.slice(16, 20)}-${hexadecimal.slice(20)}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Creates a new UUID v7 string using the current time.
|
|
217
|
+
*
|
|
218
|
+
* Convenience shortcut equivalent to `new UUIDV7().toString()`.
|
|
219
|
+
*
|
|
220
|
+
* @returns {string} UUID v7 in canonical hexadecimal format.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```js
|
|
224
|
+
* const id = UUIDV7.create();
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
static create() {
|
|
228
|
+
return new UUIDV7().toString();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Validates a value that can be used as a UUID v7 timestamp source.
|
|
233
|
+
*
|
|
234
|
+
* `undefined` represents the current time, a `Date` represents its Unix
|
|
235
|
+
* timestamp, and a UUID v7 string represents the timestamp encoded in that
|
|
236
|
+
* UUID.
|
|
237
|
+
*
|
|
238
|
+
* @param {*} value - Value to validate.
|
|
239
|
+
* @returns {Validation} Validation result.
|
|
240
|
+
* @example
|
|
241
|
+
* ```js
|
|
242
|
+
* const result = UUIDV7.validate();
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
static validate(value) {
|
|
246
|
+
if (value === undefined) {
|
|
247
|
+
return Validation.success();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (value instanceof Date) {
|
|
251
|
+
if (Number.isNaN(value.getTime())) {
|
|
252
|
+
return Validation.failure({
|
|
253
|
+
error: RangeError,
|
|
254
|
+
message: 'Invalid timestamp.',
|
|
255
|
+
code: 'INVALID_TIMESTAMP',
|
|
256
|
+
custom: false,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return Validation.success();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (typeof value === 'string') {
|
|
263
|
+
if (!UUIDV7_REGEXP.test(value)) {
|
|
264
|
+
return Validation.failure({
|
|
265
|
+
error: RangeError,
|
|
266
|
+
message: 'Invalid UUID v7.',
|
|
267
|
+
code: 'INVALID_UUID',
|
|
268
|
+
custom: false,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return Validation.success();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return Validation.failure({
|
|
275
|
+
error: TypeError,
|
|
276
|
+
message: 'Timestamp must be a Date, string, or undefined.',
|
|
277
|
+
code: 'INVALID_TIMESTAMP_SOURCE',
|
|
278
|
+
custom: false,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Validates that a value is a valid UUID v7 string.
|
|
284
|
+
*
|
|
285
|
+
* @param {unknown} value - Value to validate.
|
|
286
|
+
* @returns {Validation} Validation result.
|
|
287
|
+
* @example
|
|
288
|
+
* ```js
|
|
289
|
+
* const result = UUIDV7.validateUUIDString('019937f2-1234-7abc-8def-123456789abc');
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
static validateUUIDString(value) {
|
|
293
|
+
if (value === undefined) {
|
|
294
|
+
return Validation.failure({
|
|
295
|
+
error: ReferenceError,
|
|
296
|
+
message: 'UUID must be a string.',
|
|
297
|
+
custom: false,
|
|
298
|
+
code: 'MISSING_UUID',
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (typeof value !== 'string') {
|
|
303
|
+
return Validation.failure({
|
|
304
|
+
error: TypeError,
|
|
305
|
+
message: 'UUID must be a string.',
|
|
306
|
+
custom: false,
|
|
307
|
+
code: 'INVALID_UUID_TYPE',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!UUIDV7_REGEXP.test(value)) {
|
|
312
|
+
return Validation.failure({
|
|
313
|
+
error: RangeError,
|
|
314
|
+
message: 'Invalid UUID v7 format.',
|
|
315
|
+
custom: false,
|
|
316
|
+
code: 'INVALID_UUID',
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return Validation.success();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Asserts that a value can be used as a UUID v7 timestamp source.
|
|
325
|
+
*
|
|
326
|
+
* Unlike {@link UUIDV7.validate}, this method throws when validation fails.
|
|
327
|
+
*
|
|
328
|
+
* @param {unknown} value - Value to validate.
|
|
329
|
+
* @throws {TypeError} If the value has an unsupported type.
|
|
330
|
+
* @throws {RangeError} If the value is invalid.
|
|
331
|
+
* @example
|
|
332
|
+
* ```js
|
|
333
|
+
* UUIDV7.assert(new Date());
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
static assert(value) {
|
|
337
|
+
const validation = UUIDV7.validate(value);
|
|
338
|
+
|
|
339
|
+
if (!validation.ok) {
|
|
340
|
+
throw validation.error;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
346
|
+
export default UUIDV7;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Defines the base class for structured application errors.
|
|
3
|
+
*
|
|
4
|
+
* @description BaseError serves as the foundation for application-specific errors.
|
|
5
|
+
* It provides a consistent interface for error handling with support for:
|
|
6
|
+
*
|
|
7
|
+
* - Predefined error identifiers and custom error messages.
|
|
8
|
+
* - Message templating with placeholders.
|
|
9
|
+
* - Error chaining via the `cause` property.
|
|
10
|
+
* - Contextual information via `details`.
|
|
11
|
+
* - A consistent error structure across the application.
|
|
12
|
+
*
|
|
13
|
+
* Subclasses should define their own `MESSAGES` map with domain-specific
|
|
14
|
+
* error identifiers and message templates.
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
* @module BaseError
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
21
|
+
/**
|
|
22
|
+
* A symbolic identifier used to resolve an application error definition.
|
|
23
|
+
*
|
|
24
|
+
* @typedef {string} ErrorIdentifier
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Options for creating an error instance.
|
|
29
|
+
*
|
|
30
|
+
* @typedef {object} ErrorOptions
|
|
31
|
+
* @property {Record<string, unknown>} [values] - Values for template placeholders in the error message.
|
|
32
|
+
* @property {unknown} [details] - Additional contextual information about the error.
|
|
33
|
+
* @property {Error} [cause] - The original error that caused this error (for error chaining).
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Normalized error definition used internally to construct an error instance.
|
|
38
|
+
*
|
|
39
|
+
* @typedef {object} ErrorDefinition
|
|
40
|
+
* @property {string} message - The final error message.
|
|
41
|
+
* @property {ErrorIdentifier} [code] - The resolved error identifier.
|
|
42
|
+
* @property {unknown} [details] - Additional error details.
|
|
43
|
+
* @property {{ cause: Error }} [errorOptions] - Options for the Error constructor (e.g., cause).
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
47
|
+
/**
|
|
48
|
+
* Base class for application-specific errors.
|
|
49
|
+
*
|
|
50
|
+
* This class supports predefined error identifiers as well as custom error
|
|
51
|
+
* messages. When a known error identifier is provided, it is automatically
|
|
52
|
+
* resolved to its corresponding message template.
|
|
53
|
+
*
|
|
54
|
+
* @augments Error
|
|
55
|
+
* @private
|
|
56
|
+
*/
|
|
57
|
+
class BaseError extends Error {
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new {@link BaseError}.
|
|
60
|
+
*
|
|
61
|
+
* @param {ErrorIdentifier} identifier - A predefined error identifier or a custom error message.
|
|
62
|
+
* @param {ErrorOptions} [options] - Additional information used to format the message, attach domain details, or preserve the original cause.
|
|
63
|
+
* @example
|
|
64
|
+
* ```js
|
|
65
|
+
* class ValidationError extends BaseError {}
|
|
66
|
+
* throw new ValidationError('INVALID_VALUE');
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
constructor(identifier, options = {}) {
|
|
70
|
+
const definition = new.target.resolveDefinition(identifier, options);
|
|
71
|
+
|
|
72
|
+
super(definition.message, definition.errorOptions);
|
|
73
|
+
|
|
74
|
+
this.name = new.target.name;
|
|
75
|
+
|
|
76
|
+
if (definition.code !== undefined) {
|
|
77
|
+
/**
|
|
78
|
+
* Predefined error identifier, when available.
|
|
79
|
+
*
|
|
80
|
+
* @type {ErrorIdentifier}
|
|
81
|
+
*/
|
|
82
|
+
this.code = definition.code;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (definition.details !== undefined) {
|
|
86
|
+
/**
|
|
87
|
+
* Additional contextual information about the error.
|
|
88
|
+
*
|
|
89
|
+
* @type {unknown}
|
|
90
|
+
*/
|
|
91
|
+
this.details = definition.details;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Error.captureStackTrace?.(this, new.target);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Replaces placeholder tokens in a predefined message.
|
|
99
|
+
*
|
|
100
|
+
* Placeholders are in the format `{key}` and are replaced with the
|
|
101
|
+
* corresponding value from the `values` object.
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
* @static
|
|
105
|
+
* @param {string} message - The message template containing placeholders.
|
|
106
|
+
* @param {Record<string, unknown>} [values] - Key-value pairs for placeholder replacement.
|
|
107
|
+
* @returns {string} The formatted message with placeholders replaced.
|
|
108
|
+
*/
|
|
109
|
+
static #formatMessage(message, values = {}) {
|
|
110
|
+
return message.replace(/\{(\w+)\}/g, (_, key) => String(values[key] ?? `{${key}}`));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Resolves an error identifier into a normalized error definition.
|
|
115
|
+
*
|
|
116
|
+
* This method handles both predefined error identifiers and custom error messages.
|
|
117
|
+
* When a predefined identifier is found, it resolves to the corresponding message
|
|
118
|
+
* and applies any placeholders.
|
|
119
|
+
*
|
|
120
|
+
* @private
|
|
121
|
+
* @static
|
|
122
|
+
* @param {ErrorIdentifier} identifier - The error identifier or custom message.
|
|
123
|
+
* @param {ErrorOptions} [options] - Additional error options.
|
|
124
|
+
* @returns {ErrorDefinition} Normalized error definition.
|
|
125
|
+
*/
|
|
126
|
+
static resolveDefinition(identifier, options) {
|
|
127
|
+
const entry = this.MESSAGES.get(identifier);
|
|
128
|
+
|
|
129
|
+
if (entry === undefined) {
|
|
130
|
+
return {
|
|
131
|
+
message: identifier,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
message: BaseError.#formatMessage(entry, options.values),
|
|
137
|
+
code: identifier,
|
|
138
|
+
details: options.details,
|
|
139
|
+
errorOptions: options.cause !== undefined ? { cause: options.cause } : undefined,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Message template catalog indexed by error identifier.
|
|
145
|
+
*
|
|
146
|
+
* Subclasses should override this property with their own
|
|
147
|
+
* identifier-to-message mappings.
|
|
148
|
+
*
|
|
149
|
+
* @type {Map<ErrorIdentifier, string>}
|
|
150
|
+
* @private
|
|
151
|
+
* @static
|
|
152
|
+
*/
|
|
153
|
+
static MESSAGES = new Map();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
157
|
+
export default BaseError;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Defines the internal error type used for IPC subsystem failures.
|
|
3
|
+
*
|
|
4
|
+
* @description This class supports predefined error identifiers as well
|
|
5
|
+
* as custom error messages. When a known error identifier is provided,
|
|
6
|
+
* it is automatically resolved to its corresponding message.
|
|
7
|
+
*
|
|
8
|
+
* @private
|
|
9
|
+
* @module IPCError
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
13
|
+
// » IMPORT LOCAL MODULES
|
|
14
|
+
import BaseError from '../BaseError/index.mjs';
|
|
15
|
+
|
|
16
|
+
// ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
17
|
+
/**
|
|
18
|
+
* @template {string} T
|
|
19
|
+
* @typedef {T | (string & {})} LiteralUnion
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {LiteralUnion<
|
|
24
|
+
* 'IPC_INVALID_CHANNEL' |
|
|
25
|
+
* 'IPC_INVALID_HANDLER' |
|
|
26
|
+
* 'IPC_INVALID_LISTENER' |
|
|
27
|
+
* 'IPC_CLOSED' |
|
|
28
|
+
* 'IPC_CHANNEL_NOT_FOUND'
|
|
29
|
+
* >} IPCErrorIdentifier
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options for creating an error instance.
|
|
34
|
+
*
|
|
35
|
+
* @typedef {object} IPCErrorOptions
|
|
36
|
+
* @property {Record<string, unknown>} [values] - Values for template placeholders in the error message.
|
|
37
|
+
* @property {unknown} [details] - Additional contextual information about the error.
|
|
38
|
+
* @property {Error} [cause] - The original error that caused this error (for error chaining).
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
42
|
+
/**
|
|
43
|
+
* Error thrown when an IPC subsystem operation cannot be completed.
|
|
44
|
+
*
|
|
45
|
+
* This error type covers failures related to IPC handler registration,
|
|
46
|
+
* listener management, and IPC lifecycle operations.
|
|
47
|
+
*
|
|
48
|
+
* @augments BaseError
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
class IPCError extends BaseError {
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new {@link IPCError}.
|
|
54
|
+
*
|
|
55
|
+
* @param {IPCErrorIdentifier} identifier - A predefined error identifier or a custom error message.
|
|
56
|
+
* @param {IPCErrorOptions} [options] - Additional information used to format the message, attach domain details, or preserve the original cause.
|
|
57
|
+
* @example
|
|
58
|
+
* ```js
|
|
59
|
+
* throw new IPCError('IPC_INVALID_CHANNEL');
|
|
60
|
+
* ```
|
|
61
|
+
* @example
|
|
62
|
+
* ```js
|
|
63
|
+
* throw new IPCError('IPC_CHANNEL_NOT_FOUND', {
|
|
64
|
+
* values: { channel: 'get-user' },
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
constructor(identifier, options = {}) {
|
|
69
|
+
super(identifier, options);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Collection of predefined IPC error messages.
|
|
74
|
+
*
|
|
75
|
+
* Available error identifiers:
|
|
76
|
+
*
|
|
77
|
+
* - `IPC_INVALID_CHANNEL`.
|
|
78
|
+
* - `IPC_INVALID_HANDLER`.
|
|
79
|
+
* - `IPC_INVALID_LISTENER`.
|
|
80
|
+
* - `IPC_CLOSED`.
|
|
81
|
+
* - `IPC_CHANNEL_NOT_FOUND`.
|
|
82
|
+
*
|
|
83
|
+
* @private
|
|
84
|
+
* @static
|
|
85
|
+
* @type {Map<IPCErrorIdentifier, string>}
|
|
86
|
+
*/
|
|
87
|
+
static MESSAGES = new Map([
|
|
88
|
+
['IPC_INVALID_CHANNEL', 'Channel must be a non-empty string.'],
|
|
89
|
+
['IPC_INVALID_HANDLER', 'Handler must be a function.'],
|
|
90
|
+
['IPC_INVALID_LISTENER', 'Listener must be a function.'],
|
|
91
|
+
['IPC_CLOSED', 'IPCMain has been closed.'],
|
|
92
|
+
['IPC_CHANNEL_NOT_FOUND', 'No handler registered for channel "{channel}".'],
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
97
|
+
export default IPCError;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Defines domain-specific errors for middleware validation.
|
|
3
|
+
*
|
|
4
|
+
* @description MiddlewareError extends BaseError to provide structured,
|
|
5
|
+
* identifiable errors specific to middleware validation. It centralizes
|
|
6
|
+
* error messages and supports template placeholders for dynamic context.
|
|
7
|
+
*
|
|
8
|
+
* @module MiddlewareError
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
12
|
+
// » IMPORT LOCAL MODULES
|
|
13
|
+
import BaseError from '../BaseError/index.mjs';
|
|
14
|
+
|
|
15
|
+
// ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
16
|
+
/**
|
|
17
|
+
* @template {string} T
|
|
18
|
+
* @typedef {T | (string & {})} LiteralUnion
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Identifies a predefined middleware error or allows a custom error message.
|
|
23
|
+
*
|
|
24
|
+
* @typedef {LiteralUnion<
|
|
25
|
+
* 'INVALID_MIDDLEWARE_TYPE' |
|
|
26
|
+
* 'INVALID_MIDDLEWARE_ARITY' |
|
|
27
|
+
* 'INVALID_MIDDLEWARES_TYPE'
|
|
28
|
+
* >} MiddlewareErrorIdentifier
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Options for creating an error instance.
|
|
33
|
+
*
|
|
34
|
+
* @typedef {object} MiddlewareErrorOptions
|
|
35
|
+
* @property {Record<string, unknown>} [values] - Values for template placeholders in the error message.
|
|
36
|
+
* @property {unknown} [details] - Additional contextual information about the error.
|
|
37
|
+
* @property {Error} [cause] - The original error that caused this error (for error chaining).
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
41
|
+
/**
|
|
42
|
+
* Error thrown when middleware cannot be validated.
|
|
43
|
+
*
|
|
44
|
+
* @classdesc This error type provides identifiable failures related to
|
|
45
|
+
* middleware validation.
|
|
46
|
+
*
|
|
47
|
+
* @augments BaseError
|
|
48
|
+
* @private
|
|
49
|
+
*/
|
|
50
|
+
class MiddlewareError extends BaseError {
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new {@link MiddlewareError}.
|
|
53
|
+
*
|
|
54
|
+
* @param {MiddlewareErrorIdentifier} identifier - A predefined error identifier or a custom error message.
|
|
55
|
+
* @param {MiddlewareErrorOptions} [options] - Additional information used to format the message, attach domain details, or preserve the original cause.
|
|
56
|
+
* @example
|
|
57
|
+
* ```js
|
|
58
|
+
* throw new MiddlewareError('INVALID_MIDDLEWARE_TYPE', {
|
|
59
|
+
* values: {
|
|
60
|
+
* expected: 'function',
|
|
61
|
+
* received: 'string',
|
|
62
|
+
* },
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
* @example
|
|
66
|
+
* ```js
|
|
67
|
+
* throw new MiddlewareError('INVALID_MIDDLEWARE_ARITY', {
|
|
68
|
+
* values: {
|
|
69
|
+
* expected: 2,
|
|
70
|
+
* received: 1,
|
|
71
|
+
* },
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
constructor(identifier, options = {}) {
|
|
76
|
+
super(identifier, options);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Collection of predefined middleware error messages.
|
|
81
|
+
*
|
|
82
|
+
* Available error identifiers:
|
|
83
|
+
*
|
|
84
|
+
* - `'INVALID_MIDDLEWARE_TYPE'`.
|
|
85
|
+
* - `'INVALID_MIDDLEWARE_ARITY'`.
|
|
86
|
+
* - `'INVALID_MIDDLEWARES_TYPE'`.
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
* @static
|
|
90
|
+
* @type {Map<MiddlewareErrorIdentifier, string>}
|
|
91
|
+
*/
|
|
92
|
+
static MESSAGES = new Map([
|
|
93
|
+
['INVALID_MIDDLEWARE_TYPE', 'Expected middleware to be a {expected}, but received {received}.'],
|
|
94
|
+
[
|
|
95
|
+
'INVALID_MIDDLEWARE_ARITY',
|
|
96
|
+
'Middleware must declare exactly {expected} parameters, but received {received}.',
|
|
97
|
+
],
|
|
98
|
+
[
|
|
99
|
+
'INVALID_MIDDLEWARES_TYPE',
|
|
100
|
+
'Expected middlewares to be an {expected}, but received {received}.',
|
|
101
|
+
],
|
|
102
|
+
]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
106
|
+
export default MiddlewareError;
|