@flancer32/teq-web 0.1.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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Enum for server types used to configure built-in web server.
3
+ * - 'http': HTTP/1.1
4
+ * - 'http2': HTTP/2 without TLS (cleartext)
5
+ * - 'https': HTTP/2 over TLS (via http2.createSecureServer)
6
+ */
7
+ const Fl32_Web_Back_Enum_Server_Type = {
8
+ HTTP2: 'http2',
9
+ HTTP: 'http',
10
+ HTTPS: 'https'
11
+ };
12
+ export default Fl32_Web_Back_Enum_Server_Type;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Enum for web request processing stages in this plugin.
3
+ * Used to define processing phases in the web dispatcher specific to this plugin.
4
+ */
5
+ const Fl32_Web_Back_Enum_Stage = {
6
+ PRE: 'pre', // Pre-processing stage: initial request handling (e.g., logging, authentication)
7
+ PROCESS: 'process', // Main processing stage: routing and core logic
8
+ POST: 'post' // Post-processing stage: final actions (e.g., logging response, cleanup)
9
+ };
10
+ export default Fl32_Web_Back_Enum_Stage;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Logs basic request information at the beginning of the request lifecycle.
3
+ * @implements Fl32_Web_Back_Api_Handler
4
+ */
5
+ export default class Fl32_Web_Back_Handler_Pre_Log {
6
+ /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
7
+ /**
8
+ * @param {Fl32_Web_Back_Logger} logger
9
+ * @param {Fl32_Web_Back_Dto_Handler_Info} dtoInfo
10
+ * @param {typeof Fl32_Web_Back_Enum_Stage} STAGE
11
+ */
12
+ constructor(
13
+ {
14
+ Fl32_Web_Back_Logger$: logger,
15
+ Fl32_Web_Back_Dto_Handler_Info$: dtoInfo,
16
+ Fl32_Web_Back_Enum_Stage$: STAGE,
17
+ }
18
+ ) {
19
+ /* eslint-enable jsdoc/check-param-names */
20
+ // VARS
21
+ const _info = dtoInfo.create();
22
+ _info.name = this.constructor.name;
23
+ _info.stage = STAGE.PRE;
24
+ Object.freeze(_info);
25
+
26
+ // MAIN
27
+
28
+ /**
29
+ * Log request method and URL.
30
+ *
31
+ * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} req
32
+ * @returns {Promise<void>}
33
+ */
34
+ this.handle = async function (req) {
35
+ logger.debug(`${req.method} ${req.url}`);
36
+ };
37
+
38
+ /**
39
+ * Return handler registration info.
40
+ *
41
+ * @returns {Fl32_Web_Back_Dto_Handler_Info.Dto}
42
+ */
43
+ this.getRegistrationInfo = () => _info;
44
+ }
45
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Serves static files from a configured root directory.
3
+ * Prevents directory traversal and streams file content to the response.
4
+ *
5
+ * @implements Fl32_Web_Back_Api_Handler
6
+ */
7
+ export default class Fl32_Web_Back_Handler_Static {
8
+ /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
9
+ /**
10
+ * @param {typeof import('node:fs')} fs - Node.js file system module.
11
+ * @param {typeof import('node:http2')} http2
12
+ * @param {typeof import('node:path')} path - Node.js path module.
13
+ * @param {Fl32_Web_Back_Logger} logger - Logger instance.
14
+ * @param {Fl32_Web_Back_Helper_Mime} helpMime - MIME helper for content type resolution.
15
+ * @param {Fl32_Web_Back_Helper_Respond} respond - Response helper with status utilities.
16
+ * @param {Fl32_Web_Back_Dto_Handler_Info} dtoInfo - DTO factory for handler registration.
17
+ * @param {typeof Fl32_Web_Back_Enum_Stage} STAGE - Enum of handler stages.
18
+ */
19
+ constructor(
20
+ {
21
+ 'node:fs': fs,
22
+ 'node:http2': http2,
23
+ 'node:path': path,
24
+ Fl32_Web_Back_Logger$: logger,
25
+ Fl32_Web_Back_Helper_Mime$: helpMime,
26
+ Fl32_Web_Back_Helper_Respond$: respond,
27
+ Fl32_Web_Back_Dto_Handler_Info$: dtoInfo,
28
+ Fl32_Web_Back_Enum_Stage$: STAGE,
29
+ }
30
+ ) {
31
+ /* eslint-enable jsdoc/check-param-names */
32
+ // VARS
33
+ const {promises: fsp} = fs;
34
+ const {constants: H2} = http2;
35
+ const {
36
+ HTTP2_HEADER_CONTENT_LENGTH,
37
+ HTTP2_HEADER_CONTENT_TYPE,
38
+ HTTP2_HEADER_LAST_MODIFIED,
39
+ HTTP_STATUS_OK,
40
+ } = H2;
41
+
42
+ /**
43
+ * Handler registration info.
44
+ * @type {Fl32_Web_Back_Dto_Handler_Info.Dto}
45
+ */
46
+ const _info = dtoInfo.create();
47
+ _info.name = this.constructor.name;
48
+ _info.stage = STAGE.PROCESS;
49
+ Object.freeze(_info);
50
+
51
+ /**
52
+ * Root directory for static files.
53
+ * @type {string}
54
+ */
55
+ let _root;
56
+
57
+ /**
58
+ * Default filenames to try when a path is a directory.
59
+ * @type {string[]}
60
+ */
61
+ const _defaultFiles = ['index.html', 'index.htm', 'index.txt'];
62
+
63
+
64
+ /**
65
+ * Handles the incoming request by attempting to serve a static file.
66
+ *
67
+ * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} req - HTTP request object.
68
+ * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} res - HTTP response object.
69
+ * @returns {Promise<boolean>} - True if the file was served, false otherwise.
70
+ */
71
+ this.handle = async function (req, res) {
72
+ if (!respond.isWritable(res)) return false;
73
+
74
+ try {
75
+ const urlPath = decodeURIComponent(req.url.split('?')[0]);
76
+ let fsPath = path.resolve(_root, '.' + urlPath);
77
+
78
+ if (!fsPath.startsWith(_root)) return false;
79
+
80
+ let stat;
81
+ try {
82
+ stat = await fsp.stat(fsPath);
83
+ } catch {
84
+ return false;
85
+ }
86
+
87
+ // If a path is a directory — try default files
88
+ if (stat.isDirectory()) {
89
+ for (const file of _defaultFiles) {
90
+ const candidate = path.join(fsPath, file);
91
+ try {
92
+ const s = await fsp.stat(candidate);
93
+ if (s.isFile()) {
94
+ fsPath = candidate;
95
+ stat = s;
96
+ break;
97
+ }
98
+ } catch {
99
+ // ignore and continue
100
+ }
101
+ }
102
+ if (!stat.isFile()) return false;
103
+ }
104
+
105
+ const stream = fs.createReadStream(fsPath);
106
+ const ext = path.extname(fsPath).toLowerCase();
107
+ const headers = {
108
+ [HTTP2_HEADER_CONTENT_LENGTH]: stat.size,
109
+ [HTTP2_HEADER_CONTENT_TYPE]: helpMime.getByExt(ext),
110
+ [HTTP2_HEADER_LAST_MODIFIED]: stat.mtime.toUTCString(),
111
+ };
112
+ res.writeHead(HTTP_STATUS_OK, headers);
113
+ stream.pipe(res);
114
+ return true;
115
+ } catch (e) {
116
+ logger.exception(e);
117
+ return false;
118
+ }
119
+ };
120
+
121
+ /**
122
+ * Initializes the handler with the root directory.
123
+ *
124
+ * @param {object} params
125
+ * @param {string} params.rootPath - Absolute or relative path to the static root directory.
126
+ * @returns {Promise<void>}
127
+ */
128
+ this.init = async function ({rootPath}) {
129
+ _root = path.resolve(rootPath);
130
+ logger.info(`Static files root: ${_root}`);
131
+ };
132
+
133
+ /**
134
+ * Returns the handler registration info.
135
+ * @returns {Fl32_Web_Back_Dto_Handler_Info.Dto}
136
+ */
137
+ this.getRegistrationInfo = () => _info;
138
+ }
139
+ }
@@ -0,0 +1,86 @@
1
+ export default class Fl32_Web_Back_Helper_Cast {
2
+
3
+ /**
4
+ * Cast input data into an array. Ensures the result is always an array.
5
+ * Optionally casts each item using the provided itemCast function.
6
+ *
7
+ * @param {*} data - Input data to be cast to array.
8
+ * @param {function(*): *} [itemCast] - Optional function to cast each item.
9
+ * @returns {Array}
10
+ */
11
+ array(data, itemCast) {
12
+ let arr = [];
13
+
14
+ if (Array.isArray(data)) {
15
+ arr = data;
16
+ } else if (data !== null) {
17
+ arr = [data];
18
+ }
19
+
20
+ return (typeof itemCast === 'function')
21
+ ? arr.map(itemCast).filter(v => v !== undefined)
22
+ : arr;
23
+ }
24
+
25
+
26
+ /**
27
+ * Cast input data into decimal 'number' data type.
28
+ * @param {*} data
29
+ * @returns {number|undefined}
30
+ */
31
+ decimal(data) {
32
+ const res = Number.parseFloat(data);
33
+ return ((typeof res === 'number') && (!isNaN(res))) ? res : undefined;
34
+ }
35
+
36
+ /**
37
+ * Cast input data into a valid enumeration value.
38
+ * Supports case normalization (upper/lower).
39
+ * If both `upper` and `lower` are true, `upper` takes precedence.
40
+ *
41
+ * @param {*} data - The input to cast.
42
+ * @param {object} enu - Object whose values represent valid enum values.
43
+ * @param {object} [params] - Parameters object.
44
+ * @param {boolean} [params.lower] - Normalize input to lower case before comparison.
45
+ * @param {boolean} [params.upper] - Normalize input to upper case before comparison.
46
+ * @returns {string|undefined}
47
+ */
48
+ enum(data, enu, {lower, upper} = {}) {
49
+ let norm = data;
50
+
51
+ if (typeof data === 'string') {
52
+ if (upper) norm = data.toUpperCase();
53
+ else if (lower) norm = data.toLowerCase();
54
+ }
55
+
56
+ const values = Object.values(enu);
57
+ return values.includes(norm) ? norm : undefined;
58
+ }
59
+
60
+ /**
61
+ * Cast input data into integer 'number' data type.
62
+ * @param {*} data - Input data to be cast to integer.
63
+ * @returns {number|undefined}
64
+ */
65
+ int(data) {
66
+ const norm = (typeof data === 'string') ? data.trim() : data;
67
+ const res = Number.parseInt(norm);
68
+ return ((typeof res === 'number') && (!isNaN(res))) ? res : undefined;
69
+ }
70
+
71
+ /**
72
+ * Cast input data into 'string' data type.
73
+ * @param {*} data - Input data to be cast to string.
74
+ * @returns {string|undefined}
75
+ */
76
+ string(data) {
77
+ if (typeof data === 'string') {
78
+ return data;
79
+ } else if (typeof data === 'number') {
80
+ return String(data);
81
+ } else if (typeof data === 'boolean') {
82
+ return (data) ? 'true' : 'false';
83
+ }
84
+ return undefined;
85
+ }
86
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * MIME type helper with built-in mapping for common file extensions.
3
+ * Can be replaced or extended by the application via the DI container.
4
+ */
5
+ export default class Fl32_Web_Back_Helper_Mime {
6
+ constructor() {
7
+ /**
8
+ * Mapping from file extension to MIME type.
9
+ * Keys must start with a dot, e.g. '.html'.
10
+ * @type {{[key: string]: string}}
11
+ */
12
+ const _types = Object.freeze({
13
+ '.aac': 'audio/aac',
14
+ '.abw': 'application/x-abiword',
15
+ '.avi': 'video/x-msvideo',
16
+ '.bmp': 'image/bmp',
17
+ '.bz': 'application/x-bzip',
18
+ '.bz2': 'application/x-bzip2',
19
+ '.css': 'text/css',
20
+ '.csv': 'text/csv',
21
+ '.doc': 'application/msword',
22
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
23
+ '.eot': 'application/vnd.ms-fontobject',
24
+ '.epub': 'application/epub+zip',
25
+ '.gz': 'application/gzip',
26
+ '.gif': 'image/gif',
27
+ '.htm': 'text/html',
28
+ '.html': 'text/html',
29
+ '.ico': 'image/vnd.microsoft.icon',
30
+ '.ics': 'text/calendar',
31
+ '.jar': 'application/java-archive',
32
+ '.jpeg': 'image/jpeg',
33
+ '.jpg': 'image/jpeg',
34
+ '.js': 'application/javascript',
35
+ '.json': 'application/json',
36
+ '.mid': 'audio/midi',
37
+ '.midi': 'audio/midi',
38
+ '.mjs': 'application/javascript',
39
+ '.mp3': 'audio/mpeg',
40
+ '.mp4': 'video/mp4',
41
+ '.mpeg': 'video/mpeg',
42
+ '.mpkg': 'application/vnd.apple.installer+xml',
43
+ '.odp': 'application/vnd.oasis.opendocument.presentation',
44
+ '.ods': 'application/vnd.oasis.opendocument.spreadsheet',
45
+ '.odt': 'application/vnd.oasis.opendocument.text',
46
+ '.oga': 'audio/ogg',
47
+ '.ogv': 'video/ogg',
48
+ '.ogx': 'application/ogg',
49
+ '.otf': 'font/otf',
50
+ '.png': 'image/png',
51
+ '.pdf': 'application/pdf',
52
+ '.ppt': 'application/vnd.ms-powerpoint',
53
+ '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
54
+ '.rar': 'application/x-rar-compressed',
55
+ '.rtf': 'application/rtf',
56
+ '.sh': 'application/x-sh',
57
+ '.svg': 'image/svg+xml',
58
+ '.swf': 'application/x-shockwave-flash',
59
+ '.tar': 'application/x-tar',
60
+ '.tif': 'image/tiff',
61
+ '.tiff': 'image/tiff',
62
+ '.ts': 'video/mp2t',
63
+ '.ttf': 'font/ttf',
64
+ '.txt': 'text/plain',
65
+ '.vsd': 'application/vnd.visio',
66
+ '.wav': 'audio/wav',
67
+ '.weba': 'audio/webm',
68
+ '.webm': 'video/webm',
69
+ '.webp': 'image/webp',
70
+ '.woff': 'font/woff',
71
+ '.woff2': 'font/woff2',
72
+ '.xhtml': 'application/xhtml+xml',
73
+ '.xls': 'application/vnd.ms-excel',
74
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
75
+ '.xml': 'application/xml',
76
+ '.zip': 'application/zip',
77
+ '.7z': 'application/x-7z-compressed',
78
+ });
79
+
80
+ /**
81
+ * Returns the MIME type for the given extension.
82
+ *
83
+ * @param {string} ext - File extension including leading dot (e.g. '.html').
84
+ * @returns {string} MIME type if known, otherwise 'application/octet-stream'.
85
+ */
86
+ this.getByExt = function (ext) {
87
+ return _types[ext.toLowerCase()] || 'application/octet-stream';
88
+ };
89
+ }
90
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Sorts named handlers by relative `before` / `after` constraints using Kahn's algorithm.
3
+ */
4
+ export default class Fl32_Web_Back_Helper_Order_Kahn {
5
+
6
+ /**
7
+ * Topologically sorts handlers with `name`, `before`, `after` fields.
8
+ *
9
+ * @param {Fl32_Web_Back_Api_Handler[]} handlers - Handlers to sort.
10
+ * @returns {Fl32_Web_Back_Api_Handler[]} - Sorted list.
11
+ * @throws {Error} - If circular dependency is detected.
12
+ */
13
+ sort(handlers) {
14
+ const nameToHandler = new Map();
15
+ const graph = new Map(); // name => Set of downstream nodes
16
+ const inDegree = new Map(); // name => number of incoming edges
17
+
18
+ // Initialize maps
19
+ for (const h of handlers) {
20
+ const info = h.getRegistrationInfo();
21
+ const name = info.name;
22
+ nameToHandler.set(name, h);
23
+ graph.set(name, new Set());
24
+ inDegree.set(name, 0);
25
+ }
26
+
27
+ // Build graph
28
+ for (const h of handlers) {
29
+ const {name, after = [], before = []} = h.getRegistrationInfo();
30
+
31
+ for (const dep of after) {
32
+ if (!graph.has(dep)) continue;
33
+ graph.get(dep).add(name);
34
+ inDegree.set(name, inDegree.get(name) + 1);
35
+ }
36
+
37
+ for (const dep of before) {
38
+ if (!graph.has(dep)) continue;
39
+ graph.get(name).add(dep);
40
+ inDegree.set(dep, inDegree.get(dep) + 1);
41
+ }
42
+ }
43
+
44
+ // Kahn's algorithm
45
+ const queue = [];
46
+ for (const [name, count] of inDegree.entries()) {
47
+ if (count === 0) queue.push(name);
48
+ }
49
+
50
+ const sorted = [];
51
+ while (queue.length > 0) {
52
+ const name = queue.shift();
53
+ sorted.push(nameToHandler.get(name));
54
+ for (const neighbor of graph.get(name)) {
55
+ inDegree.set(neighbor, inDegree.get(neighbor) - 1);
56
+ if (inDegree.get(neighbor) === 0) queue.push(neighbor);
57
+ }
58
+ }
59
+
60
+ if (sorted.length !== handlers.length) {
61
+ throw new Error('Circular dependency detected among handlers');
62
+ }
63
+
64
+ return sorted;
65
+ }
66
+ }
@@ -0,0 +1,78 @@
1
+ /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
2
+ export default class Fl32_Web_Back_Helper_Respond {
3
+ /**
4
+ * @param {typeof import('node:http2')} http2
5
+ */
6
+ constructor(
7
+ {
8
+ 'node:http2': http2,
9
+ }
10
+ ) {
11
+ // VARS
12
+ const {constants: H2} = http2;
13
+ const {
14
+ HTTP2_HEADER_ALLOW,
15
+ HTTP_STATUS_BAD_GATEWAY,
16
+ HTTP_STATUS_BAD_REQUEST,
17
+ HTTP_STATUS_CONFLICT,
18
+ HTTP_STATUS_CREATED,
19
+ HTTP_STATUS_FORBIDDEN,
20
+ HTTP_STATUS_FOUND,
21
+ HTTP_STATUS_INTERNAL_SERVER_ERROR,
22
+ HTTP_STATUS_METHOD_NOT_ALLOWED,
23
+ HTTP_STATUS_MOVED_PERMANENTLY,
24
+ HTTP_STATUS_NOT_FOUND,
25
+ HTTP_STATUS_NOT_MODIFIED,
26
+ HTTP_STATUS_NO_CONTENT,
27
+ HTTP_STATUS_OK,
28
+ HTTP_STATUS_PAYMENT_REQUIRED,
29
+ HTTP_STATUS_SEE_OTHER,
30
+ HTTP_STATUS_SERVICE_UNAVAILABLE,
31
+ HTTP_STATUS_UNAUTHORIZED,
32
+ } = H2;
33
+
34
+ // FUNC
35
+ /**
36
+ * Sends an HTTP response with a given status code.
37
+ *
38
+ * @param {object} params
39
+ * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} params.res - HTTP response object.
40
+ * @param {{[key: string]: string}} [params.headers={}] - Custom headers.
41
+ * @param {string|object} [params.body=''] - Response body.
42
+ * @param {number} status - HTTP status code.
43
+ * @returns {boolean} - `true` if response was sent, `false` if headers were already sent.
44
+ */
45
+ function send({res, headers = {}, body = ''}, status) {
46
+ if (res.headersSent || res.writableEnded) return false;
47
+ res.writeHead(status, headers);
48
+ res.end(typeof body === 'string' ? body : JSON.stringify(body));
49
+ return true;
50
+ }
51
+
52
+ // MAIN
53
+
54
+ /** @see send */
55
+ this.code200_Ok = function ({res, headers = {}, body = ''}) {
56
+ return send({res, headers, body}, HTTP_STATUS_OK);
57
+ };
58
+
59
+ /** @see send */
60
+ this.code404_NotFound = function ({res, headers = {}, body = ''}) {
61
+ return send({res, headers, body}, HTTP_STATUS_NOT_FOUND);
62
+ };
63
+
64
+ /** @see send */
65
+ this.code500_InternalServerError = function ({res, headers = {}, body = 'Internal Server Error'}) {
66
+ return send({res, headers, body}, HTTP_STATUS_INTERNAL_SERVER_ERROR);
67
+ };
68
+
69
+ /**
70
+ * Checks if the response is writable and not yet sent.
71
+ * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} res
72
+ * @returns {boolean}
73
+ */
74
+ this.isWritable = function (res) {
75
+ return !res.headersSent && !res.writableEnded;
76
+ };
77
+ }
78
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Simple logger implementation that delegates to the native console.
3
+ */
4
+ export default class Fl32_Web_Back_Logger {
5
+ /**
6
+ * Logs an error message.
7
+ * @param {...any} args - The error message or data.
8
+ */
9
+ error(...args) {
10
+ console.error('[ERROR]', ...args);
11
+ }
12
+
13
+ /**
14
+ * Logs a warning message.
15
+ * @param {...any} args - The warning message or data.
16
+ */
17
+ warn(...args) {
18
+ console.warn('[WARN]', ...args);
19
+ }
20
+
21
+ /**
22
+ * Logs an informational message.
23
+ * @param {...any} args - The informational message or data.
24
+ */
25
+ info(...args) {
26
+ console.info('[INFO]', ...args);
27
+ }
28
+
29
+ /**
30
+ * Logs a debug message.
31
+ * @param {...any} args - The debug message or data.
32
+ */
33
+ debug(...args) {
34
+ console.debug('[DEBUG]', ...args);
35
+ }
36
+
37
+ /**
38
+ * Logs a trace message.
39
+ * @param {...any} args - The trace message or data.
40
+ */
41
+ trace(...args) {
42
+ console.trace('[TRACE]', ...args);
43
+ }
44
+
45
+ /**
46
+ * Logs an exception with optional additional context.
47
+ * @param {Error} exception - The exception to log.
48
+ * @param {...any} context - Additional context or metadata.
49
+ */
50
+ exception(exception, ...context) {
51
+ console.error('[EXCEPTION]', exception.stack || exception.toString(), ...context);
52
+ }
53
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Factory for TLS configuration DTO.
3
+ * Produces validated DTOs for HTTPS server configuration.
4
+ */
5
+ export default class Fl32_Web_Back_Server_Config_Tls {
6
+ /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
7
+ /**
8
+ * @param {Fl32_Web_Back_Helper_Cast} cast
9
+ */
10
+ constructor(
11
+ {
12
+ Fl32_Web_Back_Helper_Cast$: cast,
13
+ }
14
+ ) {
15
+ /* eslint-enable jsdoc/require-param-description,jsdoc/check-param-names */
16
+ /**
17
+ * Create a validated DTO for TLS configuration.
18
+ *
19
+ * @param {*} [data] - Optional raw object.
20
+ * @returns {Dto}
21
+ */
22
+ this.create = function (data) {
23
+ const res = Object.assign(new Dto(), data);
24
+ if (data) {
25
+ res.ca = cast.string(data?.ca);
26
+ res.cert = cast.string(data.cert);
27
+ res.key = cast.string(data.key);
28
+ }
29
+ return res;
30
+ };
31
+ }
32
+ }
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
+ }