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.
- package/.env.production +3 -0
- package/.github/workflows/ghpkg.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +1 -1
- package/.github/workflows/publish.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/CHANGELOG.md +145 -1
- package/Dockerfile +1 -1
- package/README.md +5 -121
- package/bin/build.js +18 -9
- package/bin/deploy.js +102 -197
- package/bin/file.js +4 -6
- package/cli.md +16 -12
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +54 -54
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/manifests/lxd/underpost-setup.sh +5 -5
- package/package.json +3 -3
- package/scripts/ssl.sh +164 -0
- package/src/cli/baremetal.js +7 -7
- package/src/cli/cloud-init.js +1 -1
- package/src/cli/cluster.js +31 -3
- package/src/cli/cron.js +9 -1
- package/src/cli/db.js +64 -2
- package/src/cli/deploy.js +189 -4
- package/src/cli/env.js +43 -0
- package/src/cli/fs.js +96 -2
- package/src/cli/image.js +15 -0
- package/src/cli/index.js +17 -4
- package/src/cli/monitor.js +33 -2
- package/src/cli/repository.js +95 -2
- package/src/cli/run.js +315 -51
- package/src/cli/script.js +32 -0
- package/src/cli/secrets.js +34 -0
- package/src/cli/test.js +42 -1
- package/src/client/components/core/Css.js +16 -8
- package/src/client/components/core/Docs.js +5 -13
- package/src/client/components/core/Modal.js +48 -29
- package/src/client/components/core/Router.js +6 -3
- package/src/client/components/core/Worker.js +205 -118
- package/src/client/components/core/windowGetDimensions.js +229 -162
- package/src/client/components/default/MenuDefault.js +1 -0
- package/src/client.dev.js +6 -3
- package/src/db/DataBaseProvider.js +65 -12
- package/src/db/mariadb/MariaDB.js +39 -6
- package/src/db/mongo/MongooseDB.js +51 -133
- package/src/index.js +2 -2
- package/src/mailer/EmailRender.js +58 -9
- package/src/mailer/MailerProvider.js +99 -25
- package/src/runtime/express/Express.js +32 -38
- package/src/runtime/lampp/Dockerfile +1 -1
- package/src/server/auth.js +9 -28
- package/src/server/backup.js +20 -0
- package/src/server/client-build-live.js +23 -12
- package/src/server/client-build.js +136 -91
- package/src/server/client-dev-server.js +35 -8
- package/src/server/client-icons.js +19 -0
- package/src/server/conf.js +543 -80
- package/src/server/dns.js +184 -42
- package/src/server/downloader.js +65 -24
- package/src/server/object-layer.js +260 -162
- package/src/server/peer.js +3 -9
- package/src/server/proxy.js +93 -76
- package/src/server/runtime.js +15 -21
- package/src/server/ssr.js +4 -4
- package/src/server/start.js +39 -0
- package/src/server/tls.js +251 -0
- package/src/server/valkey.js +11 -10
- package/src/ws/IoInterface.js +133 -39
- package/src/ws/IoServer.js +80 -31
- package/src/ws/core/core.ws.connection.js +50 -16
- package/src/ws/core/core.ws.emit.js +47 -8
- package/src/ws/core/core.ws.server.js +62 -10
- package/manifests/maas/lxd-preseed.yaml +0 -32
- package/src/server/ssl.js +0 -108
- /package/{manifests/maas → scripts}/device-scan.sh +0 -0
- /package/{manifests/maas → scripts}/gpu-diag.sh +0 -0
- /package/{manifests/maas → scripts}/maas-setup.sh +0 -0
- /package/{manifests/maas → scripts}/nat-iptables.sh +0 -0
- /package/{manifests/maas → scripts}/nvim.sh +0 -0
- /package/{manifests/maas → scripts}/snap-clean.sh +0 -0
- /package/{manifests/maas → scripts}/ssh-cluster-info.sh +0 -0
|
@@ -1,202 +1,269 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
13
|
-
*
|
|
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
|
-
//
|
|
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
|
-
*
|
|
29
|
-
* @
|
|
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
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
35
|
+
return null;
|
|
37
36
|
};
|
|
38
37
|
|
|
38
|
+
// --- Core Dimension Class ---
|
|
39
|
+
|
|
39
40
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* @
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
height: toInt(
|
|
84
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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] -
|
|
125
|
-
* @returns {number|null}
|
|
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
|
-
*
|
|
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] -
|
|
157
|
-
* @returns {number|null}
|
|
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
|
-
|
|
174
|
-
};
|
|
263
|
+
// --- Default Export ---
|
|
175
264
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
56
|
+
if (!this.#instance[key]) this.#instance[key] = {};
|
|
13
57
|
|
|
14
|
-
if (!db || this
|
|
58
|
+
if (!db || this.#instance[key][db.provider]) return this.#instance[key][db.provider];
|
|
15
59
|
|
|
16
|
-
// logger.info(`Load ${db.provider} provider`,
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
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 };
|