@flancer32/teq-web 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +236 -127
  3. package/ai/AGENTS.md +36 -0
  4. package/ai/abstractions.md +75 -0
  5. package/ai/examples/minimal-server.md +78 -0
  6. package/ai/overview.md +27 -0
  7. package/ai/rules.md +41 -0
  8. package/package.json +43 -37
  9. package/src/Back/Api/Handler.mjs +26 -0
  10. package/src/Back/{Defaults.js → Defaults.mjs} +6 -1
  11. package/src/Back/Dto/Info.mjs +66 -0
  12. package/src/Back/Dto/{Handler/Source.js → Source.mjs} +26 -23
  13. package/src/Back/Enum/Server/Type.mjs +13 -0
  14. package/src/Back/Enum/Stage.mjs +13 -0
  15. package/src/Back/Handler/Pre/Log.mjs +59 -0
  16. package/src/Back/Handler/Static/A/{Config.js → Config.mjs} +14 -3
  17. package/src/Back/Handler/Static/A/{Fallback.js → Fallback.mjs} +16 -4
  18. package/src/Back/Handler/Static/A/{FileService.js → FileService.mjs} +31 -14
  19. package/src/Back/Handler/Static/A/{Registry.js → Registry.mjs} +18 -6
  20. package/src/Back/Handler/Static/A/{Resolver.js → Resolver.mjs} +13 -2
  21. package/src/Back/Handler/Static.mjs +83 -0
  22. package/src/Back/Helper/Cast.mjs +116 -0
  23. package/src/Back/Helper/{Mime.js → Mime.mjs} +2 -0
  24. package/src/Back/Helper/Order/Kahn.mjs +69 -0
  25. package/src/Back/Helper/{Respond.js → Respond.mjs} +14 -3
  26. package/src/Back/Logger.mjs +57 -0
  27. package/src/Back/PipelineEngine.mjs +228 -0
  28. package/src/Back/Server/Config/{Tls.js → Tls.mjs} +35 -33
  29. package/src/Back/Server/Config.mjs +69 -0
  30. package/src/Back/{Server.js → Server.mjs} +35 -24
  31. package/types.d.ts +27 -22
  32. package/src/AGENTS.md +0 -108
  33. package/src/Back/Api/Handler.js +0 -26
  34. package/src/Back/Dispatcher.js +0 -115
  35. package/src/Back/Dto/Handler/Info.js +0 -68
  36. package/src/Back/Enum/Server/Type.js +0 -12
  37. package/src/Back/Enum/Stage.js +0 -10
  38. package/src/Back/Handler/Pre/Log.js +0 -45
  39. package/src/Back/Handler/Static.js +0 -63
  40. package/src/Back/Helper/Cast.js +0 -114
  41. package/src/Back/Helper/Order/Kahn.js +0 -66
  42. package/src/Back/Logger.js +0 -53
  43. package/src/Back/Server/Config.js +0 -69
  44. package/teqfw.json +0 -8
@@ -0,0 +1,83 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * Universal static-file PROCESS handler.
5
+ *
6
+ * @implements Fl32_Web_Back_Api_Handler
7
+ */
8
+ export const __deps__ = Object.freeze({
9
+ registry: 'Fl32_Web_Back_Handler_Static_A_Registry$',
10
+ fileService: 'Fl32_Web_Back_Handler_Static_A_FileService$',
11
+ respond: 'Fl32_Web_Back_Helper_Respond$',
12
+ logger: 'Fl32_Web_Back_Logger$',
13
+ dtoInfoFactory: 'Fl32_Web_Back_Dto_Info__Factory$',
14
+ STAGE: 'Fl32_Web_Back_Enum_Stage$',
15
+ });
16
+
17
+ /**
18
+ * @typedef {object} Fl32_Web_Back_Handler_StaticConstructorParams
19
+ * @property {Fl32_Web_Back_Handler_Static_A_Registry} registry
20
+ * @property {Fl32_Web_Back_Handler_Static_A_FileService} fileService
21
+ * @property {Fl32_Web_Back_Helper_Respond} respond
22
+ * @property {Fl32_Web_Back_Logger} logger
23
+ * @property {Fl32_Web_Back_Dto_Info$Factory} dtoInfoFactory
24
+ * @property {Fl32_Web_Back_Enum_Stage} STAGE
25
+ */
26
+
27
+ export default class Fl32_Web_Back_Handler_Static {
28
+ /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
29
+ /**
30
+ * @param {Fl32_Web_Back_Handler_StaticConstructorParams} params
31
+ */
32
+ constructor(
33
+ {
34
+ registry,
35
+ fileService,
36
+ respond,
37
+ logger,
38
+ dtoInfoFactory,
39
+ STAGE,
40
+ }
41
+ ) {
42
+ /* eslint-enable jsdoc/check-param-names */
43
+
44
+ const _info = dtoInfoFactory.create({
45
+ name: this.constructor.name,
46
+ stage: STAGE.PROCESS,
47
+ });
48
+
49
+ /**
50
+ * Initialize registry with provided sources.
51
+ *
52
+ * @param {{sources: Fl32_Web_Back_Dto_Source[]}} params
53
+ * @returns {Promise<void>}
54
+ */
55
+ this.init = async ({sources = []} = {}) => {
56
+ registry.addConfigs(sources);
57
+ };
58
+
59
+ /**
60
+ * Attempt to handle incoming request.
61
+ *
62
+ * @param {Fl32_Web_Back_PipelineEngine_RequestContext} context
63
+ * @returns {Promise<void>}
64
+ */
65
+ this.handle = async (context) => {
66
+ const req = context.request;
67
+ const res = context.response;
68
+ if (!respond.isWritable(res)) return;
69
+ const urlPath = decodeURIComponent(req.url.split('?')[0]);
70
+ const match = registry.find(urlPath);
71
+ if (!match) return;
72
+ const served = await fileService.serve(match.config, match.rel, req, res);
73
+ if (served) {
74
+ context.complete();
75
+ }
76
+ };
77
+
78
+ /**
79
+ * @returns {Fl32_Web_Back_Dto_Info}
80
+ */
81
+ this.getRegistrationInfo = () => _info;
82
+ }
83
+ }
@@ -0,0 +1,116 @@
1
+ // @ts-check
2
+
3
+ export default class Fl32_Web_Back_Helper_Cast {
4
+ constructor() {
5
+ /**
6
+ * Cast input data into an array. Ensures the result is always an array.
7
+ * Optionally casts each item using the provided itemCast function.
8
+ *
9
+ * @param {*} data - Input data to be cast to array.
10
+ * @param {function(*): *} [itemCast] - Optional function to cast each item.
11
+ * @returns {Array}
12
+ */
13
+ this.array = function (data, itemCast) {
14
+ let arr = [];
15
+
16
+ if (Array.isArray(data)) {
17
+ arr = data;
18
+ } else if (data !== null) {
19
+ arr = [data];
20
+ }
21
+
22
+ return (typeof itemCast === 'function')
23
+ ? arr.map(itemCast).filter(v => v !== undefined)
24
+ : arr;
25
+ };
26
+
27
+ /**
28
+ * Cast input data into decimal 'number' data type.
29
+ * @param {*} data
30
+ * @returns {number|undefined}
31
+ */
32
+ this.decimal = function (data) {
33
+ const res = Number.parseFloat(data);
34
+ return ((typeof res === 'number') && (!isNaN(res))) ? res : undefined;
35
+ };
36
+
37
+ /**
38
+ * Cast input data into a valid enumeration value.
39
+ * Supports case normalization (upper/lower).
40
+ * If both `upper` and `lower` are true, `upper` takes precedence.
41
+ *
42
+ * @param {*} data - The input to cast.
43
+ * @param {object} enu - Object whose values represent valid enum values.
44
+ * @param {object} [params] - Parameters object.
45
+ * @param {boolean} [params.lower] - Normalize input to lower case before comparison.
46
+ * @param {boolean} [params.upper] - Normalize input to upper case before comparison.
47
+ * @returns {string|undefined}
48
+ */
49
+ this.enum = function (data, enu, {lower, upper} = {}) {
50
+ let norm = data;
51
+
52
+ if (typeof data === 'string') {
53
+ if (upper) norm = data.toUpperCase();
54
+ else if (lower) norm = data.toLowerCase();
55
+ }
56
+
57
+ const values = Object.values(enu);
58
+ return values.includes(norm) ? norm : undefined;
59
+ };
60
+
61
+ /**
62
+ * Cast input data into integer 'number' data type.
63
+ * @param {*} data - Input data to be cast to integer.
64
+ * @returns {number|undefined}
65
+ */
66
+ this.int = function (data) {
67
+ const norm = (typeof data === 'string') ? data.trim() : data;
68
+ const res = Number.parseInt(norm);
69
+ return ((typeof res === 'number') && (!isNaN(res))) ? res : undefined;
70
+ };
71
+
72
+ /**
73
+ * Cast input data into 'string' data type.
74
+ * @param {*} data - Input data to be cast to string.
75
+ * @returns {string|undefined}
76
+ */
77
+ this.string = function (data) {
78
+ if (typeof data === 'string') {
79
+ return data;
80
+ } else if (typeof data === 'number') {
81
+ return String(data);
82
+ } else if (typeof data === 'boolean') {
83
+ return (data) ? 'true' : 'false';
84
+ }
85
+ return undefined;
86
+ };
87
+
88
+ /**
89
+ * Cast an object to a map with string keys and array-of-string values.
90
+ * Throws error on invalid structure or values.
91
+ *
92
+ * @param {*} data - Raw input to cast.
93
+ * @returns {Record<string, string[]>}
94
+ */
95
+ this.stringArrayMap = function (data) {
96
+ if (data === undefined) return {};
97
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
98
+ throw new Error('Invalid value for allow');
99
+ }
100
+ const res = {};
101
+ for (const [key, arr] of Object.entries(data)) {
102
+ if (!Array.isArray(arr)) throw new Error(`Invalid allow list for ${key}`);
103
+ const k = this.string(key);
104
+ if (!k) throw new Error('Invalid allow key');
105
+ const items = [];
106
+ for (const item of arr) {
107
+ const val = this.string(item);
108
+ if (!val) throw new Error(`Invalid allow list for ${k}`);
109
+ items.push(val);
110
+ }
111
+ res[k] = items;
112
+ }
113
+ return res;
114
+ };
115
+ }
116
+ }
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  /**
2
4
  * MIME type helper with built-in mapping for common file extensions.
3
5
  * Can be replaced or extended by the application via the DI container.
@@ -0,0 +1,69 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * Sorts named handlers by relative `before` / `after` constraints using Kahn's algorithm.
5
+ */
6
+ export default class Fl32_Web_Back_Helper_Order_Kahn {
7
+ constructor() {
8
+ /**
9
+ * Topologically sorts handlers with `name`, `before`, `after` fields.
10
+ *
11
+ * @param {Fl32_Web_Back_Api_Handler[]} handlers - Handlers to sort.
12
+ * @returns {Fl32_Web_Back_Api_Handler[]} - Sorted list.
13
+ * @throws {Error} - If circular dependency is detected.
14
+ */
15
+ this.sort = function (handlers) {
16
+ const nameToHandler = new Map();
17
+ const graph = new Map(); // name => Set of downstream nodes
18
+ const inDegree = new Map(); // name => number of incoming edges
19
+
20
+ // Initialize maps
21
+ for (const h of handlers) {
22
+ const info = h.getRegistrationInfo();
23
+ const name = info.name;
24
+ nameToHandler.set(name, h);
25
+ graph.set(name, new Set());
26
+ inDegree.set(name, 0);
27
+ }
28
+
29
+ // Build graph
30
+ for (const h of handlers) {
31
+ const {name, after = [], before = []} = h.getRegistrationInfo();
32
+
33
+ for (const dep of after) {
34
+ if (!graph.has(dep)) continue;
35
+ graph.get(dep).add(name);
36
+ inDegree.set(name, inDegree.get(name) + 1);
37
+ }
38
+
39
+ for (const dep of before) {
40
+ if (!graph.has(dep)) continue;
41
+ graph.get(name).add(dep);
42
+ inDegree.set(dep, inDegree.get(dep) + 1);
43
+ }
44
+ }
45
+
46
+ // Kahn's algorithm
47
+ const queue = [];
48
+ for (const [name, count] of inDegree.entries()) {
49
+ if (count === 0) queue.push(name);
50
+ }
51
+
52
+ const sorted = [];
53
+ while (queue.length > 0) {
54
+ const name = queue.shift();
55
+ sorted.push(nameToHandler.get(name));
56
+ for (const neighbor of graph.get(name)) {
57
+ inDegree.set(neighbor, inDegree.get(neighbor) - 1);
58
+ if (inDegree.get(neighbor) === 0) queue.push(neighbor);
59
+ }
60
+ }
61
+
62
+ if (sorted.length !== handlers.length) {
63
+ throw new Error('Circular dependency detected among handlers');
64
+ }
65
+
66
+ return sorted;
67
+ };
68
+ }
69
+ }
@@ -1,11 +1,22 @@
1
+ // @ts-check
2
+
1
3
  /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
4
+ export const __deps__ = Object.freeze({
5
+ http2: 'node_http2',
6
+ });
7
+
8
+ /**
9
+ * @typedef {object} Fl32_Web_Back_Helper_RespondConstructorParams
10
+ * @property {typeof import('node:http2')} http2
11
+ */
12
+
2
13
  export default class Fl32_Web_Back_Helper_Respond {
3
14
  /**
4
- * @param {typeof import('node:http2')} http2
15
+ * @param {Fl32_Web_Back_Helper_RespondConstructorParams} params
5
16
  */
6
17
  constructor(
7
18
  {
8
- 'node:http2': http2,
19
+ http2,
9
20
  }
10
21
  ) {
11
22
  // VARS
@@ -152,4 +163,4 @@ export default class Fl32_Web_Back_Helper_Respond {
152
163
  return !res.headersSent && !res.writableEnded;
153
164
  };
154
165
  }
155
- }
166
+ }
@@ -0,0 +1,57 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * Simple logger implementation that delegates to the native console.
5
+ */
6
+ export default class Fl32_Web_Back_Logger {
7
+ constructor() {
8
+ /**
9
+ * Logs an error message.
10
+ * @param {...any} args - The error message or data.
11
+ */
12
+ this.error = function (...args) {
13
+ console.error('[ERROR]', ...args);
14
+ };
15
+
16
+ /**
17
+ * Logs a warning message.
18
+ * @param {...any} args - The warning message or data.
19
+ */
20
+ this.warn = function (...args) {
21
+ console.warn('[WARN]', ...args);
22
+ };
23
+
24
+ /**
25
+ * Logs an informational message.
26
+ * @param {...any} args - The informational message or data.
27
+ */
28
+ this.info = function (...args) {
29
+ console.info('[INFO]', ...args);
30
+ };
31
+
32
+ /**
33
+ * Logs a debug message.
34
+ * @param {...any} args - The debug message or data.
35
+ */
36
+ this.debug = function (...args) {
37
+ console.debug('[DEBUG]', ...args);
38
+ };
39
+
40
+ /**
41
+ * Logs a trace message.
42
+ * @param {...any} args - The trace message or data.
43
+ */
44
+ this.trace = function (...args) {
45
+ console.trace('[TRACE]', ...args);
46
+ };
47
+
48
+ /**
49
+ * Logs an exception with optional additional context.
50
+ * @param {Error} exception - The exception to log.
51
+ * @param {...any} context - Additional context or metadata.
52
+ */
53
+ this.exception = function (exception, ...context) {
54
+ console.error('[EXCEPTION]', exception.stack || exception.toString(), ...context);
55
+ };
56
+ }
57
+ }
@@ -0,0 +1,228 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * Pipeline Engine is the single request-lifecycle coordination component.
5
+ * It executes handlers in three deterministic stages:
6
+ * `INIT -> PROCESS -> FINALIZE`.
7
+ */
8
+ export const __deps__ = Object.freeze({
9
+ logger: 'Fl32_Web_Back_Logger$',
10
+ respond: 'Fl32_Web_Back_Helper_Respond$',
11
+ helpOrder: 'Fl32_Web_Back_Helper_Order_Kahn$',
12
+ STAGE: 'Fl32_Web_Back_Enum_Stage$',
13
+ });
14
+
15
+ /**
16
+ * @typedef {object} Fl32_Web_Back_PipelineEngineConstructorParams
17
+ * @property {Fl32_Web_Back_Logger} logger
18
+ * @property {Fl32_Web_Back_Helper_Respond} respond
19
+ * @property {Fl32_Web_Back_Helper_Order_Kahn} helpOrder
20
+ * @property {Fl32_Web_Back_Enum_Stage} STAGE
21
+ */
22
+
23
+ /**
24
+ * @typedef {object} Fl32_Web_Back_PipelineEngine_RequestContext
25
+ * @property {module:http.IncomingMessage|module:http2.Http2ServerRequest} request
26
+ * @property {module:http.ServerResponse|module:http2.Http2ServerResponse} response
27
+ * @property {Record<string, unknown>} data
28
+ * @property {boolean} completed
29
+ * @property {() => void} complete
30
+ * @property {() => boolean} isCompleted
31
+ */
32
+
33
+ const KEY_STAGE = Symbol('stage');
34
+
35
+ export default class Fl32_Web_Back_PipelineEngine {
36
+ /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
37
+ /**
38
+ * @param {Fl32_Web_Back_PipelineEngineConstructorParams} params
39
+ */
40
+ constructor(
41
+ {
42
+ logger,
43
+ respond,
44
+ helpOrder,
45
+ STAGE,
46
+ }
47
+ ) {
48
+ /* eslint-enable jsdoc/require-param-description,jsdoc/check-param-names */
49
+ /** @type {Map<string, Fl32_Web_Back_Api_Handler>} */
50
+ const handlers = new Map();
51
+ /** @type {Fl32_Web_Back_Api_Handler[]} */
52
+ let initHandlers = [];
53
+ /** @type {Fl32_Web_Back_Api_Handler[]} */
54
+ let processHandlers = [];
55
+ /** @type {Fl32_Web_Back_Api_Handler[]} */
56
+ let finalizeHandlers = [];
57
+ let isLocked = false;
58
+
59
+ /**
60
+ * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} request
61
+ * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} response
62
+ * @returns {Fl32_Web_Back_PipelineEngine_RequestContext}
63
+ */
64
+ function createRequestContext(request, response) {
65
+ let completed = false;
66
+ /** @type {Fl32_Web_Back_PipelineEngine_RequestContext & {[KEY_STAGE]: string|null}} */
67
+ const context = {
68
+ request,
69
+ response,
70
+ data: {},
71
+ completed: false,
72
+ complete: () => {
73
+ context.completed = true;
74
+ },
75
+ isCompleted: () => completed,
76
+ [KEY_STAGE]: null,
77
+ };
78
+
79
+ Object.defineProperty(context, 'completed', {
80
+ configurable: false,
81
+ enumerable: true,
82
+ get() {
83
+ return completed;
84
+ },
85
+ set(value) {
86
+ if (value !== true && value !== false) {
87
+ throw new Error('Request completion flag accepts only boolean values');
88
+ }
89
+ if (value === false && completed) {
90
+ throw new Error('Request completion flag cannot be reset');
91
+ }
92
+ if (value === true && !completed) {
93
+ if (context[KEY_STAGE] !== STAGE.PROCESS) {
94
+ throw new Error('Only PROCESS handlers may complete request processing');
95
+ }
96
+ completed = true;
97
+ }
98
+ },
99
+ });
100
+
101
+ return context;
102
+ }
103
+
104
+ /**
105
+ * @param {Fl32_Web_Back_Api_Handler} handler
106
+ * @param {string} stage
107
+ * @param {Fl32_Web_Back_PipelineEngine_RequestContext & {[KEY_STAGE]: string|null}} context
108
+ * @returns {Promise<void>}
109
+ */
110
+ async function runHandler(handler, stage, context) {
111
+ context[KEY_STAGE] = stage;
112
+ await handler.handle(context);
113
+ }
114
+
115
+ /**
116
+ * @returns {void}
117
+ */
118
+ this.orderHandlers = function () {
119
+ const init = [];
120
+ const process = [];
121
+ const finalize = [];
122
+
123
+ for (const handler of handlers.values()) {
124
+ const info = handler.getRegistrationInfo();
125
+ if (info.stage === STAGE.INIT) {
126
+ init.push(handler);
127
+ } else if (info.stage === STAGE.PROCESS) {
128
+ process.push(handler);
129
+ } else if (info.stage === STAGE.FINALIZE) {
130
+ finalize.push(handler);
131
+ } else {
132
+ throw new Error(`Unsupported handler stage '${String(info.stage)}'`);
133
+ }
134
+ }
135
+
136
+ initHandlers = helpOrder.sort(init);
137
+ processHandlers = helpOrder.sort(process);
138
+ finalizeHandlers = helpOrder.sort(finalize);
139
+ isLocked = true;
140
+ };
141
+
142
+ /**
143
+ * @returns {void}
144
+ */
145
+ this.lockHandlers = () => this.orderHandlers();
146
+
147
+ /**
148
+ * @param {Fl32_Web_Back_Api_Handler} handler
149
+ * @returns {void}
150
+ */
151
+ this.addHandler = function (handler) {
152
+ if (isLocked) {
153
+ throw new Error('Handler registration is locked after pipeline ordering');
154
+ }
155
+ const info = handler.getRegistrationInfo();
156
+ if (!info?.name) {
157
+ throw new Error('Handler registration requires a non-empty name');
158
+ }
159
+ handlers.set(info.name, handler);
160
+ };
161
+
162
+ /**
163
+ * @param {Fl32_Web_Back_Api_Handler} handler
164
+ * @returns {void}
165
+ */
166
+ this.registerHandler = (handler) => this.addHandler(handler);
167
+
168
+ /**
169
+ * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} req
170
+ * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} res
171
+ * @returns {Promise<void>}
172
+ */
173
+ this.onEventRequest = async function (req, res) {
174
+ if (!isLocked) {
175
+ this.orderHandlers();
176
+ }
177
+ /** @type {Fl32_Web_Back_PipelineEngine_RequestContext & {[KEY_STAGE]: string|null}} */
178
+ const context = createRequestContext(req, res);
179
+
180
+ try {
181
+ for (const handler of initHandlers) {
182
+ try {
183
+ await runHandler(handler, STAGE.INIT, context);
184
+ } catch (error) {
185
+ logger.exception(error);
186
+ }
187
+ }
188
+
189
+ for (const handler of processHandlers) {
190
+ if (context.isCompleted()) {
191
+ break;
192
+ }
193
+ try {
194
+ await runHandler(handler, STAGE.PROCESS, context);
195
+ } catch (error) {
196
+ logger.exception(error);
197
+ if (respond.isWritable(res)) {
198
+ respond.code500_InternalServerError({res, body: 'Internal Server Error'});
199
+ }
200
+ context.completed = true;
201
+ break;
202
+ }
203
+ }
204
+
205
+ if (!context.isCompleted() && respond.isWritable(res)) {
206
+ logger.error(`404 Not Found: ${req.url}`);
207
+ respond.code404_NotFound({res});
208
+ }
209
+ } finally {
210
+ for (const handler of finalizeHandlers) {
211
+ try {
212
+ await runHandler(handler, STAGE.FINALIZE, context);
213
+ } catch (error) {
214
+ logger.exception(error);
215
+ }
216
+ }
217
+ context[KEY_STAGE] = null;
218
+ }
219
+ };
220
+
221
+ /**
222
+ * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} req
223
+ * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} res
224
+ * @returns {Promise<void>}
225
+ */
226
+ this.handleRequest = async (req, res) => this.onEventRequest(req, res);
227
+ }
228
+ }
@@ -1,55 +1,57 @@
1
+ // @ts-check
2
+
3
+ export const __deps__ = Object.freeze({
4
+ cast: 'Fl32_Web_Back_Helper_Cast$',
5
+ });
6
+
1
7
  /**
2
- * Factory for TLS configuration DTO.
3
- * Produces validated DTOs for HTTPS server configuration.
8
+ * @typedef {object} Fl32_Web_Back_Server_Config_TlsFactoryParams
9
+ * @property {Fl32_Web_Back_Helper_Cast} cast
4
10
  */
11
+
5
12
  export default class Fl32_Web_Back_Server_Config_Tls {
13
+ /**
14
+ * Trusted CA certificates in PEM format.
15
+ * @type {string|undefined}
16
+ */
17
+ ca;
18
+
19
+ /**
20
+ * Certificate in PEM format.
21
+ * @type {string}
22
+ */
23
+ cert;
24
+
25
+ /**
26
+ * Private key in PEM format.
27
+ * @type {string}
28
+ */
29
+ key;
30
+ }
31
+
32
+ export class Factory {
6
33
  /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
7
34
  /**
8
- * @param {Fl32_Web_Back_Helper_Cast} cast
35
+ * @param {Fl32_Web_Back_Server_Config_TlsFactoryParams} params
9
36
  */
10
37
  constructor(
11
38
  {
12
- Fl32_Web_Back_Helper_Cast$: cast,
39
+ cast,
13
40
  }
14
41
  ) {
15
42
  /* eslint-enable jsdoc/require-param-description,jsdoc/check-param-names */
16
43
  /**
17
- * Create a validated DTO for TLS configuration.
18
- *
19
- * @param {*} [data] - Optional raw object.
20
- * @returns {Dto}
44
+ * @param {*} [data]
45
+ * @returns {Fl32_Web_Back_Server_Config_Tls}
21
46
  */
22
47
  this.create = function (data) {
23
- const res = Object.assign(new Dto(), data);
48
+ const res = new Fl32_Web_Back_Server_Config_Tls();
24
49
  if (data) {
25
50
  res.ca = cast.string(data?.ca);
26
51
  res.cert = cast.string(data.cert);
27
52
  res.key = cast.string(data.key);
28
53
  }
29
- return res;
54
+ return Object.freeze(res);
30
55
  };
31
56
  }
32
57
  }
33
-
34
- /**
35
- * @memberOf Fl32_Web_Back_Server_Config_Tls
36
- */
37
- class Dto {
38
- /**
39
- * Trusted CA certificates in PEM format.
40
- * @type {string|undefined}
41
- */
42
- ca;
43
-
44
- /**
45
- * Certificate in PEM format.
46
- * @type {string}
47
- */
48
- cert;
49
-
50
- /**
51
- * Private key in PEM format.
52
- * @type {string}
53
- */
54
- key;
55
- }