@underpostnet/underpost 2.99.1 → 2.99.5

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 (42) hide show
  1. package/.env.development +0 -3
  2. package/.env.production +1 -3
  3. package/.env.test +0 -3
  4. package/LICENSE +1 -1
  5. package/README.md +30 -30
  6. package/baremetal/commission-workflows.json +52 -0
  7. package/bin/deploy.js +101 -47
  8. package/cli.md +47 -43
  9. package/examples/static-page/README.md +55 -378
  10. package/examples/static-page/ssr-components/CustomPage.js +1 -13
  11. package/jsconfig.json +4 -2
  12. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  13. package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
  14. package/manifests/deployment/playwright/deployment.yaml +52 -0
  15. package/package.json +2 -2
  16. package/scripts/disk-devices.sh +13 -0
  17. package/scripts/rocky-pwa.sh +2 -2
  18. package/scripts/ssl.sh +12 -6
  19. package/src/api/user/user.model.js +1 -0
  20. package/src/cli/baremetal.js +576 -176
  21. package/src/cli/cloud-init.js +97 -79
  22. package/src/cli/deploy.js +6 -24
  23. package/src/cli/env.js +4 -1
  24. package/src/cli/image.js +7 -40
  25. package/src/cli/index.js +37 -7
  26. package/src/cli/repository.js +3 -1
  27. package/src/cli/run.js +109 -92
  28. package/src/cli/secrets.js +0 -34
  29. package/src/cli/static.js +0 -26
  30. package/src/cli/test.js +13 -1
  31. package/src/client/components/core/Polyhedron.js +896 -7
  32. package/src/client/components/core/Translate.js +4 -0
  33. package/src/client/services/default/default.management.js +12 -2
  34. package/src/index.js +27 -1
  35. package/src/runtime/express/Express.js +3 -3
  36. package/src/server/conf.js +6 -4
  37. package/src/server/logger.js +33 -31
  38. package/src/server/process.js +27 -2
  39. package/src/server/proxy.js +4 -6
  40. package/src/server/tls.js +30 -25
  41. package/examples/static-page/QUICK-REFERENCE.md +0 -481
  42. package/examples/static-page/STATIC-GENERATOR-GUIDE.md +0 -757
@@ -687,6 +687,10 @@ const TranslateCore = {
687
687
  en: 'Markdown source copied to clipboard',
688
688
  es: 'Fuente de Markdown copiada al portapapeles',
689
689
  };
690
+ Translate.Data['success-clear-filter'] = {
691
+ en: 'Filter cleared successfully',
692
+ es: 'Filtro limpiado con éxito',
693
+ };
690
694
  },
691
695
  };
692
696
 
@@ -39,9 +39,19 @@ const DefaultOptions = {
39
39
  const columnDefFormatter = (obj, columnDefs, customFormat) => {
40
40
  for (const colDef of columnDefs)
41
41
  switch (colDef.cellDataType) {
42
- case 'date':
43
- obj[colDef.field] = obj[colDef.field] ? new Date(obj[colDef.field]) : new Date();
42
+ case 'date': {
43
+ const value = obj[colDef.field];
44
+
45
+ // Do NOT default missing/blank dates to "now" — render as empty instead.
46
+ if (value === null || value === undefined || value === '') {
47
+ obj[colDef.field] = null;
48
+ break;
49
+ }
50
+
51
+ const date = new Date(value);
52
+ obj[colDef.field] = isNaN(date.getTime()) ? null : date;
44
53
  break;
54
+ }
45
55
  case 'boolean':
46
56
  if (obj[colDef.field] !== true && obj[colDef.field] !== false) obj[colDef.field] = false;
47
57
  default:
package/src/index.js CHANGED
@@ -25,6 +25,7 @@ import UnderpostDns from './server/dns.js';
25
25
  import UnderpostBackup from './server/backup.js';
26
26
  import UnderpostCron from './server/cron.js';
27
27
  import UnderpostStartUp from './server/start.js';
28
+ import UnderpostTLS from './server/tls.js';
28
29
 
29
30
  /**
30
31
  * Underpost main module methods
@@ -38,7 +39,16 @@ class Underpost {
38
39
  * @type {String}
39
40
  * @memberof Underpost
40
41
  */
41
- static version = 'v2.99.1';
42
+ static version = 'v2.99.5';
43
+
44
+ /**
45
+ * Required Node.js major version
46
+ * @static
47
+ * @type {String}
48
+ * @memberof Underpost
49
+ */
50
+ static majorNodejsVersion = 'v24';
51
+
42
52
  /**
43
53
  * Repository cli API
44
54
  * @static
@@ -228,8 +238,23 @@ class Underpost {
228
238
  static get start() {
229
239
  return UnderpostStartUp.API;
230
240
  }
241
+
242
+ /**
243
+ * TLS/SSL server utilities API
244
+ * @static
245
+ * @type {UnderpostTLS.API}
246
+ * @memberof Underpost
247
+ */
248
+ static get tls() {
249
+ return UnderpostTLS.API;
250
+ }
231
251
  }
232
252
 
253
+ if (!process.version || !process.version.startsWith(`${Underpost.majorNodejsVersion}.`))
254
+ console.warn(
255
+ `${`Underpost Warning: Required Node.js version is `.red}${`${Underpost.majorNodejsVersion}.x`.bgBlue.bold.white}${`, you are using `.red}${process.version.bgRed.bold.white}`,
256
+ );
257
+
233
258
  const up = Underpost;
234
259
 
235
260
  const underpost = Underpost;
@@ -258,6 +283,7 @@ export {
258
283
  UnderpostBackup,
259
284
  UnderpostCron,
260
285
  UnderpostStartUp,
286
+ UnderpostTLS,
261
287
  };
262
288
 
263
289
  export default Underpost;
@@ -20,7 +20,7 @@ import { createPeerServer } from '../../server/peer.js';
20
20
  import { createValkeyConnection } from '../../server/valkey.js';
21
21
  import { applySecurity, authMiddlewareFactory } from '../../server/auth.js';
22
22
  import { ssrMiddlewareFactory } from '../../server/ssr.js';
23
- import { TLS } from '../../server/tls.js';
23
+
24
24
  import { shellExec } from '../../server/process.js';
25
25
  import { devProxyHostFactory, isDevProxyContext, isTlsDevProxy } from '../../server/conf.js';
26
26
 
@@ -249,8 +249,8 @@ class ExpressService {
249
249
 
250
250
  // Start listening on the main port
251
251
  if (useLocalSsl && process.env.NODE_ENV === 'development') {
252
- if (!TLS.validateSecureContext()) shellExec(`node bin/deploy tls`);
253
- const { ServerSSL } = await TLS.createSslServer(app);
252
+ if (!Underpost.tls.validateSecureContext()) shellExec(`node bin/deploy tls`);
253
+ const { ServerSSL } = await Underpost.tls.createSslServer(app);
254
254
  await Underpost.start.listenPortController(ServerSSL, port, runningData);
255
255
  } else await Underpost.start.listenPortController(server, port, runningData);
256
256
 
@@ -66,7 +66,7 @@ const Config = {
66
66
  /**
67
67
  * @method deployIdFactory
68
68
  * @description Creates a new deploy ID.
69
- * @param {string} [deployId='dd-default
69
+ * @param {string} [deployId='dd-default']
70
70
  * @param {object} [options={ subConf: '', cluster: false }] - The options.
71
71
  * @memberof ServerConfBuilder
72
72
  */
@@ -842,8 +842,10 @@ const buildPortProxyRouter = (
842
842
 
843
843
  if (options.devProxyContext === true && process.env.NODE_ENV === 'development') {
844
844
  const confDevApiServer = JSON.parse(
845
- fs.readFileSync(`./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`),
846
- 'utf8',
845
+ fs.readFileSync(
846
+ `./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`,
847
+ 'utf8',
848
+ ),
847
849
  );
848
850
  let devApiHosts = [];
849
851
  let origins = [];
@@ -899,7 +901,7 @@ const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1
899
901
  * @description Gets the data deploy.
900
902
  * @param {object} options - The options.
901
903
  * @param {boolean} [options.buildSingleReplica=false] - The build single replica.
902
- * @param {string} options.deployId - The deploy ID.
904
+ * @param {string} [options.deployId] - The deploy ID.
903
905
  * @param {boolean} [options.disableSyncEnvPort=false] - The disable sync env port.
904
906
  * @returns {object} - The data deploy.
905
907
  * @memberof ServerConfBuilder
@@ -28,11 +28,13 @@ const levels = {
28
28
  debug: 4,
29
29
  };
30
30
 
31
- // This method set the current severity based on
32
- // the current NODE_ENV: show all the log levels
33
- // if the server was run in development mode; otherwise,
34
- // if it was run in production, show only warn and error messages.
35
- const level = () => 'info'; // (process.env.NODE_ENV || 'development' ? 'debug' : 'warn');
31
+ /**
32
+ * The `level` function determines the logging level based on the provided `logLevel` parameter or defaults to 'info'.
33
+ * @param {string} logLevel - The logging level to be used. If not provided, it defaults to 'info'.
34
+ * @returns {string} The logging level to be used for the logger.
35
+ * @memberof Logger
36
+ */
37
+ const level = (logLevel = '') => logLevel || 'info';
36
38
 
37
39
  // Define different colors for each level.
38
40
  // Colors make the log message more visible,
@@ -98,13 +100,14 @@ const setUpInfo = async (logger = new winston.Logger()) => {
98
100
  * messages.
99
101
  * @param meta - The `meta` parameter in the `loggerFactory` function is used to extract the last part
100
102
  * of a URL and use it to create log files in a specific directory.
101
- * @returns {winston.Logger} The `loggerFactory` function returns a logger instance created using Winston logger
103
+ * @param logLevel - Specify the logging level for the logger instance. e.g., 'error', 'warn', 'info', 'debug'.
104
+ * @returns {underpostLogger} The `loggerFactory` function returns a logger instance created using Winston logger
102
105
  * library. The logger instance is configured with various transports for printing out messages to
103
106
  * different destinations such as the terminal, error.log file, and all.log file. The logger instance
104
107
  * also has a method `setUpInfo` attached to it for setting up additional information.
105
108
  * @memberof Logger
106
109
  */
107
- const loggerFactory = (meta = { url: '' }) => {
110
+ const loggerFactory = (meta = { url: '' }, logLevel = '') => {
108
111
  meta = meta.url.split('/').pop();
109
112
  // Define which transports the logger must use to print out messages.
110
113
  // In this example, we are using three different transports
@@ -125,7 +128,7 @@ const loggerFactory = (meta = { url: '' }) => {
125
128
  // and used to log messages.
126
129
  const logger = winston.createLogger({
127
130
  defaultMeta: meta,
128
- level: level(),
131
+ level: level(logLevel),
129
132
  levels,
130
133
  format: format(meta),
131
134
  transports,
@@ -133,45 +136,44 @@ const loggerFactory = (meta = { url: '' }) => {
133
136
  // rejectionHandlers: [new winston.transports.File({ filename: 'rejections.log' })],
134
137
  // exitOnError: false,
135
138
  });
136
- logger.setUpInfo = async () => {
137
- await setUpInfo(logger);
138
- };
139
+ /**
140
+ * The returned logger is a real Winston logger instance with an extra `setUpInfo` method.
141
+ *
142
+ * @memberof Logger
143
+ * @typedef {winston.Logger & {
144
+ * setUpInfo: (logger?: winston.Logger) => Promise<void>
145
+ * }} underpostLogger
146
+ */
147
+ logger.setUpInfo = () => setUpInfo(logger);
148
+
139
149
  return logger;
140
150
  };
141
151
 
142
152
  /**
143
- * The `loggerMiddleware` function creates a middleware for logging HTTP requests using Morgan with
144
- * custom message format and options.
145
- * @param meta - The `meta` parameter in the `loggerMiddleware` function is an object that contains
146
- * information about the request URL. It has a default value of an empty object `{ url: '' }`. This
147
- * object is used to provide additional metadata for logging purposes.
148
- * @returns {Handler<any, any>} The `loggerMiddleware` function returns a middleware function that uses the Morgan library
149
- * to log HTTP request information. The middleware function formats the log message using predefined
150
- * tokens provided by Morgan and custom tokens like `:host` to include specific request details. The
151
- * log message format includes information such as remote address, HTTP method, host, URL, status code,
152
- * content length, and response time in milliseconds. The middleware
153
+ * The `loggerMiddleware` function is an Express middleware that uses the Morgan library to log HTTP requests.
154
+ * @param {Object} meta - An object containing metadata, such as the URL, to be used in the logger.
155
+ * @param {string} logLevel - The logging level to be used for the logger (e.g., 'error', 'warn', 'info', 'debug').
156
+ * @param {Function} skip - A function to determine whether to skip logging for a particular request.
157
+ * @returns {Function} A middleware function that can be used in an Express application to log HTTP requests.
153
158
  * @memberof Logger
154
159
  */
155
- const loggerMiddleware = (meta = { url: '' }) => {
160
+ const loggerMiddleware = (
161
+ meta = { url: '' },
162
+ logLevel = 'info',
163
+ skip = (req, res) => process.env.NODE_ENV === 'production',
164
+ ) => {
156
165
  const stream = {
157
166
  // Use the http severity
158
- write: (message) => loggerFactory(meta).http(message),
167
+ write: (message) => loggerFactory(meta, logLevel).http(message),
159
168
  };
160
169
 
161
- const skip = (req, res) => process.env.NODE_ENV === 'production';
162
-
163
170
  morgan.token('host', function (req, res) {
164
171
  return req.headers['host'];
165
172
  });
166
173
 
167
174
  return morgan(
168
- // Define message format string (this is the default one).
169
- // The message format is made from tokens, and each token is
170
- // defined inside the Morgan library.
171
- // You can create your custom token to show what do you want from a request.
175
+ // Define message format string
172
176
  `:remote-addr :method :host:url :status :res[content-length] - :response-time ms`,
173
- // Options: in this case, I overwrote the stream and the skip logic.
174
- // See the methods above.
175
177
  { stream, skip },
176
178
  );
177
179
  };
@@ -12,6 +12,7 @@ import dotenv from 'dotenv';
12
12
  import { loggerFactory } from './logger.js';
13
13
  import clipboard from 'clipboardy';
14
14
  import Underpost from '../index.js';
15
+ import { getNpmRootPath } from './conf.js';
15
16
 
16
17
  dotenv.config();
17
18
 
@@ -128,16 +129,40 @@ const shellCd = (cd, options = { disableLog: false }) => {
128
129
  * @param {string} cmd - The command to execute in the new terminal.
129
130
  * @param {Object} [options] - Options for the terminal opening.
130
131
  * @param {boolean} [options.single=false] - If true, execute as a single session process using `setsid`.
132
+ * @param {string} [options.chown] - Path to change ownership to the target user.
131
133
  * @returns {void}
132
134
  */
133
135
  const openTerminal = (cmd, options = { single: false }) => {
136
+ // Find the graphical user's UID from /run/user (prefer non-root UID, usually 1000)
137
+ const IDS = shellExec(`ls -1 /run/user`, { stdout: true, silent: true })
138
+ .split('\n')
139
+ .map((v) => v.trim())
140
+ .filter(Boolean);
141
+
142
+ const nonRootIds = IDS.filter((id) => id !== '0');
143
+ const ID = nonRootIds.length > 0 ? nonRootIds[0] : IDS[0];
144
+
145
+ if (!options.chown) options.chown = `/home/dd ${getNpmRootPath()}/underpost`;
146
+
147
+ shellExec(`chown -R ${ID}:${ID} ${options.chown}`);
148
+
149
+ // Run the terminal as the graphical user and use THAT user's runtime dir/bus.
150
+ const confCmd = `USER_GRAPHICAL=$(getent passwd "${ID}" | cut -d: -f1); \
151
+ sudo -u "$USER_GRAPHICAL" env DISPLAY="$DISPLAY" \
152
+ XDG_RUNTIME_DIR="/run/user/${ID}" \
153
+ DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${ID}/bus" \
154
+ PATH="$PATH" \
155
+ `;
156
+
134
157
  if (options.single === true) {
135
158
  // Run as a single session process
136
- shellExec(`setsid gnome-terminal -- bash -ic "${cmd}; exec bash" >/dev/null 2>&1 &`);
159
+ shellExec(`${confCmd} setsid gnome-terminal -- bash -ic '${cmd}; exec bash' >/dev/null 2>&1 &`, {
160
+ async: true,
161
+ });
137
162
  return;
138
163
  }
139
164
  // Run asynchronously and disown
140
- shellExec(`gnome-terminal -- bash -c "${cmd}; exec bash" & disown`, {
165
+ shellExec(`${confCmd} gnome-terminal -- bash -c '${cmd}; exec bash' >/dev/null 2>&1 & disown`, {
141
166
  async: true,
142
167
  stdout: true,
143
168
  });
@@ -13,10 +13,8 @@ import { createProxyMiddleware } from 'http-proxy-middleware';
13
13
  import { loggerFactory, loggerMiddleware } from './logger.js';
14
14
  import { buildPortProxyRouter, buildProxyRouter, getTlsHosts, isDevProxyContext, isTlsDevProxy } from './conf.js';
15
15
 
16
- import { SSL_BASE, TLS } from './tls.js';
17
16
  import { shellExec } from './process.js';
18
17
  import fs from 'fs-extra';
19
-
20
18
  import Underpost from '../index.js';
21
19
 
22
20
  dotenv.config();
@@ -85,7 +83,7 @@ class ProxyService {
85
83
  switch (port) {
86
84
  case 443:
87
85
  // For port 443 (HTTPS), create the SSL server
88
- const { ServerSSL } = await TLS.createSslServer(app, hosts);
86
+ const { ServerSSL } = await Underpost.tls.createSslServer(app, hosts);
89
87
  await Underpost.start.listenPortController(ServerSSL, port, runningData);
90
88
  break;
91
89
 
@@ -103,12 +101,12 @@ class ProxyService {
103
101
  if (isDevProxyContext() && isTlsDevProxy()) {
104
102
  tlsHosts = {};
105
103
  for (const tlsHost of getTlsHosts(hosts)) {
106
- if (fs.existsSync(SSL_BASE(tlsHost))) fs.removeSync(SSL_BASE(tlsHost));
107
- if (!TLS.validateSecureContext(tlsHost)) shellExec(`node bin/deploy tls "${tlsHost}"`);
104
+ if (fs.existsSync(Underpost.tls.SSL_BASE(tlsHost))) fs.removeSync(Underpost.tls.SSL_BASE(tlsHost));
105
+ if (!Underpost.tls.validateSecureContext(tlsHost)) shellExec(`node bin/deploy tls "${tlsHost}"`);
108
106
  tlsHosts[tlsHost] = {};
109
107
  }
110
108
  }
111
- const { ServerSSL } = await TLS.createSslServer(app, tlsHosts);
109
+ const { ServerSSL } = await Underpost.tls.createSslServer(app, tlsHosts);
112
110
  await Underpost.start.listenPortController(ServerSSL, port, runningData);
113
111
  break;
114
112
  }
package/src/server/tls.js CHANGED
@@ -1,8 +1,7 @@
1
1
  /**
2
- * Provides utilities for managing, building, and serving SSL/TLS contexts,
3
- * primarily using Certbot files and creating HTTPS servers.
2
+ * Transport Layer Security (TLS) / SSL utilities and HTTPS server creation and management.
4
3
  * @module src/server/tls.js
5
- * @namespace TransportLayerSecurity
4
+ * @namespace UnderpostTLS
6
5
  */
7
6
 
8
7
  import fs from 'fs-extra';
@@ -43,7 +42,7 @@ class TLS {
43
42
  * It attempts to be permissive: accepts cert-only, cert+ca, or fullchain.
44
43
  * @param {string} host
45
44
  * @returns {{key?:string, cert?:string, fullchain?:string, ca?:string, dir:string}}
46
- * @memberof TransportLayerSecurity
45
+ * @memberof UnderpostTLS
47
46
  */
48
47
  static locateSslFiles(host = DEFAULT_HOST) {
49
48
  const dir = SSL_BASE(host);
@@ -103,7 +102,7 @@ class TLS {
103
102
  * Validate that a secure context can be built for host (key + cert or fullchain present)
104
103
  * @param {string} host
105
104
  * @returns {boolean}
106
- * @memberof TransportLayerSecurity
105
+ * @memberof UnderpostTLS
107
106
  */
108
107
  static validateSecureContext(host = DEFAULT_HOST) {
109
108
  const files = TLS.locateSslFiles(host);
@@ -116,7 +115,7 @@ class TLS {
116
115
  * If separate cert + ca are found, they will be used accordingly.
117
116
  * @param {string} host
118
117
  * @returns {{key:string, cert:string, ca?:string}} options
119
- * @memberof TransportLayerSecurity
118
+ * @memberof UnderpostTLS
120
119
  */
121
120
  static buildSecureContext(host = DEFAULT_HOST) {
122
121
  const files = TLS.locateSslFiles(host);
@@ -142,7 +141,7 @@ class TLS {
142
141
  * The function will copy existing discovered files to: key.key, crt.crt, ca_bundle.crt when possible.
143
142
  * @param {string} host
144
143
  * @returns {boolean} true if at least key+cert exist after operation
145
- * @memberof TransportLayerSecurity
144
+ * @memberof UnderpostTLS
146
145
  */
147
146
  static async buildLocalSSL(host = DEFAULT_HOST) {
148
147
  const dir = SSL_BASE(host);
@@ -177,19 +176,16 @@ class TLS {
177
176
  * @param {import('express').Application} app
178
177
  * @param {Object<string, any>} hosts
179
178
  * @returns {{ServerSSL?: https.Server}}
180
- * @memberof TransportLayerSecurity
179
+ * @memberof UnderpostTLS
181
180
  */
182
181
  static async createSslServer(app, hosts = { [DEFAULT_HOST]: {} }) {
183
182
  let server;
184
183
  for (const host of Object.keys(hosts)) {
185
184
  // ensure canonical files exist (copies where possible)
186
185
  await TLS.buildLocalSSL(host);
187
- if (!TLS.validate_secure_context_check(host)) {
188
- // backward compatibility: some callers expect validateSecureContext
189
- if (!TLS.validateSecureContext(host)) {
190
- logger.error('Invalid SSL context, skipping host', { host });
191
- continue;
192
- }
186
+ if (!TLS.validateSecureContext(host)) {
187
+ logger.error('Invalid SSL context, skipping host', { host });
188
+ continue;
193
189
  }
194
190
 
195
191
  // build secure context options
@@ -218,7 +214,7 @@ class TLS {
218
214
  * @param {number} port
219
215
  * @param {Object<string, any>} proxyRouter
220
216
  * @returns {import('express').RequestHandler}
221
- * @memberof TransportLayerSecurity
217
+ * @memberof UnderpostTLS
222
218
  */
223
219
  static sslRedirectMiddleware(req, res, port = 80, proxyRouter = {}) {
224
220
  const sslRedirectUrl = `https://${req.headers.host}${req.url}`;
@@ -238,14 +234,23 @@ class TLS {
238
234
  }
239
235
  }
240
236
 
241
- // small helper for internal backward compatibility check name typo in older code
242
- TLS.validate_secure_context_check = TLS.validateSecureContext;
243
-
244
- // Backward compatibility exports
245
- const buildSSL = TLS.buildLocalSSL;
246
- const buildSecureContext = TLS.buildSecureContext;
247
- const validateSecureContext = TLS.validateSecureContext;
248
- const createSslServer = TLS.createSslServer;
249
- const sslRedirectMiddleware = TLS.sslRedirectMiddleware;
237
+ /**
238
+ * @class UnderpostTLS
239
+ * @description TLS/SSL utilities for Underpost.
240
+ * @memberof UnderpostTLS
241
+ */
242
+ class UnderpostTLS {
243
+ static API = {
244
+ TLS,
245
+ SSL_BASE,
246
+ locateSslFiles: TLS.locateSslFiles,
247
+ validateSecureContext: TLS.validateSecureContext,
248
+ buildSecureContext: TLS.buildSecureContext,
249
+ buildLocalSSL: TLS.buildLocalSSL,
250
+ createSslServer: TLS.createSslServer,
251
+ sslRedirectMiddleware: TLS.sslRedirectMiddleware,
252
+ };
253
+ }
250
254
 
251
- export { TLS, SSL_BASE, buildSSL, buildSecureContext, validateSecureContext, createSslServer, sslRedirectMiddleware };
255
+ export { TLS, SSL_BASE, UnderpostTLS };
256
+ export default UnderpostTLS;