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,202 +1,269 @@
1
- /*
2
- * windowGetDimensions.js
3
- * ES6 vanilla utilities: windowGetH and windowGetW
4
- * Returns the most reliable viewport height/width available, with fallbacks
5
- * from modern to old browsers.
6
- *
7
- * Usage:
8
- * import { windowGetH, windowGetW } from './windowGetDimensions.js';
9
- * const h = windowGetH();
10
- * const w = windowGetW();
1
+ /**
2
+ * This module exports utility functions (`windowGetH`, `windowGetW`) for reliably
3
+ * determining the browser viewport dimensions, refactored into a class structure
4
+ * for encapsulation and better organization.
11
5
  *
12
- * Notes:
13
- * - visualViewport (when present) reflects the *visible* viewport (changes when
14
- * the on-screen keyboard opens, or when mobile address/toolbars show/hide).
15
- * - documentElement.clientHeight/Width reflect the layout viewport.
16
- * - window.innerHeight/innerWidth include scrollbars and are widely supported.
17
- * - screen.* values are last-resort and reflect the physical screen, not the
18
- * browser chrome.
6
+ * @module src/client/components/core/windowGetDimensions.js
7
+ * @namespace PwaWindowDimensions
19
8
  */
20
9
 
21
- // Helper: coerce a candidate to a finite integer (or null if not usable)
10
+ // --- Internal Helper Functions ---
11
+
12
+ /**
13
+ * Helper: coerce a candidate value to a finite integer (or null if not usable).
14
+ * @private
15
+ * @param {*} v - The value to coerce (e.g., height/width from a window object).
16
+ * @returns {number|null} The rounded positive integer, or null if invalid.
17
+ * @memberof PwaWindowDimensions
18
+ */
22
19
  const toInt = (v) => {
23
20
  const n = Number(v);
24
21
  return Number.isFinite(n) && n > 0 ? Math.round(n) : null;
25
22
  };
26
23
 
27
24
  /**
28
- * Try visualViewport values (most accurate for "what's actually visible").
29
- * @returns {{height: number|null, width: number|null}}
25
+ * Helper: Merge candidates in priority order and return first valid value.
26
+ * @private
27
+ * @param {...(number|null)[]} candidates - A list of number or null values.
28
+ * @returns {number|null} The first finite, positive integer found, or null.
29
+ * @memberof PwaWindowDimensions
30
30
  */
31
- const getFromVisualViewport = () => {
32
- if (typeof window !== 'undefined' && window.visualViewport) {
33
- const { height, width } = window.visualViewport;
34
- return { height: toInt(height), width: toInt(width) };
31
+ const pickFirst = (...candidates) => {
32
+ for (const c of candidates) {
33
+ if (Number.isFinite(c) && c > 0) return Math.round(c);
35
34
  }
36
- return { height: null, width: null };
35
+ return null;
37
36
  };
38
37
 
38
+ // --- Core Dimension Class ---
39
+
39
40
  /**
40
- * Try layout viewport (doctype-root) measurements.
41
- * document.documentElement.clientHeight/clientWidth are stable and widely used.
42
- * @returns {{height: number|null, width: number|null}}
41
+ * @namespace PwaWindowDimensions
42
+ * @class
43
+ * @classdesc Utility class containing static methods for reliably determining the
44
+ * browser viewport dimensions, prioritizing visual viewport, then layout viewport,
45
+ * and finally screen dimensions as fallbacks.
46
+ *
47
+ * Usage:
48
+ * import PwaWindowDimensions from './windowGetDimensions.js';
49
+ * const h = PwaWindowDimensions.getH();
50
+ * @memberof PwaWindowDimensions
43
51
  */
44
- const getFromDocumentElement = () => {
45
- if (typeof document !== 'undefined' && document.documentElement) {
46
- const { clientHeight, clientWidth } = document.documentElement;
47
- return { height: toInt(clientHeight), width: toInt(clientWidth) };
52
+ export class PwaWindowDimensions {
53
+ // --- Private Static Getters (Encapsulating browser APIs) ---
54
+
55
+ /**
56
+ * @private
57
+ * @static
58
+ * Try visualViewport values (most accurate for "what's actually visible").
59
+ * @returns {{height: number|null, width: number|null}}
60
+ * @memberof PwaWindowDimensions
61
+ */
62
+ static #getFromVisualViewport() {
63
+ if (typeof window !== 'undefined' && window.visualViewport) {
64
+ const { height, width } = window.visualViewport;
65
+ return { height: toInt(height), width: toInt(width) };
66
+ }
67
+ return { height: null, width: null };
48
68
  }
49
- return { height: null, width: null };
50
- };
51
69
 
52
- /**
53
- * Try window.* measurements (innerHeight/innerWidth are widely supported).
54
- * @returns {{height: number|null, width: number|null}}
55
- */
56
- const getFromWindowInner = () => {
57
- if (typeof window !== 'undefined') {
58
- return { height: toInt(window.innerHeight), width: toInt(window.innerWidth) };
70
+ /**
71
+ * @private
72
+ * @static
73
+ * Try layout viewport (doctype-root) measurements.
74
+ * document.documentElement.clientHeight/clientWidth are stable and widely used.
75
+ * @returns {{height: number|null, width: number|null}}
76
+ * @memberof PwaWindowDimensions
77
+ */
78
+ static #getFromDocumentElement() {
79
+ if (typeof document !== 'undefined' && document.documentElement) {
80
+ const { clientHeight, clientWidth } = document.documentElement;
81
+ return { height: toInt(clientHeight), width: toInt(clientWidth) };
82
+ }
83
+ return { height: null, width: null };
59
84
  }
60
- return { height: null, width: null };
61
- };
62
85
 
63
- /**
64
- * Try body measurements.
65
- * @returns {{height: number|null, width: number|null}}
66
- */
67
- const getFromBody = () => {
68
- if (typeof document !== 'undefined' && document.body) {
69
- return { height: toInt(document.body.clientHeight), width: toInt(document.body.clientWidth) };
86
+ /**
87
+ * @private
88
+ * @static
89
+ * Try window.* measurements (innerHeight/innerWidth are widely supported).
90
+ * @returns {{height: number|null, width: number|null}}
91
+ * @memberof PwaWindowDimensions
92
+ */
93
+ static #getFromWindowInner() {
94
+ if (typeof window !== 'undefined') {
95
+ return { height: toInt(window.innerHeight), width: toInt(window.innerWidth) };
96
+ }
97
+ return { height: null, width: null };
70
98
  }
71
- return { height: null, width: null };
72
- };
73
99
 
74
- /**
75
- * Try screen measurements (physical screen/fallback).
76
- * screen.availHeight/availWidth are often available; outer* might also exist.
77
- * @returns {{height: number|null, width: number|null}}
78
- */
79
- const getFromScreen = () => {
80
- if (typeof window !== 'undefined' && window.screen) {
81
- const { availHeight, availWidth, height, width } = window.screen;
82
- return {
83
- height: toInt(availHeight) || toInt(height) || null,
84
- width: toInt(availWidth) || toInt(width) || null,
85
- };
100
+ /**
101
+ * @private
102
+ * @static
103
+ * Try body measurements (less reliable, used as a fallback).
104
+ * @returns {{height: number|null, width: number|null}}
105
+ * @memberof PwaWindowDimensions
106
+ */
107
+ static #getFromBody() {
108
+ if (typeof document !== 'undefined' && document.body) {
109
+ return { height: toInt(document.body.clientHeight), width: toInt(document.body.clientWidth) };
110
+ }
111
+ return { height: null, width: null };
86
112
  }
87
- return { height: null, width: null };
88
- };
89
113
 
90
- /**
91
- * Try outer dimensions (less reliable, but sometimes available).
92
- * @returns {{height: number|null, width: number|null}}
93
- */
94
- const getFromOuter = () => {
95
- if (typeof window !== 'undefined') {
96
- return { height: toInt(window.outerHeight), width: toInt(window.outerWidth) };
114
+ /**
115
+ * @private
116
+ * @static
117
+ * Try screen measurements (physical screen/last-resort fallback).
118
+ * @returns {{height: number|null, width: number|null}}
119
+ * @memberof PwaWindowDimensions
120
+ */
121
+ static #getFromScreen() {
122
+ if (typeof window !== 'undefined' && window.screen) {
123
+ const { availHeight, availWidth, height, width } = window.screen;
124
+ return {
125
+ height: toInt(availHeight) || toInt(height) || null,
126
+ width: toInt(availWidth) || toInt(width) || null,
127
+ };
128
+ }
129
+ return { height: null, width: null };
97
130
  }
98
- return { height: null, width: null };
99
- };
100
131
 
101
- /**
102
- * Merge candidates in priority order and return first valid value.
103
- * @param {...(number|null)[]} candidates
104
- * @returns {number|null}
105
- */
106
- const pickFirst = (...candidates) => {
107
- for (const c of candidates) {
108
- if (Number.isFinite(c) && c > 0) return Math.round(c);
132
+ /**
133
+ * @private
134
+ * @static
135
+ * Try outer dimensions (less reliable, sometimes available fallback).
136
+ * @returns {{height: number|null, width: number|null}}
137
+ * @memberof PwaWindowDimensions
138
+ */
139
+ static #getFromOuter() {
140
+ if (typeof window !== 'undefined') {
141
+ return { height: toInt(window.outerHeight), width: toInt(window.outerWidth) };
142
+ }
143
+ return { height: null, width: null };
109
144
  }
110
- return null;
111
- };
145
+
146
+ // --- Public Static Methods ---
147
+
148
+ /**
149
+ * Get the best-available viewport height in pixels.
150
+ *
151
+ * Priority (from most reliable for "visible" to least):
152
+ * 1. window.visualViewport.height (if `preferVisualViewport` is true)
153
+ * 2. document.documentElement.clientHeight (Layout viewport)
154
+ * 3. window.innerHeight (Window size)
155
+ * 4. document.body.clientHeight (Body size)
156
+ * 5. window.visualViewport.height (if `preferVisualViewport` is false)
157
+ * 6. window.screen.availHeight / window.screen.height (Physical screen)
158
+ * 7. window.outerHeight (Last resort)
159
+ *
160
+ * @memberof PwaWindowDimensions
161
+ * @static
162
+ * @param {Object} [options]
163
+ * @param {boolean} [options.preferVisualViewport=true] - When true, visualViewport is checked first (best for visible screen size, e.g., above mobile keyboard).
164
+ * @returns {number|null} Height in px (rounded integer) or null if none found.
165
+ * @memberof PwaWindowDimensions
166
+ */
167
+ static getH(options = {}) {
168
+ const { preferVisualViewport = true } = options;
169
+
170
+ const vv = PwaWindowDimensions.#getFromVisualViewport();
171
+ const de = PwaWindowDimensions.#getFromDocumentElement();
172
+ const wi = PwaWindowDimensions.#getFromWindowInner();
173
+ const bd = PwaWindowDimensions.#getFromBody();
174
+ const sc = PwaWindowDimensions.#getFromScreen();
175
+ const ot = PwaWindowDimensions.#getFromOuter();
176
+
177
+ // Determine the prioritized list of height candidates
178
+ let candidates = [de.height, wi.height, bd.height];
179
+ if (preferVisualViewport) {
180
+ candidates = [vv.height, ...candidates]; // vv first
181
+ } else {
182
+ candidates.push(vv.height); // vv later
183
+ }
184
+
185
+ // Add final fallbacks
186
+ candidates.push(sc.height, ot.height);
187
+
188
+ return pickFirst(...candidates) || null;
189
+ }
190
+
191
+ /**
192
+ * Get the best-available viewport width in pixels.
193
+ *
194
+ * Priority (from most reliable for "visible" to least):
195
+ * 1. window.visualViewport.width (if `preferVisualViewport` is true)
196
+ * 2. document.documentElement.clientWidth (Layout viewport)
197
+ * 3. window.innerWidth (Window size)
198
+ * 4. document.body.clientWidth (Body size)
199
+ * 5. window.visualViewport.width (if `preferVisualViewport` is false)
200
+ * 6. window.screen.availWidth / window.screen.width (Physical screen)
201
+ * 7. window.outerWidth (Last resort)
202
+ *
203
+ * @memberof PwaWindowDimensions
204
+ * @static
205
+ * @param {Object} [options]
206
+ * @param {boolean} [options.preferVisualViewport=true] - When true, visualViewport is checked first.
207
+ * @returns {number|null} Width in px (rounded integer) or null if none found.
208
+ * @memberof PwaWindowDimensions
209
+ */
210
+ static getW(options = {}) {
211
+ const { preferVisualViewport = true } = options;
212
+
213
+ const vv = PwaWindowDimensions.#getFromVisualViewport();
214
+ const de = PwaWindowDimensions.#getFromDocumentElement();
215
+ const wi = PwaWindowDimensions.#getFromWindowInner();
216
+ const bd = PwaWindowDimensions.#getFromBody();
217
+ const sc = PwaWindowDimensions.#getFromScreen();
218
+ const ot = PwaWindowDimensions.#getFromOuter();
219
+
220
+ // Determine the prioritized list of width candidates
221
+ let candidates = [de.width, wi.width, bd.width];
222
+ if (preferVisualViewport) {
223
+ candidates = [vv.width, ...candidates]; // vv first
224
+ } else {
225
+ candidates.push(vv.width); // vv later
226
+ }
227
+
228
+ // Add final fallbacks
229
+ candidates.push(sc.width, ot.width);
230
+
231
+ return pickFirst(...candidates) || null;
232
+ }
233
+ }
234
+
235
+ // --- Backward Compatibility Exports (Legacy API) ---
112
236
 
113
237
  /**
114
238
  * Get the best-available viewport height in pixels.
115
- * Priority (from most reliable for "visible" to least):
116
- * 1. window.visualViewport.height
117
- * 2. document.documentElement.clientHeight
118
- * 3. window.innerHeight
119
- * 4. document.body.clientHeight
120
- * 5. window.screen.availHeight / window.screen.height
121
- * 6. window.outerHeight
239
+ * This function exists for backward compatibility; it wraps PwaWindowDimensions.getH().
122
240
  *
241
+ * @function windowGetH
242
+ * @memberof PwaWindowDimensions
123
243
  * @param {Object} [options]
124
- * @param {boolean} [options.preferVisualViewport=true] - when true, prefer visualViewport if present
125
- * @returns {number|null} height in px (rounded integer) or null if none found
244
+ * @param {boolean} [options.preferVisualViewport=true] - When true, visualViewport is checked first.
245
+ * @returns {number|null} Height in px (rounded integer) or null if none found.
246
+ * @memberof PwaWindowDimensions
126
247
  */
127
- export const windowGetH = (options = {}) => {
128
- const { preferVisualViewport = true } = options;
129
-
130
- const vv = getFromVisualViewport();
131
- const de = getFromDocumentElement();
132
- const wi = getFromWindowInner();
133
- const bd = getFromBody();
134
- const sc = getFromScreen();
135
- const ot = getFromOuter();
136
-
137
- if (preferVisualViewport) {
138
- return pickFirst(vv.height, de.height, wi.height, bd.height, sc.height, ot.height) || null;
139
- }
140
-
141
- // if not preferring visualViewport, still include it but later
142
- return pickFirst(de.height, wi.height, bd.height, vv.height, sc.height, ot.height) || null;
143
- };
248
+ export const windowGetH = (options = {}) => PwaWindowDimensions.getH(options);
144
249
 
145
250
  /**
146
251
  * Get the best-available viewport width in pixels.
147
- * Priority (from most reliable for "visible" to least):
148
- * 1. window.visualViewport.width
149
- * 2. document.documentElement.clientWidth
150
- * 3. window.innerWidth
151
- * 4. document.body.clientWidth
152
- * 5. window.screen.availWidth / window.screen.width
153
- * 6. window.outerWidth
252
+ * This function exists for backward compatibility; it wraps PwaWindowDimensions.getW().
154
253
  *
254
+ * @function windowGetW
255
+ * @memberof PwaWindowDimensions
155
256
  * @param {Object} [options]
156
- * @param {boolean} [options.preferVisualViewport=true] - when true, prefer visualViewport if present
157
- * @returns {number|null} width in px (rounded integer) or null if none found
257
+ * @param {boolean} [options.preferVisualViewport=true] - When true, prefer visualViewport if present
258
+ * @returns {number|null} Width in px (rounded integer) or null if none found.
259
+ * @memberof PwaWindowDimensions
158
260
  */
159
- export const windowGetW = (options = {}) => {
160
- const { preferVisualViewport = true } = options;
161
-
162
- const vv = getFromVisualViewport();
163
- const de = getFromDocumentElement();
164
- const wi = getFromWindowInner();
165
- const bd = getFromBody();
166
- const sc = getFromScreen();
167
- const ot = getFromOuter();
168
-
169
- if (preferVisualViewport) {
170
- return pickFirst(vv.width, de.width, wi.width, bd.width, sc.width, ot.width) || null;
171
- }
261
+ export const windowGetW = (options = {}) => PwaWindowDimensions.getW(options);
172
262
 
173
- return pickFirst(de.width, wi.width, bd.width, vv.width, sc.width, ot.width) || null;
174
- };
263
+ // --- Default Export ---
175
264
 
176
- // Convenience default export (optional)
177
- export default {
178
- windowGetH,
179
- windowGetW,
180
- };
181
-
182
- /* --------------------------------------------------------------------------
183
- * Example usage:
184
- *
185
- * import { windowGetH, windowGetW } from './windowGetDimensions.js';
186
- *
187
- * // Get values now
188
- * const currentH = windowGetH();
189
- * const currentW = windowGetW();
190
- *
191
- * // React to changes (recommended on mobile)
192
- * if (window.visualViewport) {
193
- * window.visualViewport.addEventListener('resize', () => {
194
- * console.log('visualViewport resize ->', windowGetH(), windowGetW());
195
- * });
196
- * } else {
197
- * window.addEventListener('resize', () => {
198
- * console.log('window resize ->', windowGetH(), windowGetW());
199
- * });
200
- * }
201
- *
202
- * --------------------------------------------------------------------------*/
265
+ /**
266
+ * @typedef {PwaWindowDimensions} PwaWindowDimensions
267
+ * @memberof PwaWindowDimensions
268
+ */
269
+ export default PwaWindowDimensions;
@@ -186,6 +186,7 @@ const MenuDefault = {
186
186
  })}
187
187
  ${await BtnIcon.Render({
188
188
  class: 'in wfa main-btn-menu main-btn-chat',
189
+ useMenuBtn: true,
189
190
  label: html`${renderMenuLabel({
190
191
  icon: html`<i class="far fa-comments"></i>`,
191
192
  text: html`<span class="menu-label-text">${Translate.Render('chat')}</span>`,
package/src/client.dev.js CHANGED
@@ -6,16 +6,19 @@
6
6
  import dotenv from 'dotenv';
7
7
  import { loggerFactory } from './server/logger.js';
8
8
  import { ProcessController } from './server/process.js';
9
- import { Config } from './server/conf.js';
9
+ import { Config, buildClientStaticConf } from './server/conf.js';
10
10
  import { createClientDevServer } from './server/client-dev-server.js';
11
- dotenv.config();
12
11
 
13
- await Config.build();
12
+ dotenv.config();
14
13
 
15
14
  const logger = loggerFactory(import.meta);
16
15
 
17
16
  await logger.setUpInfo();
18
17
 
18
+ await buildClientStaticConf();
19
+
20
+ await Config.build();
21
+
19
22
  await createClientDevServer();
20
23
 
21
24
  ProcessController.init(logger);
@@ -1,29 +1,73 @@
1
1
  import { MongooseDB } from './mongo/MongooseDB.js';
2
2
  import { loggerFactory } from '../server/logger.js';
3
3
 
4
+ /**
5
+ * Module for managing and loading various database connections (e.g., Mongoose, MariaDB).
6
+ * @module src/db/DataBaseProvider.js
7
+ * @namespace DataBaseProviderNamespace
8
+ */
9
+
4
10
  const logger = loggerFactory(import.meta);
5
11
 
6
- const DataBaseProvider = {
7
- instance: {},
8
- load: async function (options = { apis: [], host: '', path: '', db: {} }) {
12
+ /**
13
+ * @class
14
+ * @alias DataBaseProviderService
15
+ * @memberof DataBaseProviderNamespace
16
+ * @classdesc Centralized service for loading, managing, and accessing multiple database connections
17
+ * based on application configuration (host, path, provider type).
18
+ */
19
+ class DataBaseProviderService {
20
+ /**
21
+ * Internal storage for database connection instances, keyed by host+path.
22
+ * @type {object.<string, object>}
23
+ * @private
24
+ */
25
+ #instance = {};
26
+
27
+ /**
28
+ * Retrieves the internal instance storage for direct access (used for backward compatibility).
29
+ * @returns {object.<string, object>} The internal connection instance map.
30
+ */
31
+ get instance() {
32
+ return this.#instance;
33
+ }
34
+
35
+ /**
36
+ * Loads and initializes a database provider based on the configuration.
37
+ * If the connection is already loaded for the given host/path, it returns the existing instance.
38
+ *
39
+ * @async
40
+ * @param {object} [options] - Configuration for the database connection.
41
+ * @param {Array<string>} [options.apis=[]] - List of APIs whose models should be loaded (for Mongoose).
42
+ * @param {string} [options.host=''] - The host part of the application context (e.g., domain).
43
+ * @param {string} [options.path=''] - The path part of the application context.
44
+ * @param {object} [options.db={}] - The specific database configuration object.
45
+ * @param {string} options.db.provider - The name of the database provider ('mongoose', 'mariadb', etc.).
46
+ * @param {string} options.db.host - The database server host.
47
+ * @param {string} options.db.name - The database name.
48
+ * @returns {Promise<object|undefined>} A promise that resolves to the initialized provider object
49
+ * or `undefined` on error or if the provider is already loaded.
50
+ */
51
+ async load(options = { apis: [], host: '', path: '', db: {} }) {
9
52
  try {
10
53
  const { apis, host, path, db } = options;
54
+ const key = `${host}${path}`;
11
55
 
12
- if (!this.instance[`${host}${path}`]) this.instance[`${host}${path}`] = {};
56
+ if (!this.#instance[key]) this.#instance[key] = {};
13
57
 
14
- if (!db || this.instance[`${host}${path}`][db.provider]) return;
58
+ if (!db || this.#instance[key][db.provider]) return this.#instance[key][db.provider];
15
59
 
16
- // logger.info(`Load ${db.provider} provider`, `${host}${path}`);
60
+ // logger.info(`Load ${db.provider} provider`, key);
17
61
  switch (db.provider) {
18
62
  case 'mongoose':
19
63
  {
20
64
  const conn = await MongooseDB.connect(db.host, db.name);
21
- this.instance[`${host}${path}`][db.provider] = {
65
+ this.#instance[key][db.provider] = {
22
66
  models: await MongooseDB.loadModels({ conn, apis }),
23
67
  connection: conn,
24
68
  close: async () => {
25
69
  return await new Promise((resolve) => {
26
- DataBaseProvider.instance[`${host}${path}`][db.provider].connection.close().then(() => {
70
+ this.#instance[key][db.provider].connection.close().then(() => {
27
71
  // logger.info('Mongoose connection is disconnected', db);
28
72
  return resolve();
29
73
  });
@@ -35,11 +79,20 @@ const DataBaseProvider = {
35
79
  default:
36
80
  break;
37
81
  }
38
- return this.instance[`${host}${path}`][db.provider];
82
+ return this.#instance[key][db.provider];
39
83
  } catch (error) {
40
84
  logger.error(error, { error: error.stack, options });
41
85
  return undefined;
42
86
  }
43
- },
44
- };
45
- export { DataBaseProvider };
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Singleton instance of the DataBaseProviderService class for backward compatibility.
92
+ * @alias DataBaseProvider
93
+ * @memberof DataBaseProviderNamespace
94
+ * @type {DataBaseProviderService}
95
+ */
96
+ const DataBaseProvider = new DataBaseProviderService();
97
+
98
+ export { DataBaseProvider, DataBaseProviderService as DataBaseProviderClass };
@@ -2,10 +2,35 @@ import mariadb from 'mariadb';
2
2
 
3
3
  import { loggerFactory } from '../../server/logger.js';
4
4
 
5
+ /**
6
+ * Module for interacting with MariaDB/MySQL databases using the mariadb connector.
7
+ * @module src/db/MariaDB.js
8
+ * @namespace MariaDBNamespace
9
+ */
10
+
5
11
  const logger = loggerFactory(import.meta);
6
12
 
7
- const MariaDB = {
8
- query: async (options) => {
13
+ /**
14
+ * @class
15
+ * @alias MariaDBService
16
+ * @memberof MariaDBNamespace
17
+ * @classdesc Provides a simplified interface for executing queries against a MariaDB/MySQL database
18
+ * using a connection pool, ensuring connection management (acquisition and release).
19
+ */
20
+ class MariaDBService {
21
+ /**
22
+ * Executes a SQL query against the MariaDB database.
23
+ *
24
+ * @async
25
+ * @param {object} options - The database connection and query options.
26
+ * @param {string} [options.host='127.0.0.1'] - The database host.
27
+ * @param {number} [options.port=3306] - The database port.
28
+ * @param {string} [options.user='root'] - The database user.
29
+ * @param {string} [options.password=''] - The database password.
30
+ * @param {string} options.query - The SQL query string to execute.
31
+ * @returns {Promise<any>} The result of the database query.
32
+ */
33
+ async query(options) {
9
34
  const { host, port, user, password, query } = options;
10
35
  const pool = mariadb.createPool({
11
36
  host: 'host' in options ? host : '127.0.0.1',
@@ -22,12 +47,20 @@ const MariaDB = {
22
47
  if (error.stack.startsWith('TypeError: Do not know how to serialize a BigInt')) return;
23
48
  logger.error(error, error.stack);
24
49
  } finally {
25
- if (conn) conn.release(); //release to pool
50
+ if (conn) conn.release(); // release to pool
26
51
  await pool.end();
27
52
  }
28
53
 
29
54
  return result;
30
- },
31
- };
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Singleton instance of the MariaDBService class for backward compatibility.
60
+ * @alias MariaDB
61
+ * @memberof MariaDBNamespace
62
+ * @type {MariaDBService}
63
+ */
64
+ const MariaDB = new MariaDBService();
32
65
 
33
- export { MariaDB };
66
+ export { MariaDB, MariaDBService as MariaDBClass };