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
@@ -325,33 +325,13 @@ const validatePasswordMiddleware = (req) => {
325
325
  /**
326
326
  * Creates cookie options for the refresh token.
327
327
  * @param {import('express').Request} req The Express request object.
328
+ * @param {string} host The host name.
328
329
  * @returns {object} Cookie options.
329
330
  * @memberof Auth
330
331
  */
331
- const cookieOptionsFactory = (req) => {
332
+ const cookieOptionsFactory = (req, host) => {
332
333
  const isProduction = process.env.NODE_ENV === 'production';
333
334
 
334
- // Determine hostname safely:
335
- // Prefer origin header if present (it contains protocol + host)
336
- let candidateHost = undefined;
337
- try {
338
- if (req.headers && req.headers.origin) {
339
- candidateHost = new URL(req.headers.origin).hostname;
340
- }
341
- } catch (e) {
342
- /* ignore parse error */
343
- logger.error(e);
344
- }
345
-
346
- // fallback to req.hostname (Express sets this; ensure trust proxy if behind proxy)
347
- if (!candidateHost) candidateHost = (req.hostname || '').split(':')[0];
348
-
349
- candidateHost = (candidateHost || '').trim().replace(/^www\./i, '');
350
-
351
- // Do not set domain for localhost, 127.x.x.x, or plain IPs
352
- const isIpOrLocal = /^(localhost|127(?:\.\d+){0,2}\.\d+|\[::1\]|\d+\.\d+\.\d+\.\d+)$/i.test(candidateHost);
353
- const domain = isProduction && candidateHost && !isIpOrLocal ? `.${candidateHost}` : undefined;
354
-
355
335
  // Determine if request is secure: respect X-Forwarded-Proto when behind proxy
356
336
  const forwardedProto = (req.headers && req.headers['x-forwarded-proto']) || '';
357
337
  const reqIsSecure = Boolean(req.secure || forwardedProto.split(',')[0] === 'https');
@@ -361,17 +341,16 @@ const cookieOptionsFactory = (req) => {
361
341
  const sameSite = secure ? 'None' : 'Lax';
362
342
 
363
343
  // Safe parse of maxAge minutes
364
- const minutes = Number.parseInt(process.env.ACCESS_EXPIRE_MINUTES, 10);
365
- const maxAge = Number.isFinite(minutes) && minutes > 0 ? minutes * 60 * 1000 : undefined;
344
+ const maxAge = parseInt(process.env.ACCESS_EXPIRE_MINUTES) * 60 * 1000;
366
345
 
367
346
  const opts = {
368
347
  httpOnly: true,
369
348
  secure,
370
349
  sameSite,
371
350
  path: '/',
351
+ domain: process.env.NODE_ENV === 'production' ? host : 'localhost',
352
+ maxAge,
372
353
  };
373
- if (typeof maxAge !== 'undefined') opts.maxAge = maxAge;
374
- if (domain) opts.domain = domain;
375
354
 
376
355
  return opts;
377
356
  };
@@ -409,7 +388,7 @@ async function createSessionAndUserToken(user, User, req, res, options = { host:
409
388
  const jwtid = session._id.toString();
410
389
 
411
390
  // Secure cookie settings
412
- res.cookie('refreshToken', refreshToken, cookieOptionsFactory(req));
391
+ res.cookie('refreshToken', refreshToken, cookieOptionsFactory(req, options.host));
413
392
 
414
393
  return { jwtid };
415
394
  }
@@ -512,6 +491,7 @@ async function refreshSessionAndToken(req, res, User, options = { host: '', path
512
491
 
513
492
  if (!user) {
514
493
  // Possible token reuse: look up user by some other signals? If not possible, log and throw.
494
+ // TODO: on cors requests, this will throw an error, because the cookie is not sent.
515
495
  logger.warn('Refresh token reuse or invalid token detected');
516
496
  // Optional: revoke by clearing cookie and returning unauthorized
517
497
  res.clearCookie('refreshToken', { path: '/' });
@@ -543,7 +523,7 @@ async function refreshSessionAndToken(req, res, User, options = { host: '', path
543
523
 
544
524
  logger.warn('Refreshed session for user ' + user.email);
545
525
 
546
- res.cookie('refreshToken', refreshToken, cookieOptionsFactory(req));
526
+ res.cookie('refreshToken', refreshToken, cookieOptionsFactory(req, options.host));
547
527
 
548
528
  return jwtSign(
549
529
  UserDto.auth.payload(user, session._id.toString(), req.ip, req.headers['user-agent'], options.host, options.path),
@@ -663,6 +643,7 @@ function applySecurity(app, opts = {}) {
663
643
  maxAge: 600,
664
644
  }),
665
645
  );
646
+ logger.info('Cors origin', origin);
666
647
 
667
648
  // Rate limiting + slow down
668
649
  const limiter = rateLimit({
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Manages backup operations for deployments.
3
+ * @module src/server/backup.js
4
+ * @namespace BackUp
5
+ */
6
+
1
7
  import fs from 'fs-extra';
2
8
  import { loggerFactory } from './logger.js';
3
9
  import { shellExec } from './process.js';
@@ -8,7 +14,21 @@ dotenv.config();
8
14
 
9
15
  const logger = loggerFactory(import.meta);
10
16
 
17
+ /**
18
+ * @class BackUp
19
+ * @description Manages backup operations for deployments.
20
+ * @memberof BackUp
21
+ */
11
22
  class BackUp {
23
+ /**
24
+ * @method callback
25
+ * @description Initiates a backup operation for the specified deployment list.
26
+ * @param {string} deployList - The list of deployments to backup.
27
+ * @param {Object} options - The options for the backup operation.
28
+ * @param {boolean} options.itc - Whether to backup inside container data.
29
+ * @param {boolean} options.git - Whether to backup data using Git.
30
+ * @memberof BackUp
31
+ */
12
32
  static callback = async function (deployList, options = { itc: false, git: false }) {
13
33
  if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
14
34
  deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Module for live building client-side code
3
+ * @module src/server/client-build-live.js
4
+ * @namespace clientLiveBuild
5
+ */
6
+
1
7
  import fs from 'fs-extra';
2
8
  import { Config, loadConf } from './conf.js';
3
9
  import { loggerFactory } from './logger.js';
@@ -5,21 +11,28 @@ import { buildClient } from './client-build.js';
5
11
 
6
12
  const logger = loggerFactory(import.meta);
7
13
 
14
+ /**
15
+ * @function clientLiveBuild
16
+ * @description Initiates a live build of client-side code.
17
+ * @memberof clientLiveBuild
18
+ */
8
19
  const clientLiveBuild = async () => {
9
20
  if (fs.existsSync(`./tmp/client.build.json`)) {
10
21
  const deployId = process.argv[2];
11
-
22
+ const subConf = process.argv[3];
12
23
  let clientId = 'default';
13
24
  let host = 'default.net';
14
25
  let path = '/';
15
26
  let baseHost = `${host}${path === '/' ? '' : path}`;
16
27
  let views = Config.default.client[clientId].views;
28
+ let apiBaseHost;
29
+ let apiBaseProxyPath;
17
30
 
18
31
  if (
19
32
  deployId &&
20
33
  (fs.existsSync(`./engine-private/conf/${deployId}`) || fs.existsSync(`./engine-private/replica/${deployId}`))
21
34
  ) {
22
- loadConf(deployId);
35
+ loadConf(deployId, subConf);
23
36
  const confClient = JSON.parse(
24
37
  fs.readFileSync(
25
38
  fs.existsSync(`./engine-private/replica/${deployId}`)
@@ -31,29 +44,27 @@ const clientLiveBuild = async () => {
31
44
  ),
32
45
  );
33
46
  const confServer = JSON.parse(
34
- fs.readFileSync(
35
- fs.existsSync(`./engine-private/replica/${deployId}`)
36
- ? `./engine-private/replica/${deployId}/conf.server.json`
37
- : fs.existsSync(`./engine-private/conf/${deployId}/conf.server.json`)
38
- ? `./engine-private/conf/${deployId}/conf.server.json`
39
- : `./conf/conf.server.json`,
40
- 'utf8',
41
- ),
47
+ fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`, 'utf8'),
42
48
  );
43
- host = process.argv[3];
44
- path = process.argv[4];
49
+ host = process.argv[4];
50
+ path = process.argv[5];
45
51
  clientId = confServer[host][path].client;
46
52
  views = confClient[clientId].views;
47
53
  baseHost = `${host}${path === '/' ? '' : path}`;
54
+ apiBaseHost = confServer[host][path].apiBaseHost;
55
+ apiBaseProxyPath = confServer[host][path].apiBaseProxyPath;
48
56
  }
49
57
 
50
58
  logger.info('Live build config', {
51
59
  deployId,
60
+ subConf,
52
61
  host,
53
62
  path,
54
63
  clientId,
55
64
  baseHost,
56
65
  views: views.length,
66
+ apiBaseHost,
67
+ apiBaseProxyPath,
57
68
  });
58
69
 
59
70
  const updates = JSON.parse(fs.readFileSync(`./tmp/client.build.json`, 'utf8'));
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Manages the client-side build process, including full builds and incremental builds.
3
+ * @module server/client-build.js
4
+ * @namespace clientBuild
5
+ */
6
+
1
7
  'use strict';
2
8
 
3
9
  import fs from 'fs-extra';
@@ -26,97 +32,17 @@ dotenv.config();
26
32
 
27
33
  // Static Site Generation (SSG)
28
34
 
29
- const buildAcmeChallengePath = (acmeChallengeFullPath = '') => {
30
- fs.mkdirSync(acmeChallengeFullPath, {
31
- recursive: true,
32
- });
33
- fs.writeFileSync(`${acmeChallengeFullPath}/.gitkeep`, '', 'utf8');
34
- };
35
-
36
- const fullBuild = async ({
37
- path,
38
- logger,
39
- client,
40
- db,
41
- dists,
42
- rootClientPath,
43
- acmeChallengeFullPath,
44
- publicClientId,
45
- iconsBuild,
46
- metadata,
47
- }) => {
48
- logger.warn('Full build', rootClientPath);
49
-
50
- buildAcmeChallengePath(acmeChallengeFullPath);
51
-
52
- if (publicClientId && publicClientId.startsWith('html-website-templates')) {
53
- if (!fs.existsSync(`/home/dd/html-website-templates/`))
54
- shellExec(`cd /home/dd && git clone https://github.com/designmodo/html-website-templates.git`);
55
- if (!fs.existsSync(`${rootClientPath}/index.php`)) {
56
- fs.copySync(`/home/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
57
- shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
58
- // git remote add origin git@github.com:<username>/<repo>.git
59
- fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
60
- }
61
- return;
62
- }
63
-
64
- fs.removeSync(rootClientPath);
65
-
66
- if (fs.existsSync(`./src/client/public/${publicClientId}`)) {
67
- if (iconsBuild === true) await buildIcons({ publicClientId, metadata });
68
-
69
- fs.copySync(
70
- `./src/client/public/${publicClientId}`,
71
- rootClientPath /* {
72
- filter: function (name) {
73
- console.log(name);
74
- return true;
75
- },
76
- } */,
77
- );
78
- } else if (fs.existsSync(`./engine-private/src/client/public/${publicClientId}`)) {
79
- switch (publicClientId) {
80
- case 'mysql_test':
81
- if (db) {
82
- fs.copySync(`./engine-private/src/client/public/${publicClientId}`, rootClientPath);
83
- fs.writeFileSync(
84
- `${rootClientPath}/index.php`,
85
- fs
86
- .readFileSync(`${rootClientPath}/index.php`, 'utf8')
87
- .replace('test_servername', 'localhost')
88
- .replace('test_username', db.user)
89
- .replace('test_password', db.password)
90
- .replace('test_dbname', db.name),
91
- 'utf8',
92
- );
93
- } else logger.error('not provided db config');
94
- break;
95
-
96
- default:
97
- break;
98
- }
99
- }
100
- if (dists)
101
- for (const dist of dists) {
102
- if ('folder' in dist) {
103
- if (fs.statSync(dist.folder).isDirectory()) {
104
- fs.mkdirSync(`${rootClientPath}${dist.public_folder}`, { recursive: true });
105
- fs.copySync(dist.folder, `${rootClientPath}${dist.public_folder}`);
106
- } else {
107
- const folder = dist.public_folder.split('/');
108
- folder.pop();
109
- fs.mkdirSync(`${rootClientPath}${folder.join('/')}`, { recursive: true });
110
- fs.copyFileSync(dist.folder, `${rootClientPath}${dist.public_folder}`);
111
- }
112
- }
113
- if ('styles' in dist) {
114
- fs.mkdirSync(`${rootClientPath}${dist.public_styles_folder}`, { recursive: true });
115
- fs.copySync(dist.styles, `${rootClientPath}${dist.public_styles_folder}`);
116
- }
117
- }
118
- };
119
-
35
+ /**
36
+ * @async
37
+ * @function buildClient
38
+ * @memberof clientBuild
39
+ * @param {Object} options - Options for the build process.
40
+ * @param {Array} options.liveClientBuildPaths - List of paths to build incrementally.
41
+ * @param {Array} options.instances - List of instances to build.
42
+ * @returns {Promise<void>} - Promise that resolves when the build is complete.
43
+ * @throws {Error} - If the build fails.
44
+ * @memberof clientBuild
45
+ */
120
46
  const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }) => {
121
47
  const logger = loggerFactory(import.meta);
122
48
  const confClient = JSON.parse(fs.readFileSync(`./conf/conf.client.json`, 'utf8'));
@@ -126,6 +52,125 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
126
52
  const acmeChallengePath = `/.well-known/acme-challenge`;
127
53
  const publicPath = `./public`;
128
54
 
55
+ /**
56
+ * @async
57
+ * @function buildAcmeChallengePath
58
+ * @memberof clientBuild
59
+ * @param {string} acmeChallengeFullPath - Full path to the acme-challenge directory.
60
+ * @returns {void}
61
+ * @throws {Error} - If the directory cannot be created.
62
+ * @memberof clientBuild
63
+ */
64
+ const buildAcmeChallengePath = (acmeChallengeFullPath = '') => {
65
+ fs.mkdirSync(acmeChallengeFullPath, {
66
+ recursive: true,
67
+ });
68
+ fs.writeFileSync(`${acmeChallengeFullPath}/.gitkeep`, '', 'utf8');
69
+ };
70
+
71
+ /**
72
+ * @async
73
+ * @function fullBuild
74
+ * @memberof clientBuild
75
+ * @param {Object} options - Options for the full build process.
76
+ * @param {string} options.path - Path to the client directory.
77
+ * @param {Object} options.logger - Logger instance.
78
+ * @param {string} options.client - Client name.
79
+ * @param {Object} options.db - Database configuration.
80
+ * @param {Array} options.dists - List of distributions to build.
81
+ * @param {string} options.rootClientPath - Full path to the client directory.
82
+ * @param {string} options.acmeChallengeFullPath - Full path to the acme-challenge directory.
83
+ * @param {string} options.publicClientId - Public client ID.
84
+ * @param {boolean} options.iconsBuild - Whether to build icons.
85
+ * @param {Object} options.metadata - Metadata for the client.
86
+ * @returns {Promise<void>} - Promise that resolves when the full build is complete.
87
+ * @throws {Error} - If the full build fails.
88
+ * @memberof clientBuild
89
+ */
90
+ const fullBuild = async ({
91
+ path,
92
+ logger,
93
+ client,
94
+ db,
95
+ dists,
96
+ rootClientPath,
97
+ acmeChallengeFullPath,
98
+ publicClientId,
99
+ iconsBuild,
100
+ metadata,
101
+ }) => {
102
+ logger.warn('Full build', rootClientPath);
103
+
104
+ buildAcmeChallengePath(acmeChallengeFullPath);
105
+
106
+ if (publicClientId && publicClientId.startsWith('html-website-templates')) {
107
+ if (!fs.existsSync(`/home/dd/html-website-templates/`))
108
+ shellExec(`cd /home/dd && git clone https://github.com/designmodo/html-website-templates.git`);
109
+ if (!fs.existsSync(`${rootClientPath}/index.php`)) {
110
+ fs.copySync(`/home/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
111
+ shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
112
+ // git remote add origin git@github.com:<username>/<repo>.git
113
+ fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
114
+ }
115
+ return;
116
+ }
117
+
118
+ fs.removeSync(rootClientPath);
119
+
120
+ if (fs.existsSync(`./src/client/public/${publicClientId}`)) {
121
+ if (iconsBuild === true) await buildIcons({ publicClientId, metadata });
122
+
123
+ fs.copySync(
124
+ `./src/client/public/${publicClientId}`,
125
+ rootClientPath /* {
126
+ filter: function (name) {
127
+ console.log(name);
128
+ return true;
129
+ },
130
+ } */,
131
+ );
132
+ } else if (fs.existsSync(`./engine-private/src/client/public/${publicClientId}`)) {
133
+ switch (publicClientId) {
134
+ case 'mysql_test':
135
+ if (db) {
136
+ fs.copySync(`./engine-private/src/client/public/${publicClientId}`, rootClientPath);
137
+ fs.writeFileSync(
138
+ `${rootClientPath}/index.php`,
139
+ fs
140
+ .readFileSync(`${rootClientPath}/index.php`, 'utf8')
141
+ .replace('test_servername', 'localhost')
142
+ .replace('test_username', db.user)
143
+ .replace('test_password', db.password)
144
+ .replace('test_dbname', db.name),
145
+ 'utf8',
146
+ );
147
+ } else logger.error('not provided db config');
148
+ break;
149
+
150
+ default:
151
+ break;
152
+ }
153
+ }
154
+ if (dists)
155
+ for (const dist of dists) {
156
+ if ('folder' in dist) {
157
+ if (fs.statSync(dist.folder).isDirectory()) {
158
+ fs.mkdirSync(`${rootClientPath}${dist.public_folder}`, { recursive: true });
159
+ fs.copySync(dist.folder, `${rootClientPath}${dist.public_folder}`);
160
+ } else {
161
+ const folder = dist.public_folder.split('/');
162
+ folder.pop();
163
+ fs.mkdirSync(`${rootClientPath}${folder.join('/')}`, { recursive: true });
164
+ fs.copyFileSync(dist.folder, `${rootClientPath}${dist.public_folder}`);
165
+ }
166
+ }
167
+ if ('styles' in dist) {
168
+ fs.mkdirSync(`${rootClientPath}${dist.public_styles_folder}`, { recursive: true });
169
+ fs.copySync(dist.styles, `${rootClientPath}${dist.public_styles_folder}`);
170
+ }
171
+ }
172
+ };
173
+
129
174
  // { srcBuildPath, publicBuildPath }
130
175
  const enableLiveRebuild =
131
176
  options && options.liveClientBuildPaths && options.liveClientBuildPaths.length > 0 ? true : false;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Module for creating a client-side development server
3
+ * @module src/server/client-dev-server.js
4
+ * @namespace clientDevServer
5
+ */
1
6
  import fs from 'fs-extra';
2
7
  import nodemon from 'nodemon';
3
8
  import { shellExec } from './process.js';
@@ -5,14 +10,32 @@ import { loggerFactory } from './logger.js';
5
10
 
6
11
  const logger = loggerFactory(import.meta);
7
12
 
8
- const createClientDevServer = () => {
9
- // process.argv.slice(2).join(' ')
10
- shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')}`);
13
+ /**
14
+ * @function createClientDevServer
15
+ * @description Creates a client-side development server.
16
+ * @memberof clientDevServer
17
+ * @param {string} deployId - The deployment ID.
18
+ * @param {string} subConf - The sub-configuration.
19
+ * @param {string} host - The host.
20
+ * @param {string} path - The path.
21
+ * @returns {void}
22
+ * @memberof clientDevServer
23
+ */
24
+ const createClientDevServer = (
25
+ deployId = process.argv[2] || 'dd-default',
26
+ subConf = process.argv[3] || '',
27
+ host = process.argv[4] || 'default.net',
28
+ path = process.argv[5] || '/',
29
+ ) => {
11
30
  shellExec(
12
- `env-cmd -f .env.development node src/api ${process.argv[2]}${process.argv[5] ? ` ${process.argv[5]}` : ''}${
13
- process.argv.includes('static') ? ' static' : ''
14
- }`,
15
- { async: true },
31
+ `env-cmd -f ./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-client node bin/deploy build-full-client ${deployId} ${subConf}-dev-client ${host} ${path}`.trim(),
32
+ );
33
+
34
+ shellExec(
35
+ `env-cmd -f ./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-client node src/server ${deployId} ${subConf}-dev-client`.trim(),
36
+ {
37
+ async: true,
38
+ },
16
39
  );
17
40
 
18
41
  // https://github.com/remy/nodemon/blob/main/doc/events.md
@@ -28,7 +51,11 @@ const createClientDevServer = () => {
28
51
 
29
52
  let buildPathScope = [];
30
53
 
31
- const nodemonOptions = { script: './src/client.build', args: process.argv.slice(2), watch: 'src/client' };
54
+ const nodemonOptions = {
55
+ script: './src/client.build',
56
+ args: [`${deployId}`, `${subConf}-dev-client`, `${host}`, `${path}`],
57
+ watch: 'src/client',
58
+ };
32
59
  logger.info('nodemon option', { nodemonOptions });
33
60
  nodemon(nodemonOptions)
34
61
  .on('start', function (...args) {
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Module for building client-side icons
3
+ * @module src/server/client-icons.js
4
+ * @namespace clientIcons
5
+ */
1
6
  import { favicons } from 'favicons';
2
7
  import { loggerFactory } from './logger.js';
3
8
  import fs from 'fs-extra';
@@ -5,6 +10,20 @@ import { getCapVariableName } from '../client/components/core/CommonJs.js';
5
10
 
6
11
  const logger = loggerFactory(import.meta);
7
12
 
13
+ /**
14
+ * @function buildIcons
15
+ * @description Builds icons for a client-side application.
16
+ * @memberof clientIcons
17
+ * @param {Object} metadata - The metadata for the client-side application.
18
+ * @param {string} metadata.title - The title of the client-side application.
19
+ * @param {string} metadata.description - The description of the client-side application.
20
+ * @param {string} metadata.keywords - The keywords for the client-side application.
21
+ * @param {string} metadata.author - The author of the client-side application.
22
+ * @param {string} metadata.thumbnail - The thumbnail of the client-side application.
23
+ * @param {string} metadata.themeColor - The theme color of the client-side application.
24
+ * @param {string} metadata.baseBuildIconReference - The base build icon reference for the client-side application.
25
+ * @returns {Promise<void>}
26
+ */
8
27
  const buildIcons = async ({
9
28
  publicClientId,
10
29
  metadata: { title, description, keywords, author, thumbnail, themeColor, baseBuildIconReference },