@boo-labs/server 1.0.1 → 1.0.2

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.
Files changed (24) hide show
  1. package/package.json +1 -1
  2. package/source/core/IPCMain/IPCProtocol.mjs +80 -75
  3. package/source/shared/domain/UUIDV7/index.mjs +31 -39
  4. package/source/shared/errors/ServerError/index.mjs +48 -2
  5. package/source/shared/outcome/Result/index.mjs +77 -130
  6. package/source/shared/outcome/Validation/index.mjs +56 -114
  7. package/source/shared/validations/Middleware/index.mjs +32 -23
  8. package/source/shared/validations/PathnamePattern/index.mjs +38 -39
  9. package/source/shared/validations/Server/NotFoundHandler/index.mjs +25 -15
  10. package/source/shared/validations/Server/Router/index.mjs +24 -14
  11. package/source/shared/validations/Server/ServerConfiguration/index.mjs +24 -14
  12. package/source/shared/validations/Server/SystemErrorHandler/index.mjs +25 -15
  13. package/source/shared/validations/ServerConfiguration/CORSOptions/index.mjs +95 -91
  14. package/source/shared/validations/ServerConfiguration/CSRFOptions/index.mjs +96 -96
  15. package/source/shared/validations/ServerConfiguration/CompressOptions/index.mjs +55 -43
  16. package/source/shared/validations/ServerConfiguration/CookieParserOptions/index.mjs +28 -13
  17. package/source/shared/validations/ServerConfiguration/CookieSessionOptions/index.mjs +101 -111
  18. package/source/shared/validations/ServerConfiguration/ListenOptions/index.mjs +55 -43
  19. package/source/shared/validations/ServerConfiguration/RateLimitOptions/index.mjs +71 -61
  20. package/source/shared/validations/ServerConfiguration/RequestOptions/index.mjs +44 -31
  21. package/source/shared/validations/ServerConfiguration/ResponseOptions/index.mjs +39 -25
  22. package/source/shared/validations/ServerConfiguration/SecurityHeadersOptions/index.mjs +27 -14
  23. package/source/shared/validations/ServerConfiguration/StaticOptions/index.mjs +85 -84
  24. package/source/shared/outcome/ErrorSchema.mjs +0 -361
@@ -14,11 +14,24 @@
14
14
  import Validation from '#shared/outcome/Validation';
15
15
  import PathnamePatternError from '#shared/errors/PathnamePatternError';
16
16
 
17
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ /**
19
+ * A successful {@link Validation} instance.
20
+ *
21
+ * @typedef {import('#shared/outcome/Validation').SuccessValidation} SuccessValidation
22
+ */
23
+
24
+ /**
25
+ * A failed {@link Validation} instance.
26
+ *
27
+ * @template {Error} E
28
+ * @typedef {import('#shared/outcome/Validation').FailureValidation<E>} FailureValidation
29
+ */
30
+
17
31
  // ━━ CONSTANTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
32
  /**
19
33
  * Maximum number of characters allowed in a pathname pattern.
20
34
  *
21
- * @private
22
35
  * @type {number}
23
36
  */
24
37
  const MAX_PATTERN_LENGTH = 512;
@@ -29,7 +42,6 @@ const MAX_PATTERN_LENGTH = 512;
29
42
  * Parameter names must begin with a letter or underscore and may contain
30
43
  * letters, digits, and underscores.
31
44
  *
32
- * @private
33
45
  * @type {string}
34
46
  */
35
47
  const PARAM_NAME = String.raw`[A-Za-z_][A-Za-z0-9_]*`;
@@ -38,7 +50,6 @@ const PARAM_NAME = String.raw`[A-Za-z_][A-Za-z0-9_]*`;
38
50
  * Regular expression source for a literal character allowed inside a pathname
39
51
  * segment.
40
52
  *
41
- * @private
42
53
  * @type {string}
43
54
  */
44
55
  const LITERAL_CHAR = String.raw`[A-Za-z0-9._~!$&'()+,;=@-]`;
@@ -49,7 +60,6 @@ const LITERAL_CHAR = String.raw`[A-Za-z0-9._~!$&'()+,;=@-]`;
49
60
  *
50
61
  * Supported forms are `:name` and `{name}`.
51
62
  *
52
- * @private
53
63
  * @type {string}
54
64
  */
55
65
  const PARAM_SEGMENT = String.raw`(?::${PARAM_NAME}|\{${PARAM_NAME}\})`;
@@ -111,7 +121,8 @@ const PARAMETER_PATTERN_REGEXP = /:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0
111
121
  *
112
122
  * @private
113
123
  * @param {string} pathnamePattern - Pathname pattern to validate.
114
- * @returns {Validation} Validation result.
124
+ * @returns {SuccessValidation|FailureValidation<PathnamePatternError>} Validation result.
125
+ *
115
126
  * @example
116
127
  * ```js
117
128
  * const validation = validateUniqueParamNames('/users/:id/posts/{postId}');
@@ -119,6 +130,7 @@ const PARAMETER_PATTERN_REGEXP = /:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0
119
130
  * console.log(validation.ok);
120
131
  * // => true
121
132
  * ```
133
+ *
122
134
  * @example
123
135
  * ```js
124
136
  * const validation = validateUniqueParamNames('/users/:id/posts/{id}');
@@ -134,15 +146,12 @@ function validateUniqueParamNames(pathnamePattern) {
134
146
  const name = match[1] ?? match[2];
135
147
 
136
148
  if (names.has(name)) {
137
- return Validation.failure({
138
- error: PathnamePatternError,
139
- code: 'DUPLICATE_PARAMETER_NAME',
140
- custom: true,
141
- options: {
149
+ return Validation.failure(
150
+ new PathnamePatternError('DUPLICATE_PARAMETER_NAME', {
142
151
  values: { name },
143
152
  details: { pathnamePattern },
144
- },
145
- });
153
+ }),
154
+ );
146
155
  }
147
156
 
148
157
  names.add(name);
@@ -165,7 +174,8 @@ function validateUniqueParamNames(pathnamePattern) {
165
174
  * 5. Parameter names must be unique.
166
175
  *
167
176
  * @param {unknown} pathnamePattern - Pathname pattern to validate.
168
- * @returns {Validation} Validation result.
177
+ * @returns {SuccessValidation|FailureValidation<PathnamePatternError>} Validation result.
178
+ *
169
179
  * @example
170
180
  * ```js
171
181
  * const validation = validatePathnamePattern('/users/:id');
@@ -184,45 +194,32 @@ function validateUniqueParamNames(pathnamePattern) {
184
194
  */
185
195
  export function validatePathnamePattern(pathnamePattern) {
186
196
  if (typeof pathnamePattern !== 'string') {
187
- return Validation.failure({
188
- error: PathnamePatternError,
189
- code: 'INVALID_PATTERN_TYPE',
190
- custom: true,
191
- options: {
197
+ return Validation.failure(
198
+ new PathnamePatternError('INVALID_PATTERN_TYPE', {
192
199
  values: { expected: 'string', received: typeof pathnamePattern },
193
- },
194
- });
200
+ }),
201
+ );
195
202
  }
196
203
 
197
204
  if (pathnamePattern.length === 0) {
198
- return Validation.failure({
199
- error: PathnamePatternError,
200
- code: 'EMPTY_PATTERN',
201
- custom: true,
202
- });
205
+ return Validation.failure(new PathnamePatternError('EMPTY_PATTERN'));
203
206
  }
204
207
 
205
208
  if (pathnamePattern.length > MAX_PATTERN_LENGTH) {
206
- return Validation.failure({
207
- error: PathnamePatternError,
208
- code: 'PATTERN_TOO_LONG',
209
- custom: true,
210
- options: {
209
+ return Validation.failure(
210
+ new PathnamePatternError('PATTERN_TOO_LONG', {
211
211
  values: { maxLength: MAX_PATTERN_LENGTH, actualLength: pathnamePattern.length },
212
- },
213
- });
212
+ }),
213
+ );
214
214
  }
215
215
 
216
216
  if (!PATHNAME_PATTERN_REGEXP.test(pathnamePattern)) {
217
- return Validation.failure({
218
- error: PathnamePatternError,
219
- code: 'INVALID_PATHNAME_PATTERN',
220
- custom: true,
221
- options: {
217
+ return Validation.failure(
218
+ new PathnamePatternError('INVALID_PATHNAME_PATTERN', {
222
219
  values: { pathnamePattern },
223
220
  details: { constraint: 'Must be * or start with / and contain valid segments' },
224
- },
225
- });
221
+ }),
222
+ );
226
223
  }
227
224
 
228
225
  return validateUniqueParamNames(pathnamePattern);
@@ -237,6 +234,7 @@ export function validatePathnamePattern(pathnamePattern) {
237
234
  * @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
238
235
  * @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
239
236
  * @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
237
+ *
240
238
  * @example
241
239
  * ```js
242
240
  * assertPathnamePattern('/users/:id');
@@ -250,6 +248,7 @@ export function validatePathnamePattern(pathnamePattern) {
250
248
  */
251
249
  export function assertPathnamePattern(pathnamePattern) {
252
250
  const validation = validatePathnamePattern(pathnamePattern);
251
+
253
252
  if (!validation.ok) {
254
253
  throw validation.error;
255
254
  }
@@ -13,6 +13,20 @@
13
13
  import Validation from '#shared/outcome/Validation';
14
14
  import ServerError from '#shared/errors/ServerError';
15
15
 
16
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ /**
18
+ * A successful {@link Validation} instance.
19
+ *
20
+ * @typedef {import('#shared/outcome/Validation').SuccessValidation} SuccessValidation
21
+ */
22
+
23
+ /**
24
+ * A failed {@link Validation} instance.
25
+ *
26
+ * @template {Error} E
27
+ * @typedef {import('#shared/outcome/Validation').FailureValidation<E>} FailureValidation
28
+ */
29
+
16
30
  // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
31
  /**
18
32
  * Validates a not-found handler.
@@ -21,7 +35,8 @@ import ServerError from '#shared/errors/ServerError';
21
35
  * `exchange`.
22
36
  *
23
37
  * @param {unknown} handler - Handler function to validate.
24
- * @returns {Validation} Validation result.
38
+ * @returns {SuccessValidation|FailureValidation<ServerError>} Validation result.
39
+ *
25
40
  * @example
26
41
  * ```js
27
42
  * const validation = validateNotFoundHandler((exchange) => {
@@ -42,31 +57,25 @@ import ServerError from '#shared/errors/ServerError';
42
57
  */
43
58
  export function validateNotFoundHandler(handler) {
44
59
  if (typeof handler !== 'function') {
45
- return Validation.failure({
46
- error: ServerError,
47
- code: 'INVALID_NOT_FOUND_HANDLER_TYPE',
48
- custom: true,
49
- options: {
60
+ return Validation.failure(
61
+ new ServerError('INVALID_NOT_FOUND_HANDLER_TYPE', {
50
62
  values: {
51
63
  expected: 'function',
52
64
  received: typeof handler,
53
65
  },
54
- },
55
- });
66
+ }),
67
+ );
56
68
  }
57
69
 
58
70
  if (handler.length !== 1) {
59
- return Validation.failure({
60
- error: ServerError,
61
- code: 'INVALID_NOT_FOUND_HANDLER_ARITY',
62
- custom: true,
63
- options: {
71
+ return Validation.failure(
72
+ new ServerError('INVALID_NOT_FOUND_HANDLER_ARITY', {
64
73
  values: {
65
74
  expected: 1,
66
75
  received: handler.length,
67
76
  },
68
- },
69
- });
77
+ }),
78
+ );
70
79
  }
71
80
 
72
81
  return Validation.success();
@@ -78,6 +87,7 @@ export function validateNotFoundHandler(handler) {
78
87
  * @param {unknown} handler - Handler function to validate.
79
88
  * @throws {ServerError} If the handler is not a function.
80
89
  * @throws {ServerError} If the handler does not declare exactly one parameter.
90
+ *
81
91
  * @example
82
92
  * ```js
83
93
  * assertNotFoundHandler((exchange) => {
@@ -13,12 +13,27 @@ import { ROUTER_BRAND } from '#shared/constants/symbols/brands';
13
13
  import Validation from '#shared/outcome/Validation';
14
14
  import ServerError from '#shared/errors/ServerError';
15
15
 
16
- // ━━ FUNCTIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ /**
18
+ * A successful {@link Validation} instance.
19
+ *
20
+ * @typedef {import('#shared/outcome/Validation').SuccessValidation} SuccessValidation
21
+ */
22
+
23
+ /**
24
+ * A failed {@link Validation} instance.
25
+ *
26
+ * @template {Error} E
27
+ * @typedef {import('#shared/outcome/Validation').FailureValidation<E>} FailureValidation
28
+ */
29
+
30
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
31
  /**
18
32
  * Validates that a value implements the Router contract.
19
33
  *
20
34
  * @param {unknown} value - Value to validate.
21
- * @returns {Validation} Validation result.
35
+ * @returns {SuccessValidation|FailureValidation<ServerError>} Validation result.
36
+ *
22
37
  * @example
23
38
  * ```js
24
39
  * const validation = validateRouter(router);
@@ -29,21 +44,15 @@ import ServerError from '#shared/errors/ServerError';
29
44
  */
30
45
  export function validateRouter(value) {
31
46
  if (value === null || typeof value !== 'object') {
32
- return Validation.failure({
33
- error: ServerError,
34
- message: `Expected a Router instance, received: ${value === null ? 'null' : typeof value}.`,
35
- code: 'INVALID_ROUTER_TYPE',
36
- custom: true,
37
- });
47
+ return Validation.failure(
48
+ new ServerError('INVALID_ROUTER_TYPE', {
49
+ values: { received: value === null ? 'null' : typeof value },
50
+ }),
51
+ );
38
52
  }
39
53
 
40
54
  if (Reflect.get(value, ROUTER_BRAND) !== true) {
41
- return Validation.failure({
42
- error: ServerError,
43
- message: 'Expected a Router instance.',
44
- code: 'INVALID_ROUTER_INSTANCE',
45
- custom: true,
46
- });
55
+ return Validation.failure(new ServerError('INVALID_ROUTER_INSTANCE'));
47
56
  }
48
57
 
49
58
  return Validation.success();
@@ -54,6 +63,7 @@ export function validateRouter(value) {
54
63
  *
55
64
  * @param {unknown} value - Value to assert.
56
65
  * @throws {ServerError} If the value does not implement the Router contract.
66
+ *
57
67
  * @example
58
68
  * ```js
59
69
  * assertRouter(router);
@@ -13,12 +13,27 @@ import { SERVER_CONFIGURATION_BRAND } from '#shared/constants/symbols/brands';
13
13
  import Validation from '#shared/outcome/Validation';
14
14
  import ServerError from '#shared/errors/ServerError';
15
15
 
16
- // ━━ FUNCTIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ /**
18
+ * A successful {@link Validation} instance.
19
+ *
20
+ * @typedef {import('#shared/outcome/Validation').SuccessValidation} SuccessValidation
21
+ */
22
+
23
+ /**
24
+ * A failed {@link Validation} instance.
25
+ *
26
+ * @template {Error} E
27
+ * @typedef {import('#shared/outcome/Validation').FailureValidation<E>} FailureValidation
28
+ */
29
+
30
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
31
  /**
18
32
  * Validates that a value implements the ServerConfiguration contract.
19
33
  *
20
34
  * @param {unknown} value - Value to validate.
21
- * @returns {Validation} Validation result.
35
+ * @returns {SuccessValidation|FailureValidation<ServerError>} Validation result.
36
+ *
22
37
  * @example
23
38
  * ```js
24
39
  * const validation = validateServerConfiguration(configuration);
@@ -29,21 +44,15 @@ import ServerError from '#shared/errors/ServerError';
29
44
  */
30
45
  export function validateServerConfiguration(value) {
31
46
  if (value === null || typeof value !== 'object') {
32
- return Validation.failure({
33
- error: ServerError,
34
- message: `Expected a ServerConfiguration instance, received: ${value === null ? 'null' : typeof value}.`,
35
- code: 'INVALID_SERVER_CONFIGURATION_TYPE',
36
- custom: true,
37
- });
47
+ return Validation.failure(
48
+ new ServerError('INVALID_SERVER_CONFIGURATION_TYPE', {
49
+ values: { received: value === null ? 'null' : typeof value },
50
+ }),
51
+ );
38
52
  }
39
53
 
40
54
  if (Reflect.get(value, SERVER_CONFIGURATION_BRAND) !== true) {
41
- return Validation.failure({
42
- error: ServerError,
43
- message: 'Expected a ServerConfiguration instance.',
44
- code: 'INVALID_SERVER_CONFIGURATION_INSTANCE',
45
- custom: true,
46
- });
55
+ return Validation.failure(new ServerError('INVALID_SERVER_CONFIGURATION_INSTANCE'));
47
56
  }
48
57
 
49
58
  return Validation.success();
@@ -54,6 +63,7 @@ export function validateServerConfiguration(value) {
54
63
  *
55
64
  * @param {unknown} value - Value to assert.
56
65
  * @throws {ServerError} If the value does not implement the ServerConfiguration contract.
66
+ *
57
67
  * @example
58
68
  * ```js
59
69
  * assertServerConfiguration(configuration);
@@ -13,6 +13,20 @@
13
13
  import Validation from '#shared/outcome/Validation';
14
14
  import ServerError from '#shared/errors/ServerError';
15
15
 
16
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ /**
18
+ * A successful {@link Validation} instance.
19
+ *
20
+ * @typedef {import('#shared/outcome/Validation').SuccessValidation} SuccessValidation
21
+ */
22
+
23
+ /**
24
+ * A failed {@link Validation} instance.
25
+ *
26
+ * @template {Error} E
27
+ * @typedef {import('#shared/outcome/Validation').FailureValidation<E>} FailureValidation
28
+ */
29
+
16
30
  // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
31
  /**
18
32
  * Validates a system error handler.
@@ -21,7 +35,8 @@ import ServerError from '#shared/errors/ServerError';
21
35
  * parameters: `error` and `exchange`.
22
36
  *
23
37
  * @param {unknown} handler - Handler function to validate.
24
- * @returns {Validation} Validation result.
38
+ * @returns {SuccessValidation|FailureValidation<ServerError>} Validation result.
39
+ *
25
40
  * @example
26
41
  * ```js
27
42
  * const validation = validateSystemErrorHandler((error, exchange) => {
@@ -42,31 +57,25 @@ import ServerError from '#shared/errors/ServerError';
42
57
  */
43
58
  export function validateSystemErrorHandler(handler) {
44
59
  if (typeof handler !== 'function') {
45
- return Validation.failure({
46
- error: ServerError,
47
- code: 'INVALID_SYSTEM_ERROR_HANDLER_TYPE',
48
- custom: true,
49
- options: {
60
+ return Validation.failure(
61
+ new ServerError('INVALID_SYSTEM_ERROR_HANDLER_TYPE', {
50
62
  values: {
51
63
  expected: 'function',
52
64
  received: typeof handler,
53
65
  },
54
- },
55
- });
66
+ }),
67
+ );
56
68
  }
57
69
 
58
70
  if (handler.length !== 2) {
59
- return Validation.failure({
60
- error: ServerError,
61
- code: 'INVALID_SYSTEM_ERROR_HANDLER_ARITY',
62
- custom: true,
63
- options: {
71
+ return Validation.failure(
72
+ new ServerError('INVALID_SYSTEM_ERROR_HANDLER_ARITY', {
64
73
  values: {
65
74
  expected: 2,
66
75
  received: handler.length,
67
76
  },
68
- },
69
- });
77
+ }),
78
+ );
70
79
  }
71
80
 
72
81
  return Validation.success();
@@ -78,6 +87,7 @@ export function validateSystemErrorHandler(handler) {
78
87
  * @param {unknown} handler - Handler function to validate.
79
88
  * @throws {ServerError} If the handler is not a function.
80
89
  * @throws {ServerError} If the handler does not declare exactly two parameters.
90
+ *
81
91
  * @example
82
92
  * ```js
83
93
  * assertSystemErrorHandler((error, exchange) => {