@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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -2
  3. package/index.mjs +23 -0
  4. package/package.json +71 -4
  5. package/source/application/Kernel/index.mjs +1137 -0
  6. package/source/application/Server/index.mjs +1201 -0
  7. package/source/application/configurations/Http2CleartextServerConfiguration/index.mjs +168 -0
  8. package/source/application/configurations/Http2SecureServerConfiguration/index.mjs +172 -0
  9. package/source/application/configurations/HttpServerConfiguration/index.mjs +169 -0
  10. package/source/application/configurations/HttpsServerConfiguration/index.mjs +172 -0
  11. package/source/application/configurations/ServerConfiguration/Options/CORSOptions/CORSOptionsValue.mjs +158 -0
  12. package/source/application/configurations/ServerConfiguration/Options/CORSOptions/index.mjs +87 -0
  13. package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/CSRFOptionsValue.mjs +178 -0
  14. package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/index.mjs +80 -0
  15. package/source/application/configurations/ServerConfiguration/Options/CompressOptions/CompressOptionsValue.mjs +126 -0
  16. package/source/application/configurations/ServerConfiguration/Options/CompressOptions/index.mjs +81 -0
  17. package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/CookieParserOptionsValue.mjs +107 -0
  18. package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/index.mjs +82 -0
  19. package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/CookieSessionOptionsValue.mjs +182 -0
  20. package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/index.mjs +86 -0
  21. package/source/application/configurations/ServerConfiguration/Options/ListenOptions/ListenOptionsValue.mjs +95 -0
  22. package/source/application/configurations/ServerConfiguration/Options/ListenOptions/index.mjs +47 -0
  23. package/source/application/configurations/ServerConfiguration/Options/MiddlewareOption.mjs +102 -0
  24. package/source/application/configurations/ServerConfiguration/Options/Options.mjs +105 -0
  25. package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/RateLimitOptionsValue.mjs +164 -0
  26. package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/index.mjs +84 -0
  27. package/source/application/configurations/ServerConfiguration/Options/RequestOptions/RequestOptionsValue.mjs +108 -0
  28. package/source/application/configurations/ServerConfiguration/Options/RequestOptions/index.mjs +47 -0
  29. package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/ResponseOptionsValue.mjs +101 -0
  30. package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/index.mjs +47 -0
  31. package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/SecurityHeadersOptionsValue.mjs +272 -0
  32. package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/index.mjs +85 -0
  33. package/source/application/configurations/ServerConfiguration/Options/ServerOption.mjs +50 -0
  34. package/source/application/configurations/ServerConfiguration/Options/StaticOptions/StaticOptionsValue.mjs +164 -0
  35. package/source/application/configurations/ServerConfiguration/Options/StaticOptions/index.mjs +89 -0
  36. package/source/application/configurations/ServerConfiguration/index.mjs +781 -0
  37. package/source/application/resolvers/TransportResolver/index.mjs +119 -0
  38. package/source/application/use-cases/CloseServer/index.mjs +85 -0
  39. package/source/application/use-cases/ListenServer/index.mjs +98 -0
  40. package/source/core/EventSystem/index.mjs +110 -0
  41. package/source/core/Exchange/ExchangeContext.mjs +291 -0
  42. package/source/core/Exchange/Telemetry.mjs +193 -0
  43. package/source/core/Exchange/index.mjs +604 -0
  44. package/source/core/ExchangeLayerBuilder/index.mjs +133 -0
  45. package/source/core/IPCMain/IPCMain.mjs +507 -0
  46. package/source/core/IPCMain/IPCProtocol.mjs +441 -0
  47. package/source/core/IPCMain/IPCServerChannel.mjs +331 -0
  48. package/source/core/IPCMain/WebSocketAdapter.mjs +189 -0
  49. package/source/core/Request/BodyParser/BodyParser.mjs +197 -0
  50. package/source/core/Request/BodyParser/JSONParser.mjs +70 -0
  51. package/source/core/Request/BodyParser/MultipartParser.mjs +612 -0
  52. package/source/core/Request/BodyParser/URLEncodedParser.mjs +71 -0
  53. package/source/core/Request/RequestHeaders.mjs +177 -0
  54. package/source/core/Request/index.mjs +805 -0
  55. package/source/core/Response/ResponseHeaders.mjs +402 -0
  56. package/source/core/Response/index.mjs +1370 -0
  57. package/source/core/middlewares/CORSMiddleware/index.mjs +289 -0
  58. package/source/core/middlewares/CSRFMiddleware/index.mjs +284 -0
  59. package/source/core/middlewares/CompressMiddleware/index.mjs +460 -0
  60. package/source/core/middlewares/CookieParserMiddleware/index.mjs +194 -0
  61. package/source/core/middlewares/CookieSessionMiddleware/index.mjs +460 -0
  62. package/source/core/middlewares/RateLimitMiddleware/index.mjs +245 -0
  63. package/source/core/middlewares/SecurityHeadersMiddleware/index.mjs +151 -0
  64. package/source/core/middlewares/StaticMiddleware/index.mjs +628 -0
  65. package/source/core/routing/ExchangeLayer/ExchangeMatcher.mjs +127 -0
  66. package/source/core/routing/ExchangeLayer/index.mjs +254 -0
  67. package/source/core/routing/Pipeline/index.mjs +157 -0
  68. package/source/core/routing/Router/Route.mjs +184 -0
  69. package/source/core/routing/Router/index.mjs +523 -0
  70. package/source/core/routing/RouterRegister/OptionsMiddleware.mjs +147 -0
  71. package/source/core/routing/RouterRegister/index.mjs +150 -0
  72. package/source/core/routing/RouterSystem/index.mjs +225 -0
  73. package/source/core/value-objects/Address/index.mjs +281 -0
  74. package/source/core/value-objects/Endpoint/index.mjs +293 -0
  75. package/source/index.mjs +62 -0
  76. package/source/infrastructure/adapters/Http2Adapter/index.mjs +144 -0
  77. package/source/infrastructure/adapters/Http2CleartextAdapter/index.mjs +147 -0
  78. package/source/infrastructure/adapters/HttpAdapter/index.mjs +124 -0
  79. package/source/infrastructure/adapters/HttpsAdapter/index.mjs +124 -0
  80. package/source/infrastructure/adapters/TransportAdapter/createWebSocketOpenRequest.mjs +843 -0
  81. package/source/infrastructure/adapters/TransportAdapter/index.mjs +555 -0
  82. package/source/shared/Identifier/index.mjs +671 -0
  83. package/source/shared/constants/symbols/brands/index.mjs +45 -0
  84. package/source/shared/domain/UUIDV7/index.mjs +346 -0
  85. package/source/shared/errors/BaseError/index.mjs +157 -0
  86. package/source/shared/errors/IPCError/index.mjs +97 -0
  87. package/source/shared/errors/MiddlewareError/index.mjs +106 -0
  88. package/source/shared/errors/PathnamePatternError/index.mjs +103 -0
  89. package/source/shared/errors/RequestError/index.mjs +116 -0
  90. package/source/shared/errors/ResponseError/index.mjs +140 -0
  91. package/source/shared/errors/RouterError/index.mjs +90 -0
  92. package/source/shared/errors/ServerConfigurationError/index.mjs +551 -0
  93. package/source/shared/errors/ServerError/index.mjs +127 -0
  94. package/source/shared/errors/WebSocketError/index.mjs +58 -0
  95. package/source/shared/outcome/ErrorSchema.mjs +361 -0
  96. package/source/shared/outcome/Result/index.mjs +239 -0
  97. package/source/shared/outcome/Validation/index.mjs +208 -0
  98. package/source/shared/validations/Middleware/index.mjs +160 -0
  99. package/source/shared/validations/PathnamePattern/index.mjs +256 -0
  100. package/source/shared/validations/Server/NotFoundHandler/index.mjs +94 -0
  101. package/source/shared/validations/Server/Router/index.mjs +68 -0
  102. package/source/shared/validations/Server/ServerConfiguration/index.mjs +68 -0
  103. package/source/shared/validations/Server/SystemErrorHandler/index.mjs +94 -0
  104. package/source/shared/validations/ServerConfiguration/CORSOptions/index.mjs +310 -0
  105. package/source/shared/validations/ServerConfiguration/CSRFOptions/index.mjs +299 -0
  106. package/source/shared/validations/ServerConfiguration/CompressOptions/index.mjs +204 -0
  107. package/source/shared/validations/ServerConfiguration/CookieParserOptions/index.mjs +102 -0
  108. package/source/shared/validations/ServerConfiguration/CookieSessionOptions/index.mjs +332 -0
  109. package/source/shared/validations/ServerConfiguration/ListenOptions/index.mjs +178 -0
  110. package/source/shared/validations/ServerConfiguration/RateLimitOptions/index.mjs +229 -0
  111. package/source/shared/validations/ServerConfiguration/RequestOptions/index.mjs +132 -0
  112. package/source/shared/validations/ServerConfiguration/ResponseOptions/index.mjs +122 -0
  113. package/source/shared/validations/ServerConfiguration/SecurityHeadersOptions/index.mjs +137 -0
  114. package/source/shared/validations/ServerConfiguration/StaticOptions/index.mjs +248 -0
  115. package/types/index.d.ts +719 -0
@@ -0,0 +1,101 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the ResponseOptionsValue value object.
4
+ *
5
+ * @description Normalizes and validates response configuration used by
6
+ * ServerConfiguration. When options are omitted, the value is undefined.
7
+ *
8
+ * @module ResponseOptionsValue
9
+ */
10
+
11
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
+ // » IMPORT LOCAL MODULES
13
+ import { assertResponseOptions } from '#shared/validations/ServerConfiguration/ResponseOptions';
14
+
15
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ /**
17
+ * Domain error thrown by server configuration validation.
18
+ *
19
+ * @typedef {import('#shared/errors/ServerConfigurationError').default} ServerConfigurationError
20
+ */
21
+
22
+ /**
23
+ * Represents the response options accepted by the server configuration.
24
+ *
25
+ * @typedef {object} ResponseOptionsInput
26
+ * @property {boolean} [etag] - Whether to generate a weak ETag for buffered bodies.
27
+ * @property {string} [defaultCharset] - Charset appended to eligible Content-Type headers when none is set.
28
+ */
29
+
30
+ /**
31
+ * Represents the normalized response options.
32
+ *
33
+ * @typedef {object} ResponseOptionsData
34
+ * @property {boolean} [etag] - Whether to generate a weak ETag for buffered bodies.
35
+ * @property {string} [defaultCharset] - Charset appended to eligible Content-Type headers when none is set.
36
+ */
37
+
38
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
39
+ /**
40
+ * Immutable value object representing normalized response options.
41
+ *
42
+ * @classdesc Validates and normalizes response options for the server.
43
+ * When options are omitted, the value is undefined.
44
+ */
45
+ class ResponseOptionsValue {
46
+ /**
47
+ * Normalized response options.
48
+ *
49
+ * @type {Readonly<ResponseOptionsData>|undefined}
50
+ */
51
+ #value;
52
+
53
+ /**
54
+ * Creates a new {@link ResponseOptionsValue}.
55
+ *
56
+ * @param {ResponseOptionsInput} [options] - The response options.
57
+ * @throws {ServerConfigurationError} If `options` is not a plain object.
58
+ * @throws {ServerConfigurationError} If `etag` is defined and is not a boolean.
59
+ * @throws {ServerConfigurationError} If `defaultCharset` is defined and is not a string.
60
+ * @throws {ServerConfigurationError} If `defaultCharset` is defined and is an empty string.
61
+ * @example
62
+ * ```js
63
+ * const options = new ResponseOptionsValue({ etag: true, defaultCharset: 'utf-8' });
64
+ *
65
+ * options.value;
66
+ * // => { etag: true, defaultCharset: 'utf-8' }
67
+ * ```
68
+ *
69
+ * @example
70
+ * ```js
71
+ * const options = new ResponseOptionsValue();
72
+ *
73
+ * options.value;
74
+ * // => undefined
75
+ * ```
76
+ */
77
+ constructor(options) {
78
+ assertResponseOptions(options);
79
+
80
+ this.#value =
81
+ options === undefined
82
+ ? options
83
+ : Object.freeze({
84
+ etag: options.etag,
85
+ defaultCharset: options.defaultCharset,
86
+ });
87
+ }
88
+
89
+ /**
90
+ * The response options.
91
+ *
92
+ * @readonly
93
+ * @type {Readonly<ResponseOptionsData>|undefined}
94
+ */
95
+ get value() {
96
+ return this.#value;
97
+ }
98
+ }
99
+
100
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
101
+ export default ResponseOptionsValue;
@@ -0,0 +1,47 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the ResponseOptions server configuration option.
4
+ *
5
+ * @description ResponseOptions wraps a normalized ResponseOptionsValue into
6
+ * the server configuration option hierarchy.
7
+ *
8
+ * @module ResponseOptions
9
+ */
10
+
11
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
+ // » IMPORT LOCAL MODULES
13
+ import ServerOption from '../ServerOption.mjs';
14
+ import ResponseOptionsValue from './ResponseOptionsValue.mjs';
15
+
16
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ /**
18
+ * Represents the response options accepted by the server configuration.
19
+ *
20
+ * @typedef {import('./ResponseOptionsValue.mjs').ResponseOptionsInput} ResponseOptionsInput
21
+ */
22
+
23
+ /**
24
+ * Represents the normalized response options.
25
+ *
26
+ * @typedef {import('./ResponseOptionsValue.mjs').ResponseOptionsData} ResponseOptionsData
27
+ */
28
+
29
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
30
+ /**
31
+ * Server configuration option wrapping a normalized response configuration.
32
+ *
33
+ * @augments {ServerOption<ResponseOptionsData|undefined>}
34
+ */
35
+ class ResponseOptions extends ServerOption {
36
+ /**
37
+ * Creates a new {@link ResponseOptions}.
38
+ *
39
+ * @param {ResponseOptionsInput} [options] - The response options.
40
+ */
41
+ constructor(options) {
42
+ super('response', new ResponseOptionsValue(options));
43
+ }
44
+ }
45
+
46
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
47
+ export default ResponseOptions;
@@ -0,0 +1,272 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the SecurityHeadersOptionsValue value object.
4
+ *
5
+ * @description Normalizes and validates security headers middleware
6
+ * configuration used by SecurityHeadersMiddleware. When options are
7
+ * omitted, defaults are applied and the value is always a complete
8
+ * SecurityHeadersOptionsData object.
9
+ *
10
+ * @module SecurityHeadersOptionsValue
11
+ */
12
+
13
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14
+ // » IMPORT LOCAL MODULES
15
+ import { assertSecurityHeadersOptions } from '#shared/validations/ServerConfiguration/SecurityHeadersOptions';
16
+
17
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ /**
19
+ * Domain error thrown by server configuration validation.
20
+ *
21
+ * @typedef {import('#shared/errors/ServerConfigurationError').default} ServerConfigurationError
22
+ */
23
+
24
+ /**
25
+ * Represents the security headers options accepted by the server configuration.
26
+ *
27
+ * Every property accepts a string header value or `false` to omit the header.
28
+ *
29
+ * @typedef {object} SecurityHeadersOptionsInput
30
+ * @property {string|false} [contentSecurityPolicy] - Value for the Content-Security-Policy header, or `false` to omit it.
31
+ * @property {string|false} [crossOriginEmbedderPolicy] - Value for the Cross-Origin-Embedder-Policy header, or `false` to omit it.
32
+ * @property {string|false} [crossOriginOpenerPolicy] - Value for the Cross-Origin-Opener-Policy header, or `false` to omit it.
33
+ * @property {string|false} [crossOriginResourcePolicy] - Value for the Cross-Origin-Resource-Policy header, or `false` to omit it.
34
+ * @property {string|false} [originAgentCluster] - Value for the Origin-Agent-Cluster header, or `false` to omit it.
35
+ * @property {string|false} [permissionsPolicy] - Value for the Permissions-Policy header, or `false` to omit it.
36
+ * @property {string|false} [referrerPolicy] - Value for the Referrer-Policy header, or `false` to omit it.
37
+ * @property {string|false} [strictTransportSecurity] - Value for the Strict-Transport-Security header, or `false` to omit it.
38
+ * @property {string|false} [xContentTypeOptions] - Value for the X-Content-Type-Options header, or `false` to omit it.
39
+ * @property {string|false} [xDnsPrefetchControl] - Value for the X-DNS-Prefetch-Control header, or `false` to omit it.
40
+ * @property {string|false} [xDownloadOptions] - Value for the X-Download-Options header, or `false` to omit it.
41
+ * @property {string|false} [xFrameOptions] - Value for the X-Frame-Options header, or `false` to omit it.
42
+ * @property {string|false} [xPermittedCrossDomainPolicies] - Value for the X-Permitted-Cross-Domain-Policies header, or `false` to omit it.
43
+ * @property {string|false} [xXssProtection] - Value for the legacy X-XSS-Protection header, or `false` to omit it.
44
+ */
45
+
46
+ /**
47
+ * Represents the normalized security headers options.
48
+ *
49
+ * @typedef {object} SecurityHeadersOptionsData
50
+ * @property {string|false} contentSecurityPolicy - Value for the Content-Security-Policy header, or `false` to omit it.
51
+ * @property {string|false} crossOriginEmbedderPolicy - Value for the Cross-Origin-Embedder-Policy header, or `false` to omit it.
52
+ * @property {string|false} crossOriginOpenerPolicy - Value for the Cross-Origin-Opener-Policy header, or `false` to omit it.
53
+ * @property {string|false} crossOriginResourcePolicy - Value for the Cross-Origin-Resource-Policy header, or `false` to omit it.
54
+ * @property {string|false} originAgentCluster - Value for the Origin-Agent-Cluster header, or `false` to omit it.
55
+ * @property {string|false} permissionsPolicy - Value for the Permissions-Policy header, or `false` to omit it.
56
+ * @property {string|false} referrerPolicy - Value for the Referrer-Policy header, or `false` to omit it.
57
+ * @property {string|false} strictTransportSecurity - Value for the Strict-Transport-Security header, or `false` to omit it.
58
+ * @property {string|false} xContentTypeOptions - Value for the X-Content-Type-Options header, or `false` to omit it.
59
+ * @property {string|false} xDnsPrefetchControl - Value for the X-DNS-Prefetch-Control header, or `false` to omit it.
60
+ * @property {string|false} xDownloadOptions - Value for the X-Download-Options header, or `false` to omit it.
61
+ * @property {string|false} xFrameOptions - Value for the X-Frame-Options header, or `false` to omit it.
62
+ * @property {string|false} xPermittedCrossDomainPolicies - Value for the X-Permitted-Cross-Domain-Policies header, or `false` to omit it.
63
+ * @property {string|false} xXssProtection - Value for the legacy X-XSS-Protection header, or `false` to omit it.
64
+ */
65
+
66
+ // ━━ CONSTANTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
67
+ /**
68
+ * Default value for the Content-Security-Policy header.
69
+ *
70
+ * Disabled by default because it must be tailored to each application.
71
+ *
72
+ * @type {string|false}
73
+ */
74
+ const DEFAULT_CONTENT_SECURITY_POLICY = false;
75
+
76
+ /**
77
+ * Default value for the Cross-Origin-Embedder-Policy header.
78
+ *
79
+ * Disabled by default because it breaks cross-origin resources that do not
80
+ * opt in via CORP or CORS.
81
+ *
82
+ * @type {string|false}
83
+ */
84
+ const DEFAULT_CROSS_ORIGIN_EMBEDDER_POLICY = false;
85
+
86
+ /**
87
+ * Default value for the Cross-Origin-Opener-Policy header.
88
+ *
89
+ * @type {string|false}
90
+ */
91
+ const DEFAULT_CROSS_ORIGIN_OPENER_POLICY = 'same-origin';
92
+
93
+ /**
94
+ * Default value for the Cross-Origin-Resource-Policy header.
95
+ *
96
+ * @type {string|false}
97
+ */
98
+ const DEFAULT_CROSS_ORIGIN_RESOURCE_POLICY = 'same-origin';
99
+
100
+ /**
101
+ * Default value for the Origin-Agent-Cluster header.
102
+ *
103
+ * @type {string|false}
104
+ */
105
+ const DEFAULT_ORIGIN_AGENT_CLUSTER = '?1';
106
+
107
+ /**
108
+ * Default value for the Permissions-Policy header.
109
+ *
110
+ * Disabled by default because it must be tailored to each application.
111
+ *
112
+ * @type {string|false}
113
+ */
114
+ const DEFAULT_PERMISSIONS_POLICY = false;
115
+
116
+ /**
117
+ * Default value for the Referrer-Policy header.
118
+ *
119
+ * Preserves the full referrer for same-origin navigation and limits the
120
+ * information sent cross-origin.
121
+ *
122
+ * @type {string|false}
123
+ */
124
+ const DEFAULT_REFERRER_POLICY = 'strict-origin-when-cross-origin';
125
+
126
+ /**
127
+ * Default value for the Strict-Transport-Security header.
128
+ *
129
+ * @type {string|false}
130
+ */
131
+ const DEFAULT_STRICT_TRANSPORT_SECURITY = 'max-age=31536000; includeSubDomains';
132
+
133
+ /**
134
+ * Default value for the X-Content-Type-Options header.
135
+ *
136
+ * @type {string|false}
137
+ */
138
+ const DEFAULT_X_CONTENT_TYPE_OPTIONS = 'nosniff';
139
+
140
+ /**
141
+ * Default value for the X-DNS-Prefetch-Control header.
142
+ *
143
+ * @type {string|false}
144
+ */
145
+ const DEFAULT_X_DNS_PREFETCH_CONTROL = 'off';
146
+
147
+ /**
148
+ * Default value for the X-Download-Options header.
149
+ *
150
+ * @type {string|false}
151
+ */
152
+ const DEFAULT_X_DOWNLOAD_OPTIONS = 'noopen';
153
+
154
+ /**
155
+ * Default value for the X-Frame-Options header.
156
+ *
157
+ * @type {string|false}
158
+ */
159
+ const DEFAULT_X_FRAME_OPTIONS = 'SAMEORIGIN';
160
+
161
+ /**
162
+ * Default value for the X-Permitted-Cross-Domain-Policies header.
163
+ *
164
+ * @type {string|false}
165
+ */
166
+ const DEFAULT_X_PERMITTED_CROSS_DOMAIN_POLICIES = 'none';
167
+
168
+ /**
169
+ * Default value for the legacy X-XSS-Protection header.
170
+ *
171
+ * @type {string|false}
172
+ */
173
+ const DEFAULT_X_XSS_PROTECTION = '0';
174
+
175
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
176
+ /**
177
+ * Immutable value object representing normalized security headers middleware
178
+ * options.
179
+ *
180
+ * @classdesc Validates and normalizes security headers middleware options.
181
+ * When options are provided, defaults are applied for any omitted property.
182
+ * When options are omitted, the value is undefined.
183
+ */
184
+ class SecurityHeadersOptionsValue {
185
+ /**
186
+ * The normalized security headers options.
187
+ *
188
+ * @type {Readonly<SecurityHeadersOptionsData>|undefined}
189
+ */
190
+ #value;
191
+
192
+ /**
193
+ * Creates a new {@link SecurityHeadersOptionsValue}.
194
+ *
195
+ * @param {SecurityHeadersOptionsInput} [options] - The security headers middleware options.
196
+ * @throws {ServerConfigurationError} If `options` is invalid.
197
+ * @example
198
+ * ```js
199
+ * const options = new SecurityHeadersOptionsValue({
200
+ * contentSecurityPolicy: "default-src 'self'",
201
+ * xFrameOptions: false,
202
+ * });
203
+ *
204
+ * options.value;
205
+ * // => {
206
+ * // contentSecurityPolicy: "default-src 'self'",
207
+ * // crossOriginEmbedderPolicy: false,
208
+ * // crossOriginOpenerPolicy: 'same-origin',
209
+ * // crossOriginResourcePolicy: 'same-origin',
210
+ * // originAgentCluster: '?1',
211
+ * // permissionsPolicy: false,
212
+ * // referrerPolicy: 'strict-origin-when-cross-origin',
213
+ * // strictTransportSecurity: 'max-age=31536000; includeSubDomains',
214
+ * // xContentTypeOptions: 'nosniff',
215
+ * // xDnsPrefetchControl: 'off',
216
+ * // xDownloadOptions: 'noopen',
217
+ * // xFrameOptions: false,
218
+ * // xPermittedCrossDomainPolicies: 'none',
219
+ * // xXssProtection: '0',
220
+ * // }
221
+ * ```
222
+ *
223
+ * @example
224
+ * ```js
225
+ * const options = new SecurityHeadersOptionsValue();
226
+ *
227
+ * options.value;
228
+ * // => undefined
229
+ * ```
230
+ */
231
+ constructor(options) {
232
+ assertSecurityHeadersOptions(options);
233
+
234
+ this.#value =
235
+ options === undefined
236
+ ? options
237
+ : Object.freeze({
238
+ contentSecurityPolicy: options.contentSecurityPolicy ?? DEFAULT_CONTENT_SECURITY_POLICY,
239
+ crossOriginEmbedderPolicy:
240
+ options.crossOriginEmbedderPolicy ?? DEFAULT_CROSS_ORIGIN_EMBEDDER_POLICY,
241
+ crossOriginOpenerPolicy:
242
+ options.crossOriginOpenerPolicy ?? DEFAULT_CROSS_ORIGIN_OPENER_POLICY,
243
+ crossOriginResourcePolicy:
244
+ options.crossOriginResourcePolicy ?? DEFAULT_CROSS_ORIGIN_RESOURCE_POLICY,
245
+ originAgentCluster: options.originAgentCluster ?? DEFAULT_ORIGIN_AGENT_CLUSTER,
246
+ permissionsPolicy: options.permissionsPolicy ?? DEFAULT_PERMISSIONS_POLICY,
247
+ referrerPolicy: options.referrerPolicy ?? DEFAULT_REFERRER_POLICY,
248
+ strictTransportSecurity:
249
+ options.strictTransportSecurity ?? DEFAULT_STRICT_TRANSPORT_SECURITY,
250
+ xContentTypeOptions: options.xContentTypeOptions ?? DEFAULT_X_CONTENT_TYPE_OPTIONS,
251
+ xDnsPrefetchControl: options.xDnsPrefetchControl ?? DEFAULT_X_DNS_PREFETCH_CONTROL,
252
+ xDownloadOptions: options.xDownloadOptions ?? DEFAULT_X_DOWNLOAD_OPTIONS,
253
+ xFrameOptions: options.xFrameOptions ?? DEFAULT_X_FRAME_OPTIONS,
254
+ xPermittedCrossDomainPolicies:
255
+ options.xPermittedCrossDomainPolicies ?? DEFAULT_X_PERMITTED_CROSS_DOMAIN_POLICIES,
256
+ xXssProtection: options.xXssProtection ?? DEFAULT_X_XSS_PROTECTION,
257
+ });
258
+ }
259
+
260
+ /**
261
+ * The normalized security headers options.
262
+ *
263
+ * @readonly
264
+ * @type {Readonly<SecurityHeadersOptionsData>|undefined}
265
+ */
266
+ get value() {
267
+ return this.#value;
268
+ }
269
+ }
270
+
271
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
272
+ export default SecurityHeadersOptionsValue;
@@ -0,0 +1,85 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the SecurityHeadersOptions middleware configuration option.
4
+ *
5
+ * @description SecurityHeadersOptions wraps a normalized
6
+ * SecurityHeadersOptionsValue into the middleware configuration option
7
+ * hierarchy.
8
+ *
9
+ * @module SecurityHeadersOptions
10
+ */
11
+
12
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
13
+ // » IMPORT LOCAL MODULES
14
+ import MiddlewareOption from '../MiddlewareOption.mjs';
15
+ import SecurityHeadersOptionsValue from './SecurityHeadersOptionsValue.mjs';
16
+
17
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ /**
19
+ * Represents the security headers options accepted by the server configuration.
20
+ *
21
+ * @typedef {import('./SecurityHeadersOptionsValue.mjs').SecurityHeadersOptionsInput} SecurityHeadersOptionsInput
22
+ */
23
+
24
+ /**
25
+ * Represents the normalized security headers options.
26
+ *
27
+ * @typedef {import('./SecurityHeadersOptionsValue.mjs').SecurityHeadersOptionsData} SecurityHeadersOptionsData
28
+ */
29
+
30
+ /**
31
+ * Represents one middleware configuration consumed by the exchange layer builder.
32
+ *
33
+ * @typedef {import('../MiddlewareOption.mjs').MiddlewareConfiguration} MiddlewareConfiguration
34
+ */
35
+
36
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
37
+ /**
38
+ * Middleware configuration option wrapping a normalized security headers
39
+ * configuration.
40
+ *
41
+ * @augments {MiddlewareOption<SecurityHeadersOptionsData|undefined>}
42
+ */
43
+ class SecurityHeadersOptions extends MiddlewareOption {
44
+ /**
45
+ * Creates a new {@link SecurityHeadersOptions}.
46
+ *
47
+ * @param {SecurityHeadersOptionsInput} [options] - The security headers middleware options.
48
+ * @example
49
+ * ```js
50
+ * const securityHeadersOptions = new SecurityHeadersOptions({
51
+ * contentSecurityPolicy: "default-src 'self'",
52
+ * xFrameOptions: 'DENY',
53
+ * });
54
+ * ```
55
+ */
56
+ constructor(options) {
57
+ super('securityHeaders', new SecurityHeadersOptionsValue(options));
58
+ }
59
+
60
+ /**
61
+ * Composes the security headers middleware configuration consumed by the
62
+ * exchange layer builder.
63
+ *
64
+ * Security headers are a cross-cutting concern applied to every request
65
+ * regardless of pathname or method, so both `pathnamePattern` and `method`
66
+ * are `undefined`.
67
+ *
68
+ * @returns {MiddlewareConfiguration} The composed middleware configuration.
69
+ * @example
70
+ * ```js
71
+ * const configuration = securityHeadersOptions.compose();
72
+ * ```
73
+ */
74
+ compose() {
75
+ return {
76
+ name: this.name,
77
+ options: this.value,
78
+ pathnamePattern: undefined,
79
+ method: undefined,
80
+ };
81
+ }
82
+ }
83
+
84
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
85
+ export default SecurityHeadersOptions;
@@ -0,0 +1,50 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the abstract base for server configuration options.
4
+ *
5
+ * @description ServerOption identifies configuration options that belong to
6
+ * the server layer (listen, request, response).
7
+ *
8
+ * @module ServerOption
9
+ */
10
+
11
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
+ // » IMPORT LOCAL MODULES
13
+ import Options from './Options.mjs';
14
+
15
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ /**
17
+ * Represents a value object wrapping a normalized configuration value.
18
+ *
19
+ * @template {Record<string, unknown>|undefined} TValue
20
+ * @typedef {import('./Options.mjs').ValueObject<TValue>} ValueObject
21
+ */
22
+
23
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
24
+ /**
25
+ * Abstract base class for server configuration options.
26
+ *
27
+ * @abstract
28
+ * @template {Record<string, unknown>|undefined} TValue
29
+ * @augments Options<TValue>
30
+ */
31
+ class ServerOption extends Options {
32
+ /**
33
+ * Creates a server configuration option instance.
34
+ *
35
+ * @abstract
36
+ * @param {string} name - Option name.
37
+ * @param {ValueObject<TValue>} value - Normalized option value.
38
+ * @throws {TypeError} If ServerOption is instantiated directly.
39
+ */
40
+ constructor(name, value) {
41
+ if (new.target === ServerOption) {
42
+ throw new TypeError('ServerOption is an abstract class and cannot be instantiated');
43
+ }
44
+
45
+ super('server', name, value.value);
46
+ }
47
+ }
48
+
49
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
50
+ export default ServerOption;