underpost 2.8.885 → 2.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/.vscode/zed.keymap.json +17 -0
- package/.vscode/zed.settings.json +20 -0
- package/CHANGELOG.md +145 -1
- package/Dockerfile +20 -3
- package/README.md +6 -6
- package/bin/build.js +18 -9
- package/bin/deploy.js +130 -195
- package/bin/zed.js +20 -0
- package/cli.md +13 -7
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +50 -50
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/manifests/lxd/underpost-setup.sh +5 -5
- package/package.json +3 -4
- package/{manifests/maas → scripts}/ssh-cluster-info.sh +1 -1
- package/scripts/ssl.sh +164 -0
- package/src/cli/baremetal.js +8 -8
- package/src/cli/cloud-init.js +1 -1
- package/src/cli/cluster.js +15 -4
- package/src/cli/cron.js +1 -1
- package/src/cli/db.js +2 -1
- package/src/cli/deploy.js +65 -14
- package/src/cli/fs.js +2 -2
- package/src/cli/image.js +19 -2
- package/src/cli/index.js +11 -4
- package/src/cli/monitor.js +34 -1
- package/src/cli/repository.js +42 -1
- package/src/cli/run.js +396 -86
- 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 +0 -8
- package/src/client/components/core/windowGetDimensions.js +229 -162
- package/src/index.js +2 -2
- package/src/mailer/MailerProvider.js +1 -0
- package/src/runtime/express/Dockerfile +41 -0
- package/src/runtime/express/Express.js +12 -4
- package/src/runtime/lampp/Dockerfile +1 -1
- package/src/server/backup.js +20 -0
- package/src/server/client-build-live.js +12 -10
- package/src/server/client-build.js +136 -91
- package/src/server/client-dev-server.js +16 -2
- package/src/server/client-icons.js +19 -0
- package/src/server/conf.js +495 -69
- package/src/server/dns.js +169 -46
- package/src/server/downloader.js +65 -24
- package/src/server/object-layer.js +260 -162
- package/src/server/peer.js +2 -8
- package/src/server/proxy.js +93 -76
- package/src/server/runtime.js +15 -16
- package/src/server/ssr.js +4 -4
- package/src/server/tls.js +251 -0
- package/src/server/valkey.js +11 -10
- package/src/ws/IoInterface.js +2 -1
- package/src/ws/IoServer.js +2 -1
- package/src/ws/core/core.ws.connection.js +1 -1
- package/src/ws/core/core.ws.emit.js +1 -1
- package/src/ws/core/core.ws.server.js +1 -1
- 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/src/cli/script.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script module for managing the execution of scripts.
|
|
3
|
+
* @module src/cli/script.js
|
|
4
|
+
* @namespace UnderpostScript
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import { getNpmRootPath } from '../server/conf.js';
|
|
2
8
|
import { loggerFactory } from '../server/logger.js';
|
|
3
9
|
import { shellExec } from '../server/process.js';
|
|
@@ -6,14 +12,34 @@ import UnderpostDeploy from './deploy.js';
|
|
|
6
12
|
|
|
7
13
|
const logger = loggerFactory(import.meta);
|
|
8
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @class UnderpostScript
|
|
17
|
+
* @description Manages the execution of scripts.
|
|
18
|
+
* @memberof UnderpostScript
|
|
19
|
+
*/
|
|
9
20
|
class UnderpostScript {
|
|
10
21
|
static API = {
|
|
22
|
+
/**
|
|
23
|
+
* @method set
|
|
24
|
+
* @description Sets a script in the package.json file.
|
|
25
|
+
* @param {string} key - The key for the script.
|
|
26
|
+
* @param {string} value - The value for the script.
|
|
27
|
+
* @memberof UnderpostScript
|
|
28
|
+
*/
|
|
11
29
|
set(key, value) {
|
|
12
30
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
13
31
|
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
14
32
|
packageJson.scripts[key] = value;
|
|
15
33
|
fs.writeFileSync(`${npmRoot}/package.json`, JSON.stringify(packageJson, null, 4));
|
|
16
34
|
},
|
|
35
|
+
/**
|
|
36
|
+
* @method run
|
|
37
|
+
* @description Runs a script.
|
|
38
|
+
* @param {string} key - The key for the script.
|
|
39
|
+
* @param {string} value - The value for the script.
|
|
40
|
+
* @param {object} options - The options for the script.
|
|
41
|
+
* @memberof UnderpostScript
|
|
42
|
+
*/
|
|
17
43
|
run(key, value, options) {
|
|
18
44
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
19
45
|
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
@@ -41,6 +67,12 @@ class UnderpostScript {
|
|
|
41
67
|
}
|
|
42
68
|
shellExec(`cd ${npmRoot} && npm run ${key}`);
|
|
43
69
|
},
|
|
70
|
+
/**
|
|
71
|
+
* @method get
|
|
72
|
+
* @description Gets a script from the package.json file.
|
|
73
|
+
* @param {string} key - The key for the script.
|
|
74
|
+
* @memberof UnderpostScript
|
|
75
|
+
*/
|
|
44
76
|
get(key) {
|
|
45
77
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
46
78
|
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
package/src/cli/secrets.js
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets module for managing the secrets of the application.
|
|
3
|
+
* @module src/cli/secrets.js
|
|
4
|
+
* @namespace UnderpostSecret
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import dotenv from 'dotenv';
|
|
2
8
|
import { shellExec } from '../server/process.js';
|
|
3
9
|
import fs from 'fs-extra';
|
|
4
10
|
import UnderpostRootEnv from './env.js';
|
|
5
11
|
|
|
12
|
+
dotenv.config();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @class UnderpostSecret
|
|
16
|
+
* @description Manages the secrets of the application.
|
|
17
|
+
* @memberof UnderpostSecret
|
|
18
|
+
*/
|
|
6
19
|
class UnderpostSecret {
|
|
7
20
|
static API = {
|
|
21
|
+
/**
|
|
22
|
+
* @method docker
|
|
23
|
+
* @description Manages the secrets of the application.
|
|
24
|
+
* @memberof UnderpostSecret
|
|
25
|
+
*/
|
|
8
26
|
docker: {
|
|
27
|
+
/**
|
|
28
|
+
* @method init
|
|
29
|
+
* @description Initializes the docker secrets.
|
|
30
|
+
* @memberof UnderpostSecret
|
|
31
|
+
*/
|
|
9
32
|
init() {
|
|
10
33
|
shellExec(`docker swarm init`);
|
|
11
34
|
},
|
|
35
|
+
/**
|
|
36
|
+
* @method createFromEnvFile
|
|
37
|
+
* @description Creates a secret from an env file.
|
|
38
|
+
* @param {string} envPath - The path to the env file.
|
|
39
|
+
* @memberof UnderpostSecret
|
|
40
|
+
*/
|
|
12
41
|
createFromEnvFile(envPath) {
|
|
13
42
|
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
14
43
|
for (const key of Object.keys(envObj)) {
|
|
@@ -23,6 +52,11 @@ class UnderpostSecret {
|
|
|
23
52
|
shellExec(`docker secret ls`);
|
|
24
53
|
},
|
|
25
54
|
},
|
|
55
|
+
/**
|
|
56
|
+
* @method underpost
|
|
57
|
+
* @description Manages the secrets of the application.
|
|
58
|
+
* @memberof UnderpostSecret
|
|
59
|
+
*/
|
|
26
60
|
underpost: {
|
|
27
61
|
createFromEnvFile(envPath) {
|
|
28
62
|
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
package/src/cli/test.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test module for running tests on the application.
|
|
3
|
+
* @module src/cli/test.js
|
|
4
|
+
* @namespace UnderpostTest
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import { timer } from '../client/components/core/CommonJs.js';
|
|
2
8
|
import { MariaDB } from '../db/mariadb/MariaDB.js';
|
|
3
9
|
import { getNpmRootPath } from '../server/conf.js';
|
|
@@ -7,6 +13,11 @@ import UnderpostDeploy from './deploy.js';
|
|
|
7
13
|
|
|
8
14
|
const logger = loggerFactory(import.meta);
|
|
9
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @class UnderpostTest
|
|
18
|
+
* @description Manages the test of the application.
|
|
19
|
+
* @memberof UnderpostTest
|
|
20
|
+
*/
|
|
10
21
|
class UnderpostTest {
|
|
11
22
|
static API = {
|
|
12
23
|
/**
|
|
@@ -20,15 +31,35 @@ class UnderpostTest {
|
|
|
20
31
|
* @static
|
|
21
32
|
* @method setUpInfo
|
|
22
33
|
* @returns {Promise<void>}
|
|
23
|
-
* @memberof
|
|
34
|
+
* @memberof UnderpostTest
|
|
24
35
|
*/
|
|
25
36
|
async setUpInfo() {
|
|
26
37
|
return await setUpInfo(logger);
|
|
27
38
|
},
|
|
39
|
+
/**
|
|
40
|
+
* @method run
|
|
41
|
+
* @description Runs the test of the application.
|
|
42
|
+
* @memberof UnderpostTest
|
|
43
|
+
*/
|
|
28
44
|
run() {
|
|
29
45
|
actionInitLog();
|
|
30
46
|
shellExec(`cd ${getNpmRootPath()}/underpost && npm run test`);
|
|
31
47
|
},
|
|
48
|
+
/**
|
|
49
|
+
* @method callback
|
|
50
|
+
* @description Manages the test of the application.
|
|
51
|
+
* @param {string} deployList - The list of deployments to test.
|
|
52
|
+
* @param {object} options - The options for the test.
|
|
53
|
+
* @param {boolean} options.itc - If true, tests the inside container.
|
|
54
|
+
* @param {boolean} options.sh - If true, tests the shell.
|
|
55
|
+
* @param {boolean} options.logs - If true, tests the logs.
|
|
56
|
+
* @param {string} options.podName - The name of the pod to test.
|
|
57
|
+
* @param {string} options.podStatus - The status of the pod to test.
|
|
58
|
+
* @param {string} options.kindType - The type of the kind to test.
|
|
59
|
+
* @param {number} options.deltaMs - The delta time in milliseconds.
|
|
60
|
+
* @param {number} options.maxAttempts - The maximum number of attempts.
|
|
61
|
+
* @memberof UnderpostTest
|
|
62
|
+
*/
|
|
32
63
|
async callback(deployList = '', options = { itc: false, sh: false, logs: false }) {
|
|
33
64
|
if (
|
|
34
65
|
options.podName &&
|
|
@@ -86,6 +117,16 @@ class UnderpostTest {
|
|
|
86
117
|
}
|
|
87
118
|
} else return UnderpostTest.API.run();
|
|
88
119
|
},
|
|
120
|
+
/**
|
|
121
|
+
* @method statusMonitor
|
|
122
|
+
* @description Monitors the status of a pod.
|
|
123
|
+
* @param {string} podName - The name of the pod to monitor.
|
|
124
|
+
* @param {string} status - The status of the pod to monitor.
|
|
125
|
+
* @param {string} kindType - The type of the kind to monitor.
|
|
126
|
+
* @param {number} deltaMs - The delta time in milliseconds.
|
|
127
|
+
* @param {number} maxAttempts - The maximum number of attempts.
|
|
128
|
+
* @memberof UnderpostTest
|
|
129
|
+
*/
|
|
89
130
|
statusMonitor(podName, status = 'Running', kindType = '', deltaMs = 1000, maxAttempts = 60 * 5) {
|
|
90
131
|
if (!(kindType && typeof kindType === 'string')) kindType = 'pods';
|
|
91
132
|
return new Promise(async (resolve) => {
|
|
@@ -690,14 +690,6 @@ const scrollBarLightRender = () => {
|
|
|
690
690
|
.join('');
|
|
691
691
|
};
|
|
692
692
|
|
|
693
|
-
/**
|
|
694
|
-
* Adjust hex color brightness toward white/black ("mix") or by modifying HSL lightness ("hsl").
|
|
695
|
-
*
|
|
696
|
-
* @param {string} hex - Color as '#rrggbb', 'rrggbb', '#rgb', or 'rgb'.
|
|
697
|
-
* @param {number} factor - -1..1 or -100..100 (percent). Positive = lighten, negative = darken.
|
|
698
|
-
* @param {{mode?: 'mix'|'hsl'}} [options]
|
|
699
|
-
* @returns {string} - Adjusted color as '#rrggbb' (lowercase).
|
|
700
|
-
*/
|
|
701
693
|
function adjustHex(hex, factor = 0.1, options = {}) {
|
|
702
694
|
if (typeof hex !== 'string') throw new TypeError('hex must be a string');
|
|
703
695
|
if (typeof factor !== 'number') throw new TypeError('factor must be a number');
|
|
@@ -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;
|
package/src/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import UnderpostStartUp from './server/start.js';
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Underpost main module methods
|
|
28
|
-
* @class
|
|
28
|
+
* @class Underpost
|
|
29
29
|
* @memberof Underpost
|
|
30
30
|
*/
|
|
31
31
|
class Underpost {
|
|
@@ -35,7 +35,7 @@ class Underpost {
|
|
|
35
35
|
* @type {String}
|
|
36
36
|
* @memberof Underpost
|
|
37
37
|
*/
|
|
38
|
-
static version = 'v2.
|
|
38
|
+
static version = 'v2.81.0';
|
|
39
39
|
/**
|
|
40
40
|
* Repository cli API
|
|
41
41
|
* @static
|
|
@@ -27,6 +27,7 @@ const logger = loggerFactory(import.meta);
|
|
|
27
27
|
* @property {string} [host=''] - Application host for context.
|
|
28
28
|
* @property {string} [path=''] - Application path for context.
|
|
29
29
|
* @property {object.<string, string>} templates - Map of template keys to SSR component file names.
|
|
30
|
+
* @memberof MailerProviderNamespace
|
|
30
31
|
*/
|
|
31
32
|
|
|
32
33
|
/**
|