underpost 2.8.884 → 2.8.886

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 (82) hide show
  1. package/.env.production +3 -0
  2. package/.github/workflows/ghpkg.ci.yml +1 -1
  3. package/.github/workflows/npmpkg.ci.yml +1 -1
  4. package/.github/workflows/publish.ci.yml +5 -5
  5. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
  6. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  7. package/CHANGELOG.md +145 -1
  8. package/Dockerfile +1 -1
  9. package/README.md +5 -121
  10. package/bin/build.js +18 -9
  11. package/bin/deploy.js +102 -197
  12. package/bin/file.js +4 -6
  13. package/cli.md +16 -12
  14. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  15. package/manifests/deployment/dd-test-development/deployment.yaml +54 -54
  16. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  17. package/manifests/lxd/underpost-setup.sh +5 -5
  18. package/package.json +3 -3
  19. package/scripts/ssl.sh +164 -0
  20. package/src/cli/baremetal.js +7 -7
  21. package/src/cli/cloud-init.js +1 -1
  22. package/src/cli/cluster.js +31 -3
  23. package/src/cli/cron.js +9 -1
  24. package/src/cli/db.js +64 -2
  25. package/src/cli/deploy.js +189 -4
  26. package/src/cli/env.js +43 -0
  27. package/src/cli/fs.js +96 -2
  28. package/src/cli/image.js +15 -0
  29. package/src/cli/index.js +17 -4
  30. package/src/cli/monitor.js +33 -2
  31. package/src/cli/repository.js +95 -2
  32. package/src/cli/run.js +315 -51
  33. package/src/cli/script.js +32 -0
  34. package/src/cli/secrets.js +34 -0
  35. package/src/cli/test.js +42 -1
  36. package/src/client/components/core/Css.js +16 -8
  37. package/src/client/components/core/Docs.js +5 -13
  38. package/src/client/components/core/Modal.js +48 -29
  39. package/src/client/components/core/Router.js +6 -3
  40. package/src/client/components/core/Worker.js +205 -118
  41. package/src/client/components/core/windowGetDimensions.js +229 -162
  42. package/src/client/components/default/MenuDefault.js +1 -0
  43. package/src/client.dev.js +6 -3
  44. package/src/db/DataBaseProvider.js +65 -12
  45. package/src/db/mariadb/MariaDB.js +39 -6
  46. package/src/db/mongo/MongooseDB.js +51 -133
  47. package/src/index.js +2 -2
  48. package/src/mailer/EmailRender.js +58 -9
  49. package/src/mailer/MailerProvider.js +99 -25
  50. package/src/runtime/express/Express.js +32 -38
  51. package/src/runtime/lampp/Dockerfile +1 -1
  52. package/src/server/auth.js +9 -28
  53. package/src/server/backup.js +20 -0
  54. package/src/server/client-build-live.js +23 -12
  55. package/src/server/client-build.js +136 -91
  56. package/src/server/client-dev-server.js +35 -8
  57. package/src/server/client-icons.js +19 -0
  58. package/src/server/conf.js +543 -80
  59. package/src/server/dns.js +184 -42
  60. package/src/server/downloader.js +65 -24
  61. package/src/server/object-layer.js +260 -162
  62. package/src/server/peer.js +3 -9
  63. package/src/server/proxy.js +93 -76
  64. package/src/server/runtime.js +15 -21
  65. package/src/server/ssr.js +4 -4
  66. package/src/server/start.js +39 -0
  67. package/src/server/tls.js +251 -0
  68. package/src/server/valkey.js +11 -10
  69. package/src/ws/IoInterface.js +133 -39
  70. package/src/ws/IoServer.js +80 -31
  71. package/src/ws/core/core.ws.connection.js +50 -16
  72. package/src/ws/core/core.ws.emit.js +47 -8
  73. package/src/ws/core/core.ws.server.js +62 -10
  74. package/manifests/maas/lxd-preseed.yaml +0 -32
  75. package/src/server/ssl.js +0 -108
  76. /package/{manifests/maas → scripts}/device-scan.sh +0 -0
  77. /package/{manifests/maas → scripts}/gpu-diag.sh +0 -0
  78. /package/{manifests/maas → scripts}/maas-setup.sh +0 -0
  79. /package/{manifests/maas → scripts}/nat-iptables.sh +0 -0
  80. /package/{manifests/maas → scripts}/nvim.sh +0 -0
  81. /package/{manifests/maas → scripts}/snap-clean.sh +0 -0
  82. /package/{manifests/maas → scripts}/ssh-cluster-info.sh +0 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Module for managing Valkey
3
3
  * @module src/server/valkey.js
4
- * @namespace Valkey
4
+ * @namespace ValkeyService
5
5
  */
6
6
 
7
7
  import Valkey from 'iovalkey';
@@ -20,7 +20,7 @@ const ValkeyStatus = {}; // 'connected' | 'dummy' | 'error' | undefined
20
20
  * Checks if any Valkey instance is connected.
21
21
  * This is a backward-compatible overall flag.
22
22
  * @returns {boolean} True if any instance has a 'connected' status.
23
- * @memberof Valkey
23
+ * @memberof ValkeyService
24
24
  */
25
25
  const isValkeyEnable = () => Object.values(ValkeyStatus).some((s) => s === 'connected');
26
26
 
@@ -31,7 +31,7 @@ const isValkeyEnable = () => Object.values(ValkeyStatus).some((s) => s === 'conn
31
31
  * @param {string} [opts.path=''] - The path of the instance.
32
32
  * @returns {string} The instance key.
33
33
  * @private
34
- * @memberof Valkey
34
+ * @memberof ValkeyService
35
35
  */
36
36
  const _instanceKey = (opts = { host: '', path: '' }) => `${opts.host || ''}${opts.path || ''}`;
37
37
 
@@ -43,7 +43,7 @@ const _instanceKey = (opts = { host: '', path: '' }) => `${opts.host || ''}${opt
43
43
  * @param {string} [instance.path=''] - The path of the instance.
44
44
  * @param {object} [valkeyServerConnectionOptions={ host: '', path: '' }] - Connection options for the iovalkey client.
45
45
  * @returns {Promise<Valkey|undefined>} A promise that resolves to the Valkey client instance, or undefined if creation fails.
46
- * @memberof Valkey
46
+ * @memberof ValkeyService
47
47
  */
48
48
  const createValkeyConnection = async (
49
49
  instance = { host: '', path: '' },
@@ -108,7 +108,7 @@ const createValkeyConnection = async (
108
108
  * @param {object} payload - The source object.
109
109
  * @param {object} select - An object where keys are field names and values are 1 to include them.
110
110
  * @returns {object} A new object containing only the selected fields from the payload.
111
- * @memberof Valkey
111
+ * @memberof ValkeyService
112
112
  */
113
113
  const selectDtoFactory = (payload, select) => {
114
114
  const result = {};
@@ -122,7 +122,7 @@ const selectDtoFactory = (payload, select) => {
122
122
  * Factory function to create a new Valkey client instance.
123
123
  * @param {object} options - Connection options for the iovalkey client.
124
124
  * @returns {Promise<Valkey>} A promise that resolves to a new Valkey client.
125
- * @memberof Valkey
125
+ * @memberof ValkeyService
126
126
  */
127
127
  const valkeyClientFactory = async (options) => {
128
128
  const valkey = new Valkey({
@@ -154,7 +154,7 @@ const valkeyClientFactory = async (options) => {
154
154
  * @param {object} [options={ host: '', path: '' }] - The instance identifier.
155
155
  * @param {string} [key=''] - The key of the object to retrieve.
156
156
  * @returns {Promise<object|string|null>} A promise that resolves to the retrieved object, string, or null if not found.
157
- * @memberof Valkey
157
+ * @memberof ValkeyService
158
158
  */
159
159
  const getValkeyObject = async (options = { host: '', path: '' }, key = '') => {
160
160
  const k = _instanceKey(options);
@@ -185,7 +185,7 @@ const getValkeyObject = async (options = { host: '', path: '' }, key = '') => {
185
185
  * @param {string} [key=''] - The key under which to store the payload.
186
186
  * @param {object|string} [payload={}] - The data to store.
187
187
  * @returns {Promise<string>} A promise that resolves to 'OK' on success.
188
- * @memberof Valkey
188
+ * @memberof ValkeyService
189
189
  */
190
190
  const setValkeyObject = async (options = { host: '', path: '' }, key = '', payload = {}) => {
191
191
  const k = _instanceKey(options);
@@ -212,7 +212,7 @@ const setValkeyObject = async (options = { host: '', path: '' }, key = '', paylo
212
212
  * @param {string} [key=''] - The key of the object to update.
213
213
  * @param {object} [payload={}] - The new data to merge into the object.
214
214
  * @returns {Promise<string>} A promise that resolves to the result of the set operation.
215
- * @memberof Valkey
215
+ * @memberof ValkeyService
216
216
  */
217
217
  const updateValkeyObject = async (options = { host: '', path: '' }, key = '', payload = {}) => {
218
218
  let base = await getValkeyObject(options, key);
@@ -230,7 +230,7 @@ const updateValkeyObject = async (options = { host: '', path: '' }, key = '', pa
230
230
  * @param {object} [options.object={}] - An initial object to extend.
231
231
  * @param {string} [model=''] - The name of the model schema to use (e.g., 'user').
232
232
  * @returns {Promise<object>} A promise that resolves to the newly created object.
233
- * @memberof Valkey
233
+ * @memberof ValkeyService
234
234
  */
235
235
  const valkeyObjectFactory = async (options = { host: 'localhost', path: '', object: {} }, model = '') => {
236
236
  const idoDate = new Date().toISOString();
@@ -268,6 +268,7 @@ const valkeyObjectFactory = async (options = { host: 'localhost', path: '', obje
268
268
  /**
269
269
  * A collection of Valkey-related API functions.
270
270
  * @type {object}
271
+ * @memberof ValkeyServiceService
271
272
  */
272
273
  const ValkeyAPI = {
273
274
  valkeyClientFactory,
@@ -1,45 +1,139 @@
1
+ /**
2
+ * Module for creating and managing WebSocket channels.
3
+ * @module src/ws/IoInterface.js
4
+ * @namespace SocketIoInterface
5
+ */
6
+
1
7
  import { loggerFactory } from '../server/logger.js';
8
+ import { Socket } from 'socket.io';
2
9
 
3
10
  const logger = loggerFactory(import.meta);
4
11
 
5
- const IoCreateChannel = (
6
- IoInterface = {
7
- channel: '',
8
- connection: (socket = {}, client = {}, wsManagementId = '') => {},
9
- controller: (socket = {}, client = {}, args = '', wsManagementId = '') => {},
10
- disconnect: (socket = {}, client = {}, reason = '', wsManagementId = '') => {},
11
- stream: false,
12
- },
13
- ) => {
14
- return {
15
- channel: IoInterface.channel,
16
- client: {},
17
- connection: async function (socket, wsManagementId) {
18
- try {
19
- this.client[socket.id] = socket;
20
- socket.on(IoInterface.channel, (...args) => this.controller(socket, args, wsManagementId));
21
- await IoInterface.connection(socket, this.client, wsManagementId);
22
- } catch (error) {
23
- logger.error(error, { channel: IoInterface.channel, wsManagementId, stack: error.stack });
24
- }
25
- },
26
- controller: async function (socket, args, wsManagementId) {
27
- try {
28
- const payload = IoInterface.stream ? args[0] : JSON.parse(args[0]);
29
- await IoInterface.controller(socket, this.client, payload, wsManagementId, args);
30
- } catch (error) {
31
- logger.error(error, { channel: IoInterface.channel, wsManagementId, args, stack: error.stack });
32
- }
33
- },
34
- disconnect: async function (socket, reason, wsManagementId) {
35
- try {
36
- await IoInterface.disconnect(socket, this.client, reason, wsManagementId);
37
- delete this.client[socket.id];
38
- } catch (error) {
39
- logger.error(error, { channel: IoInterface.channel, wsManagementId, reason, stack: error.stack });
12
+ /**
13
+ * Defines the structure for a WebSocket channel's behavior functions.
14
+ * @typedef {Object} ChannelInterface
15
+ * @property {string} channel - The name of the channel.
16
+ * @property {function(Socket, Object.<string, Socket>, string): Promise<void>} [connection] - Handler on client connection.
17
+ * @property {function(Socket, Object.<string, Socket>, any, string, any[]): Promise<void>} [controller] - Handler for incoming channel messages.
18
+ * @property {function(Socket, Object.<string, Socket>, string, string): Promise<void>} [disconnect] - Handler on client disconnection.
19
+ * @property {boolean} [stream=false] - Whether the channel should treat the message as a raw stream (no JSON parsing).
20
+ * @memberof SocketIoInterface
21
+ */
22
+
23
+ /**
24
+ * @class IoChannel
25
+ * @alias IoChannel
26
+ * @memberof SocketIoInterface
27
+ * @classdesc Manages the logic, client map, and event listeners for a specific WebSocket channel,
28
+ * ensuring robust message handling and lifecycle management.
29
+ */
30
+ class IoChannel {
31
+ /**
32
+ * @private
33
+ * @type {ChannelInterface}
34
+ */
35
+ #IoInterface;
36
+
37
+ /**
38
+ * Map of connected sockets for this channel, keyed by socket ID.
39
+ * @type {Object.<string, Socket>}
40
+ */
41
+ client = {};
42
+
43
+ /**
44
+ * Creates an instance of IoChannel.
45
+ * @param {ChannelInterface} IoInterface - The interface object defining the channel's behavior.
46
+ */
47
+ constructor(IoInterface) {
48
+ this.#IoInterface = {
49
+ channel: '',
50
+ connection: async (socket = {}, client = {}, wsManagementId = '') => {},
51
+ controller: async (socket = {}, client = {}, payload = {}, wsManagementId = '', args = []) => {},
52
+ disconnect: async (socket = {}, client = {}, reason = '', wsManagementId = '') => {},
53
+ stream: false,
54
+ ...IoInterface,
55
+ };
56
+ logger.debug(`Channel instance created for: ${this.channel}`);
57
+ }
58
+
59
+ /**
60
+ * Gets the name of the channel.
61
+ * @returns {string} The channel name.
62
+ */
63
+ get channel() {
64
+ return this.#IoInterface.channel;
65
+ }
66
+
67
+ /**
68
+ * Handles a new socket connection for this channel.
69
+ * Sets up the listener for the channel message.
70
+ *
71
+ * @param {Socket} socket - The Socket.IO socket object.
72
+ * @param {string} wsManagementId - Unique identifier for the WebSocket management context.
73
+ * @returns {Promise<void>}
74
+ */
75
+ async connection(socket, wsManagementId) {
76
+ try {
77
+ this.client[socket.id] = socket;
78
+ // Use bind/arrow function to maintain 'this' context for the controller
79
+ socket.on(this.channel, (...args) => this.controller(socket, args, wsManagementId));
80
+ await this.#IoInterface.connection(socket, this.client, wsManagementId);
81
+ logger.debug(`Socket ${socket.id} connected to channel ${this.channel}`);
82
+ } catch (error) {
83
+ logger.error(error, { channel: this.channel, wsManagementId, stack: error.stack });
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Handles incoming messages on the channel.
89
+ *
90
+ * @private
91
+ * @param {Socket} socket - The Socket.IO socket object.
92
+ * @param {any[]} args - The raw arguments received from the socket event.
93
+ * @param {string} wsManagementId - Unique identifier for the WebSocket management context.
94
+ * @returns {Promise<void>}
95
+ */
96
+ async controller(socket, args, wsManagementId) {
97
+ try {
98
+ if (!args || args.length === 0) {
99
+ logger.warn(`No arguments received for channel: ${this.channel}`, { socketId: socket.id });
100
+ return;
40
101
  }
41
- },
42
- };
43
- };
102
+ // Determine if JSON parsing is needed based on the stream flag
103
+ const payload = this.#IoInterface.stream ? args[0] : JSON.parse(args[0]);
104
+
105
+ await this.#IoInterface.controller(socket, this.client, payload, wsManagementId, args);
106
+ } catch (error) {
107
+ logger.error(error, { channel: this.channel, wsManagementId, socketId: socket.id, args, stack: error.stack });
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Handles a socket disconnection for this channel.
113
+ *
114
+ * @param {Socket} socket - The Socket.IO socket object.
115
+ * @param {string} reason - The reason for disconnection (e.g., 'client namespace disconnect').
116
+ * @param {string} wsManagementId - Unique identifier for the WebSocket management context.
117
+ * @returns {Promise<void>}
118
+ */
119
+ async disconnect(socket, reason, wsManagementId) {
120
+ try {
121
+ await this.#IoInterface.disconnect(socket, this.client, reason, wsManagementId);
122
+ delete this.client[socket.id];
123
+ logger.debug(`Socket ${socket.id} disconnected from channel ${this.channel}. Reason: ${reason}`);
124
+ } catch (error) {
125
+ logger.error(error, { channel: this.channel, wsManagementId, reason, socketId: socket.id, stack: error.stack });
126
+ }
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Backward compatibility function to create a new channel instance.
132
+ * @memberof SocketIoInterface
133
+ * @function IoCreateChannel
134
+ * @param {ChannelInterface} IoInterface - The interface object defining the channel's behavior.
135
+ * @returns {IoChannel} An instance of the IoChannel class.
136
+ */
137
+ const IoCreateChannel = (IoInterface) => new IoChannel(IoInterface);
44
138
 
45
- export { IoCreateChannel };
139
+ export { IoChannel, IoCreateChannel };
@@ -1,39 +1,88 @@
1
+ /**
2
+ * Module for creating and managing WebSocket servers.
3
+ * @module src/ws/IoServer
4
+ * @namespace SocketIoServer
5
+ */
6
+
1
7
  'use strict';
2
8
 
3
9
  import { Server } from 'socket.io';
4
10
  import { loggerFactory } from '../server/logger.js';
11
+ import UnderpostStartUp from '../server/start.js';
5
12
 
6
- // https://socket.io/docs/v3/
13
+ import http from 'http';
7
14
 
8
15
  const logger = loggerFactory(import.meta);
9
16
 
10
- const IoServer = (httpServer, options = {}, Connection = () => {}) => {
11
- const wsOptions = {
12
- cors: {
13
- // origin: `http://localhost:${options.port}`,
14
- origins: options.origins,
15
- methods: ['GET', 'POST', 'DELETE', 'PUT'],
16
- allowedHeaders: [
17
- 'Access-Control-Allow-Headers',
18
- 'Access-Control-Allow-Origin',
19
- 'X-Requested-With',
20
- 'X-Access-Token',
21
- 'Content-Type',
22
- 'Host',
23
- 'Accept',
24
- 'Connection',
25
- 'Cache-Control',
26
- 'Authorization',
27
- ],
28
- credentials: true,
29
- },
30
- path: options.path !== '/' ? `${options.path}/socket.io/` : '/socket.io',
31
- };
32
- return {
33
- options: wsOptions,
34
- meta: import.meta,
35
- ioServer: new Server(httpServer, wsOptions).on('connection', Connection),
36
- };
37
- };
38
-
39
- export { IoServer };
17
+ /**
18
+ * @class IoServerClass
19
+ * @alias IoServerClass
20
+ * @memberof SocketIoServer
21
+ * @classdesc Provides a static factory method to create and configure a Socket.IO server,
22
+ * encapsulating WebSocket server initialization logic and CORS configuration.
23
+ */
24
+ class IoServerClass {
25
+ /**
26
+ * Creates a new WebSocket server instance attached to an HTTP server.
27
+ *
28
+ * @static
29
+ * @param {http.Server} httpServer - The HTTP server instance to attach the WebSocket server to.
30
+ * @param {Object} options - Configuration options for the WebSocket server.
31
+ * @param {string[]} options.origins - List of allowed origins for Cross-Origin Resource Sharing (CORS).
32
+ * @param {string} options.path - The base path for the API. The WebSocket path ('/socket.io') will be appended to this.
33
+ * @param {function(import('socket.io').Socket): void} ConnectionHandler - The connection handler function to be executed on a new connection.
34
+ * @returns {Object} An object containing the final options and the server instance.
35
+ * @returns {import('socket.io').ServerOptions} return.options - The final options object used to create the WebSocket server.
36
+ * @returns {import('socket.io').Server} return.ioServer - The created and listening WebSocket server instance.
37
+ * @returns {object} return.meta - The module's import meta object (`import.meta`).
38
+ */
39
+ static create(httpServer, options = {}, ConnectionHandler = () => {}) {
40
+ logger.info('origins', options.origins);
41
+ const wsOptions = {
42
+ cors: {
43
+ origins: options.origins,
44
+ methods: ['GET', 'POST', 'DELETE', 'PUT'],
45
+ allowedHeaders: [
46
+ 'Access-Control-Allow-Headers',
47
+ 'Access-Control-Allow-Origin',
48
+ 'X-Requested-With',
49
+ 'X-Access-Token',
50
+ 'Content-Type',
51
+ 'Host',
52
+ 'Accept',
53
+ 'Connection',
54
+ 'Cache-Control',
55
+ 'Authorization',
56
+ ],
57
+ credentials: true,
58
+ },
59
+ // Ensure the path ends correctly, appending '/socket.io/'
60
+ path: options.path !== '/' ? `${options.path}/socket.io/` : '/socket.io/',
61
+ };
62
+
63
+ const ioServerInstance = UnderpostStartUp.API.listenServerFactory(() =>
64
+ new Server(httpServer, wsOptions).on('connection', ConnectionHandler),
65
+ );
66
+
67
+ logger.info('Socket.IO Server created and listening', { path: wsOptions.path });
68
+
69
+ return {
70
+ options: wsOptions,
71
+ meta: import.meta,
72
+ ioServer: ioServerInstance,
73
+ };
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Backward compatibility export for the server creation function.
79
+ * @memberof SocketIoServer
80
+ * @function IoServer
81
+ * @param {http.Server} httpServer - The HTTP server instance.
82
+ * @param {Object} options - Configuration options.
83
+ * @param {function(import('socket.io').Socket): void} ConnectionHandler - The connection handler function.
84
+ * @returns {Object} The server configuration object.
85
+ */
86
+ const IoServer = IoServerClass.create;
87
+
88
+ export { IoServerClass, IoServer };
@@ -1,28 +1,62 @@
1
+ /**
2
+ * Module for handling new WebSocket connections and setting up channel listeners.
3
+ * @module ws/core.ws.connection
4
+ * @namespace CoreWsConnection
5
+ */
6
+
1
7
  import { loggerFactory } from '../../server/logger.js';
2
8
  import { CoreWsChatChannel } from './channels/core.ws.chat.js';
3
9
  import { CoreWsMailerChannel } from './channels/core.ws.mailer.js';
4
10
  import { CoreWsStreamChannel } from './channels/core.ws.stream.js';
11
+ import { Socket } from 'socket.io'; // Added for JSDoc type hinting
5
12
 
6
13
  const logger = loggerFactory(import.meta);
7
14
 
8
- const CoreWsConnection = function (socket, wsManagementId) {
9
- // const headers = socket.handshake.headers;
10
- // const ip = socket.handshake.address;
11
- // const { query, auth } = socket.handshake;
15
+ /**
16
+ * @class CoreWsConnectionManager
17
+ * @alias CoreWsConnectionManager
18
+ * @memberof CoreWsConnection
19
+ * @classdesc Manages the lifecycle of a new WebSocket connection, setting up listeners for
20
+ * all registered channels (Chat, Mailer, Stream) and handling disconnection by delegating to channel handlers.
21
+ */
22
+ class CoreWsConnectionManager {
23
+ /**
24
+ * Handles a new WebSocket connection by subscribing it to all active channels
25
+ * and setting up the disconnect listener.
26
+ *
27
+ * @static
28
+ * @param {Socket} socket - The Socket.IO socket object representing the client connection.
29
+ * @param {string} wsManagementId - Unique identifier for the WebSocket management context.
30
+ * @returns {void}
31
+ */
32
+ static handleConnection(socket, wsManagementId) {
33
+ logger.info(`New connection established. Socket ID: ${socket.id}`);
12
34
 
13
- logger.info(`CoreWsConnection ${socket.id}`);
35
+ // Subscribe socket to all channel connection handlers (assuming these channels are IoChannel instances)
36
+ CoreWsChatChannel.connection(socket, wsManagementId);
37
+ CoreWsMailerChannel.connection(socket, wsManagementId);
38
+ CoreWsStreamChannel.connection(socket, wsManagementId);
14
39
 
15
- CoreWsChatChannel.connection(socket, wsManagementId);
16
- CoreWsMailerChannel.connection(socket, wsManagementId);
17
- CoreWsStreamChannel.connection(socket, wsManagementId);
40
+ // Set up the disconnect listener
41
+ socket.on('disconnect', (reason) => {
42
+ logger.info(`Connection disconnected. Socket ID: ${socket.id} due to reason: ${reason}`);
18
43
 
19
- socket.on('disconnect', (reason) => {
20
- logger.info(`CoreWsConnection ${socket.id} due to reason: ${reason}`);
44
+ // Notify all channels of the disconnection
45
+ CoreWsChatChannel.disconnect(socket, reason, wsManagementId);
46
+ CoreWsMailerChannel.disconnect(socket, reason, wsManagementId);
47
+ CoreWsStreamChannel.disconnect(socket, reason, wsManagementId);
48
+ });
49
+ }
50
+ }
21
51
 
22
- CoreWsChatChannel.disconnect(socket, reason, wsManagementId);
23
- CoreWsMailerChannel.disconnect(socket, reason, wsManagementId);
24
- CoreWsStreamChannel.disconnect(socket, reason, wsManagementId);
25
- });
26
- };
52
+ /**
53
+ * Backward compatibility export for the connection handler function.
54
+ * @memberof CoreWsConnection
55
+ * @function CoreWsConnection
56
+ * @param {Socket} socket - The Socket.IO socket object.
57
+ * @param {string} wsManagementId - Unique identifier for the WebSocket management context.
58
+ * @returns {void}
59
+ */
60
+ const CoreWsConnection = CoreWsConnectionManager.handleConnection;
27
61
 
28
- export { CoreWsConnection };
62
+ export { CoreWsConnectionManager, CoreWsConnection };
@@ -1,14 +1,53 @@
1
+ /**
2
+ * Module for standardized WebSocket message emission (sending).
3
+ * @module ws/core.ws.emit
4
+ * @namespace CoreWsEmitter
5
+ */
6
+
1
7
  import { loggerFactory } from '../../server/logger.js';
8
+ import { Socket } from 'socket.io';
2
9
 
3
10
  const logger = loggerFactory(import.meta);
4
11
 
5
- const CoreWsEmit = (channel = '', client = {}, payload = {}) => {
6
- try {
7
- if (client && client.emit) client.emit(channel, JSON.stringify(payload));
8
- else logger.error('Invalid client', { channel, client, payload });
9
- } catch (error) {
10
- logger.error(error, { channel, client, payload, stack: error.stack });
12
+ /**
13
+ * @class CoreWsEmitter
14
+ * @alias CoreWsEmitter
15
+ * @memberof CoreWsEmitter
16
+ * @classdesc Provides a static utility method for safely emitting messages over a WebSocket connection.
17
+ */
18
+ class CoreWsEmitter {
19
+ /**
20
+ * Emits a payload to a specific client over a given channel.
21
+ * The payload is automatically JSON stringified.
22
+ *
23
+ * @static
24
+ * @param {string} [channel=''] - The name of the channel/event to emit on.
25
+ * @param {Socket | Object} [client={}] - The Socket.IO client/socket object. Must have an `emit` method.
26
+ * @param {Object} [payload={}] - The data object to send.
27
+ * @returns {void}
28
+ */
29
+ static emit(channel = '', client = {}, payload = {}) {
30
+ try {
31
+ if (client && typeof client.emit === 'function') {
32
+ client.emit(channel, JSON.stringify(payload));
33
+ } else {
34
+ logger.error('Invalid client: Cannot emit message.', { channel, client, payload });
35
+ }
36
+ } catch (error) {
37
+ logger.error(error, { channel, client, payload, stack: error.stack });
38
+ }
11
39
  }
12
- };
40
+ }
41
+
42
+ /**
43
+ * Backward compatibility export for the `emit` function.
44
+ * @memberof CoreWsEmitter
45
+ * @function CoreWsEmit
46
+ * @param {string} [channel=''] - The name of the channel/event to emit on.
47
+ * @param {Socket | Object} [client={}] - The Socket.IO client/socket object.
48
+ * @param {Object} [payload={}] - The data object to send.
49
+ * @returns {void}
50
+ */
51
+ const CoreWsEmit = CoreWsEmitter.emit;
13
52
 
14
- export { CoreWsEmit };
53
+ export { CoreWsEmitter, CoreWsEmit };
@@ -1,24 +1,76 @@
1
+ /**
2
+ * Module for creating and initializing the main WebSocket server instance.
3
+ * @module ws/core.ws.server
4
+ * @namespace CoreWsServer
5
+ */
6
+
1
7
  'use strict';
2
8
 
3
- import { IoServer } from '../IoServer.js';
9
+ import { IoServerClass } from '../IoServer.js';
4
10
  import { CoreWsConnection } from './core.ws.connection.js';
5
11
  import { CoreWsChatManagement } from './management/core.ws.chat.js';
6
12
  import { CoreWsMailerManagement } from './management/core.ws.mailer.js';
7
13
  import { CoreWsStreamManagement } from './management/core.ws.stream.js';
14
+ import http from 'http'; // Added for JSDoc type hinting
8
15
 
9
16
  // https://socket.io/docs/v3/
10
17
 
11
- const createIoServer = async (httpServer, options) => {
12
- const { host, path } = options;
13
- const wsManagementId = `${host}${path}`;
18
+ /**
19
+ * @class CoreWsServerClass
20
+ * @alias CoreWsServerClass
21
+ * @memberof CoreWsServer
22
+ * @classdesc Manages the creation and initialization of the main WebSocket server,
23
+ * including setting up the management instances for all channels.
24
+ */
25
+ class CoreWsServerClass {
26
+ /**
27
+ * Initializes channel management instances and creates the Socket.IO server.
28
+ *
29
+ * @static
30
+ * @async
31
+ * @param {http.Server} httpServer - The HTTP server instance to attach the WebSocket server to.
32
+ * @param {Object} options - Configuration options for the WebSocket server.
33
+ * @param {string} options.host - The host address.
34
+ * @param {string} options.path - The base path for the API.
35
+ * @returns {Promise<Object>} The result object from IoServer creation.
36
+ */
37
+ static async create(httpServer, options) {
38
+ const { host, path } = options;
39
+ if (!host || !path) {
40
+ throw new Error('Host and path must be provided in server options.');
41
+ }
42
+
43
+ // Create a unique identifier for this server instance's management context
44
+ const wsManagementId = `${host}${path}`;
45
+
46
+ // Initialize/Retrieve singleton management instances for all channels
47
+ CoreWsChatManagement.instance(wsManagementId);
48
+ CoreWsMailerManagement.instance(wsManagementId);
49
+ CoreWsStreamManagement.instance(wsManagementId);
14
50
 
15
- CoreWsChatManagement.instance(wsManagementId);
16
- CoreWsMailerManagement.instance(wsManagementId);
17
- CoreWsStreamManagement.instance(wsManagementId);
51
+ // Use the IoServerClass factory to create the server, passing the connection handler
52
+ return IoServerClass.create(httpServer, options, (socket) => CoreWsConnection(socket, wsManagementId));
53
+ }
54
+ }
18
55
 
19
- return IoServer(httpServer, options, (socket) => CoreWsConnection(socket, wsManagementId));
20
- };
56
+ /**
57
+ * Backward compatibility export for the server creation function.
58
+ * @memberof CoreWsServer
59
+ * @function createIoServer
60
+ * @param {http.Server} httpServer - The HTTP server instance.
61
+ * @param {Object} options - Configuration options.
62
+ * @returns {Promise<Object>} The server creation result.
63
+ */
64
+ const createIoServer = CoreWsServerClass.create;
21
65
 
66
+ /**
67
+ * Backward compatibility alias.
68
+ * @memberof CoreWsServer
69
+ * @function CoreWsServer
70
+ * @param {import('http').Server} httpServer - The HTTP server instance.
71
+ * @param {Object} options - Configuration options.
72
+ * @returns {Promise<Object>} The server creation result.
73
+ */
22
74
  const CoreWsServer = createIoServer;
23
75
 
24
- export { createIoServer, CoreWsServer };
76
+ export { CoreWsServerClass, createIoServer, CoreWsServer };
@@ -1,32 +0,0 @@
1
- config:
2
- core.https_address: "[::]:8443"
3
- # core.trust_password: password
4
- networks:
5
- - config:
6
- ipv4.address: 10.10.10.1/24
7
- ipv6.address: none
8
- description: ""
9
- name: lxdbr0
10
- type: ""
11
- project: default
12
- storage_pools:
13
- - config:
14
- size: 500GB
15
- description: ""
16
- name: default
17
- driver: zfs
18
- profiles:
19
- - config: {}
20
- description: ""
21
- devices:
22
- eth0:
23
- name: eth0
24
- network: lxdbr0
25
- type: nic
26
- root:
27
- path: /
28
- pool: default
29
- type: disk
30
- name: default
31
- projects: []
32
- cluster: null