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.
Files changed (72) 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/.vscode/zed.keymap.json +17 -0
  8. package/.vscode/zed.settings.json +20 -0
  9. package/CHANGELOG.md +145 -1
  10. package/Dockerfile +20 -3
  11. package/README.md +6 -6
  12. package/bin/build.js +18 -9
  13. package/bin/deploy.js +130 -195
  14. package/bin/zed.js +20 -0
  15. package/cli.md +13 -7
  16. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  17. package/manifests/deployment/dd-test-development/deployment.yaml +50 -50
  18. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  19. package/manifests/lxd/underpost-setup.sh +5 -5
  20. package/package.json +3 -4
  21. package/{manifests/maas → scripts}/ssh-cluster-info.sh +1 -1
  22. package/scripts/ssl.sh +164 -0
  23. package/src/cli/baremetal.js +8 -8
  24. package/src/cli/cloud-init.js +1 -1
  25. package/src/cli/cluster.js +15 -4
  26. package/src/cli/cron.js +1 -1
  27. package/src/cli/db.js +2 -1
  28. package/src/cli/deploy.js +65 -14
  29. package/src/cli/fs.js +2 -2
  30. package/src/cli/image.js +19 -2
  31. package/src/cli/index.js +11 -4
  32. package/src/cli/monitor.js +34 -1
  33. package/src/cli/repository.js +42 -1
  34. package/src/cli/run.js +396 -86
  35. package/src/cli/script.js +32 -0
  36. package/src/cli/secrets.js +34 -0
  37. package/src/cli/test.js +42 -1
  38. package/src/client/components/core/Css.js +0 -8
  39. package/src/client/components/core/windowGetDimensions.js +229 -162
  40. package/src/index.js +2 -2
  41. package/src/mailer/MailerProvider.js +1 -0
  42. package/src/runtime/express/Dockerfile +41 -0
  43. package/src/runtime/express/Express.js +12 -4
  44. package/src/runtime/lampp/Dockerfile +1 -1
  45. package/src/server/backup.js +20 -0
  46. package/src/server/client-build-live.js +12 -10
  47. package/src/server/client-build.js +136 -91
  48. package/src/server/client-dev-server.js +16 -2
  49. package/src/server/client-icons.js +19 -0
  50. package/src/server/conf.js +495 -69
  51. package/src/server/dns.js +169 -46
  52. package/src/server/downloader.js +65 -24
  53. package/src/server/object-layer.js +260 -162
  54. package/src/server/peer.js +2 -8
  55. package/src/server/proxy.js +93 -76
  56. package/src/server/runtime.js +15 -16
  57. package/src/server/ssr.js +4 -4
  58. package/src/server/tls.js +251 -0
  59. package/src/server/valkey.js +11 -10
  60. package/src/ws/IoInterface.js +2 -1
  61. package/src/ws/IoServer.js +2 -1
  62. package/src/ws/core/core.ws.connection.js +1 -1
  63. package/src/ws/core/core.ws.emit.js +1 -1
  64. package/src/ws/core/core.ws.server.js +1 -1
  65. package/manifests/maas/lxd-preseed.yaml +0 -32
  66. package/src/server/ssl.js +0 -108
  67. /package/{manifests/maas → scripts}/device-scan.sh +0 -0
  68. /package/{manifests/maas → scripts}/gpu-diag.sh +0 -0
  69. /package/{manifests/maas → scripts}/maas-setup.sh +0 -0
  70. /package/{manifests/maas → scripts}/nat-iptables.sh +0 -0
  71. /package/{manifests/maas → scripts}/nvim.sh +0 -0
  72. /package/{manifests/maas → scripts}/snap-clean.sh +0 -0
@@ -1,9 +1,17 @@
1
+ /**
2
+ * Provides utilities for building, loading, and managing server configurations,
3
+ * deployment contexts, and service configurations (API, Client, WS).
4
+ * @module src/server/conf.js
5
+ * @namespace ServerConfBuilder
6
+ */
7
+
1
8
  import fs from 'fs-extra';
2
9
  import dotenv from 'dotenv';
3
10
  import {
4
11
  capFirst,
5
12
  getCapVariableName,
6
13
  newInstance,
14
+ orderAbc,
7
15
  orderArrayFromAttrInt,
8
16
  range,
9
17
  timer,
@@ -22,18 +30,45 @@ dotenv.config();
22
30
 
23
31
  const logger = loggerFactory(import.meta);
24
32
 
33
+ /**
34
+ * @class Config
35
+ * @description Manages the configuration of the server.
36
+ * This class provides a set of static methods to automate various
37
+ * infrastructure operations, including NFS management, control server setup,
38
+ * and system provisioning for different architectures.
39
+ * @memberof ServerConfBuilder
40
+ */
25
41
  const Config = {
42
+ /**
43
+ * @method default
44
+ * @description The default configuration of the server.
45
+ * @memberof ServerConfBuilder
46
+ */
26
47
  default: DefaultConf,
48
+ /**
49
+ * @method build
50
+ * @description Builds the configuration of the server.
51
+ * @param {string} [deployContext='dd-default'] - The deploy context.
52
+ * @param {string} [deployList=''] - The deploy list.
53
+ * @param {string} [subConf=''] - The sub configuration.
54
+ * @memberof ServerConfBuilder
55
+ */
27
56
  build: async function (deployContext = 'dd-default', deployList, subConf) {
28
57
  if (process.argv[2] && typeof process.argv[2] === 'string' && process.argv[2].startsWith('dd-'))
29
58
  deployContext = process.argv[2];
30
59
  if (!subConf && process.argv[3] && typeof process.argv[3] === 'string') subConf = process.argv[3];
31
60
  if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
32
61
  UnderpostRootEnv.API.set('await-deploy', new Date().toISOString());
33
- if (fs.existsSync(`./engine-private/replica/${deployContext}`)) return loadConf(deployContext, subConf);
34
- else if (deployContext.startsWith('dd-')) return loadConf(deployContext, subConf);
35
- if (deployContext === 'proxy') Config.buildProxy(deployList, subConf);
62
+ if (deployContext.startsWith('dd-')) loadConf(deployContext, subConf);
63
+ if (deployContext === 'proxy') await Config.buildProxy(deployList, subConf);
36
64
  },
65
+ /**
66
+ * @method deployIdFactory
67
+ * @description Creates a new deploy ID.
68
+ * @param {string} [deployId='dd-default'] - The deploy ID.
69
+ * @param {object} [options={ cluster: false }] - The options.
70
+ * @memberof ServerConfBuilder
71
+ */
37
72
  deployIdFactory: function (deployId = 'dd-default', options = { cluster: false }) {
38
73
  if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
39
74
 
@@ -102,43 +137,74 @@ const Config = {
102
137
 
103
138
  return { deployIdFolder: folder, deployId };
104
139
  },
140
+ /**
141
+ * @method buildTmpConf
142
+ * @description Builds the temporary configuration of the server.
143
+ * @param {string} [folder='./conf'] - The folder.
144
+ * @memberof ServerConfBuilder
145
+ */
105
146
  buildTmpConf: function (folder = './conf') {
106
147
  for (const confType of Object.keys(this.default))
107
148
  fs.writeFileSync(`${folder}/conf.${confType}.json`, JSON.stringify(this.default[confType], null, 4), 'utf8');
108
149
  },
109
- buildProxy: function (deployList = 'dd-default', subConf = '') {
150
+ /**
151
+ * @method buildProxyByDeployId
152
+ * @description Builds the proxy by deploy ID.
153
+ * @param {string} [deployId='dd-default'] - The deploy ID.
154
+ * @param {string} [subConf=''] - The sub configuration.
155
+ * @memberof ServerConfBuilder
156
+ */
157
+ buildProxyByDeployId: function (deployId = 'dd-default', subConf = '') {
158
+ let confPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
159
+ ? `./engine-private/replica/${deployId}/conf.server.json`
160
+ : `./engine-private/conf/${deployId}/conf.server.json`;
161
+
162
+ if (
163
+ process.env.NODE_ENV === 'development' &&
164
+ subConf &&
165
+ fs.existsSync(`./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`)
166
+ )
167
+ confPath = `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
168
+
169
+ const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
170
+
171
+ for (const host of Object.keys(loadReplicas(deployId, serverConf)))
172
+ this.default.server[host] = {
173
+ ...this.default.server[host],
174
+ ...serverConf[host],
175
+ };
176
+ },
177
+ /**
178
+ * @method buildProxy
179
+ * @description Builds the proxy.
180
+ * @param {string} [deployList='dd-default'] - The deploy list.
181
+ * @param {string} [subConf=''] - The sub configuration.
182
+ * @memberof ServerConfBuilder
183
+ */
184
+ buildProxy: async function (deployList = 'dd-default', subConf = '') {
110
185
  if (!deployList) deployList = process.argv[3];
111
186
  if (!subConf) subConf = process.argv[4];
112
187
  this.default.server = {};
113
188
  for (const deployId of deployList.split(',')) {
114
- let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
115
- const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
116
- ? `./engine-private/replica/${deployId}/conf.server.json`
117
- : `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
118
- const confDevPath = fs.existsSync(privateConfDevPath)
119
- ? privateConfDevPath
120
- : `./engine-private/conf/${deployId}/conf.server.dev.json`;
121
-
122
- if (process.env.NODE_ENV === 'development' && fs.existsSync(confDevPath)) confPath = confDevPath;
123
- const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
124
-
125
- for (const host of Object.keys(loadReplicas(serverConf))) {
126
- if (serverConf[host]['/'])
127
- this.default.server[host] = {
128
- ...this.default.server[host],
129
- ...serverConf[host],
130
- };
131
- else
132
- this.default.server[host] = {
133
- ...serverConf[host],
134
- ...this.default.server[host],
135
- };
189
+ this.buildProxyByDeployId(deployId, subConf);
190
+ if (fs.existsSync(`./engine-private/replica`)) {
191
+ const singleReplicas = await fs.readdir(`./engine-private/replica`);
192
+ for (let replica of singleReplicas) {
193
+ if (replica.startsWith(deployId)) this.buildProxyByDeployId(replica, subConf);
194
+ }
136
195
  }
137
196
  }
138
197
  this.buildTmpConf();
139
198
  },
140
199
  };
141
200
 
201
+ /**
202
+ * @method loadConf
203
+ * @description Loads the configuration of the server.
204
+ * @param {string} [deployId='dd-default'] - The deploy ID.
205
+ * @param {string} [subConf=''] - The sub configuration.
206
+ * @memberof ServerConfBuilder
207
+ */
142
208
  const loadConf = (deployId = 'dd-default', subConf) => {
143
209
  if (deployId === 'current') {
144
210
  console.log(process.env.DEPLOY_ID);
@@ -164,11 +230,11 @@ const loadConf = (deployId = 'dd-default', subConf) => {
164
230
 
165
231
  for (const typeConf of Object.keys(Config.default)) {
166
232
  let srcConf = fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8');
167
- if (process.env.NODE_ENV === 'development' && typeConf === 'server') {
233
+ if (process.env.NODE_ENV === 'development' && typeConf === 'server' && subConf) {
168
234
  const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
169
235
  if (fs.existsSync(devConfPath)) srcConf = fs.readFileSync(devConfPath, 'utf8');
170
236
  }
171
- if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(JSON.parse(srcConf)), null, 4);
237
+ if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(deployId, JSON.parse(srcConf)), null, 4);
172
238
  fs.writeFileSync(`./conf/conf.${typeConf}.json`, srcConf, 'utf8');
173
239
  }
174
240
  fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
@@ -194,22 +260,47 @@ const loadConf = (deployId = 'dd-default', subConf) => {
194
260
  return { folder, deployId };
195
261
  };
196
262
 
197
- const loadReplicas = (confServer) => {
263
+ /**
264
+ * @method loadReplicas
265
+ * @description Loads the replicas of the server.
266
+ * @param {object} confServer - The server configuration.
267
+ * @memberof ServerConfBuilder
268
+ */
269
+ const loadReplicas = (deployId, confServer) => {
270
+ const confServerOrigin = newInstance(confServer);
198
271
  for (const host of Object.keys(confServer)) {
199
272
  for (const path of Object.keys(confServer[host])) {
200
273
  const { replicas, singleReplica } = confServer[host][path];
201
- if (replicas && !singleReplica)
202
- for (const replicaPath of replicas) {
203
- {
204
- confServer[host][replicaPath] = newInstance(confServer[host][path]);
205
- delete confServer[host][replicaPath].replicas;
274
+ if (replicas) {
275
+ if (!singleReplica)
276
+ for (const replicaPath of replicas) {
277
+ {
278
+ confServer[host][replicaPath] = newInstance(confServer[host][path]);
279
+ delete confServer[host][replicaPath].replicas;
280
+ }
206
281
  }
282
+ else {
283
+ const orderReplica = orderAbc(confServerOrigin[host][path].replicas);
284
+ confServerOrigin[host][path].replicas = orderReplica;
285
+ confServer[host][path].replicas = orderReplica;
207
286
  }
287
+ }
208
288
  }
209
289
  }
290
+ const serverPath = `./engine-private/conf/${deployId}/conf.server${process.env.NODE_ENV === 'production' ? '' : '.dev'}.json`;
291
+ if (fs.existsSync(serverPath)) fs.writeFileSync(serverPath, JSON.stringify(confServerOrigin, null, 4), 'utf8');
292
+
210
293
  return confServer;
211
294
  };
212
295
 
296
+ /**
297
+ * @method cloneConf
298
+ * @description Clones the configuration of the server.
299
+ * @param {object} toOptions - The options for the target configuration.
300
+ * @param {object} fromOptions - The options for the source configuration.
301
+ * @param {object} [fromDefaultOptions={ deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
302
+ * @memberof ServerConfBuilder
303
+ */
213
304
  const cloneConf = async (
214
305
  { toOptions, fromOptions },
215
306
  fromDefaultOptions = { deployId: 'dd-default', clientId: 'default' },
@@ -253,6 +344,14 @@ const cloneConf = async (
253
344
  fs.writeFileSync(`${confToFolder}/package.json`, JSON.stringify(packageData, null, 4), 'utf8');
254
345
  };
255
346
 
347
+ /**
348
+ * @method addClientConf
349
+ * @description Adds the client configuration to the server.
350
+ * @param {object} toOptions - The options for the target configuration.
351
+ * @param {object} fromOptions - The options for the source configuration.
352
+ * @param {object} [fromDefaultOptions={ deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
353
+ * @memberof ServerConfBuilder
354
+ */
256
355
  const addClientConf = async (
257
356
  { toOptions, fromOptions },
258
357
  fromDefaultOptions = { deployId: 'dd-default', clientId: 'default' },
@@ -292,6 +391,14 @@ const addClientConf = async (
292
391
  fs.writeFileSync(`${confToFolder}/conf.ssr.json`, JSON.stringify(toSsrConf, null, 4), 'utf8');
293
392
  };
294
393
 
394
+ /**
395
+ * @method buildClientSrc
396
+ * @description Builds the client source code.
397
+ * @param {object} toOptions - The options for the target configuration.
398
+ * @param {object} fromOptions - The options for the source configuration.
399
+ * @param {object} [fromDefaultOptions={ deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
400
+ * @memberof ServerConfBuilder
401
+ */
295
402
  const buildClientSrc = async (
296
403
  { toOptions, fromOptions },
297
404
  fromDefaultOptions = { deployId: 'dd-default', clientId: 'default' },
@@ -334,6 +441,14 @@ const buildClientSrc = async (
334
441
  fs.copySync(`./src/client/public/${fromOptions.clientId}`, `./src/client/public/${toOptions.clientId}`);
335
442
  };
336
443
 
444
+ /**
445
+ * @method buildApiSrc
446
+ * @description Builds the API source code.
447
+ * @param {object} toOptions - The options for the target configuration.
448
+ * @param {object} fromOptions - The options for the source configuration.
449
+ * @param {object} [fromDefaultOptions={ apiId: 'default', deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
450
+ * @memberof ServerConfBuilder
451
+ */
337
452
  const buildApiSrc = async (
338
453
  { toOptions, fromOptions },
339
454
  fromDefaultOptions = { apiId: 'default', deployId: 'dd-default', clientId: 'default' },
@@ -371,17 +486,16 @@ const buildApiSrc = async (
371
486
  ),
372
487
  'utf8',
373
488
  );
374
- return;
375
- if (fs.existsSync(`./src/client/services/${fromOptions.apiId}/${fromOptions.apiId}.management.js`))
376
- fs.writeFileSync(
377
- `./src/client/services/${toOptions.apiId}/${toOptions.apiId}.management.js`,
378
- formattedSrc(
379
- fs.readFileSync(`./src/client/services/${fromOptions.apiId}/${fromOptions.apiId}.management.js`, 'utf8'),
380
- ),
381
- 'utf8',
382
- );
383
489
  };
384
490
 
491
+ /**
492
+ * @method addApiConf
493
+ * @description Adds the API configuration to the server.
494
+ * @param {object} toOptions - The options for the target configuration.
495
+ * @param {object} fromOptions - The options for the source configuration.
496
+ * @param {object} [fromDefaultOptions={ apiId: 'default', deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
497
+ * @memberof ServerConfBuilder
498
+ */
385
499
  const addApiConf = async (
386
500
  { toOptions, fromOptions },
387
501
  fromDefaultOptions = { apiId: 'default', deployId: 'dd-default', clientId: 'default' },
@@ -407,6 +521,14 @@ const addApiConf = async (
407
521
  fs.writeFileSync(`${confToFolder}/conf.client.json`, JSON.stringify(confClient, null, 4), 'utf8');
408
522
  };
409
523
 
524
+ /**
525
+ * @method addWsConf
526
+ * @description Adds the WebSocket configuration to the server.
527
+ * @param {object} toOptions - The options for the target configuration.
528
+ * @param {object} fromOptions - The options for the source configuration.
529
+ * @param {object} [fromDefaultOptions={ wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' }] - The default options for the source configuration.
530
+ * @memberof ServerConfBuilder
531
+ */
410
532
  const addWsConf = async (
411
533
  { toOptions, fromOptions },
412
534
  fromDefaultOptions = { wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' },
@@ -432,6 +554,14 @@ const addWsConf = async (
432
554
  fs.writeFileSync(`${confToFolder}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
433
555
  };
434
556
 
557
+ /**
558
+ * @method buildWsSrc
559
+ * @description Builds the WebSocket source code.
560
+ * @param {object} toOptions - The options for the target configuration.
561
+ * @param {object} fromOptions - The options for the source configuration.
562
+ * @param {object} [fromDefaultOptions={ wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' }] - The default options for the source configuration.
563
+ * @memberof ServerConfBuilder
564
+ */
435
565
  const buildWsSrc = async (
436
566
  { toOptions, fromOptions },
437
567
  fromDefaultOptions = { wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' },
@@ -466,6 +596,13 @@ const buildWsSrc = async (
466
596
  }
467
597
  };
468
598
 
599
+ /**
600
+ * @method cloneSrcComponents
601
+ * @description Clones the source components.
602
+ * @param {object} toOptions - The options for the target configuration.
603
+ * @param {object} fromOptions - The options for the source configuration.
604
+ * @memberof ServerConfBuilder
605
+ */
469
606
  const cloneSrcComponents = async ({ toOptions, fromOptions }) => {
470
607
  const toClientVariableName = getCapVariableName(toOptions.componentsFolder);
471
608
  const fromClientVariableName = getCapVariableName(fromOptions.componentsFolder);
@@ -489,24 +626,25 @@ const cloneSrcComponents = async ({ toOptions, fromOptions }) => {
489
626
  }
490
627
  };
491
628
 
629
+ /**
630
+ * @method buildProxyRouter
631
+ * @description Builds the proxy router.
632
+ * @memberof ServerConfBuilder
633
+ */
492
634
  const buildProxyRouter = () => {
493
635
  const confServer = JSON.parse(fs.readFileSync(`./conf/conf.server.json`, 'utf8'));
494
636
  let currentPort = parseInt(process.env.PORT) + 1;
495
637
  const proxyRouter = {};
496
- const singleReplicaHosts = [];
497
638
  for (const host of Object.keys(confServer)) {
498
639
  for (const path of Object.keys(confServer[host])) {
499
- if (confServer[host][path].singleReplica && !singleReplicaHosts.includes(host)) {
500
- singleReplicaHosts.push(host);
501
- currentPort++;
502
- continue;
503
- }
640
+ if (confServer[host][path].singleReplica) continue;
641
+
504
642
  confServer[host][path].port = newInstance(currentPort);
505
643
  for (const port of confServer[host][path].proxy) {
506
644
  if (!(port in proxyRouter)) proxyRouter[port] = {};
507
645
  proxyRouter[port][`${host}${path}`] = {
508
646
  // target: `http://${host}:${confServer[host][path].port}${path}`,
509
- target: `http://localhost:${confServer[host][path].port - singleReplicaHosts.length}`,
647
+ target: `http://localhost:${confServer[host][path].port}`,
510
648
  // target: `http://127.0.0.1:${confServer[host][path].port}`,
511
649
  proxy: confServer[host][path].proxy,
512
650
  redirect: confServer[host][path].redirect,
@@ -523,7 +661,7 @@ const buildProxyRouter = () => {
523
661
  if (!(port in proxyRouter)) proxyRouter[port] = {};
524
662
  proxyRouter[port][`${host}${peerPath}`] = {
525
663
  // target: `http://${host}:${confServer[host][peerPath].port}${peerPath}`,
526
- target: `http://localhost:${confServer[host][peerPath].port - singleReplicaHosts.length}`,
664
+ target: `http://localhost:${confServer[host][peerPath].port}`,
527
665
  // target: `http://127.0.0.1:${confServer[host][peerPath].port}`,
528
666
  proxy: confServer[host][peerPath].proxy,
529
667
  host,
@@ -538,7 +676,15 @@ const buildProxyRouter = () => {
538
676
  return proxyRouter;
539
677
  };
540
678
 
541
- const pathPortAssignmentFactory = (router, confServer) => {
679
+ /**
680
+ * @method pathPortAssignmentFactory
681
+ * @description Creates the path port assignment.
682
+ * @param {string} deployId - The deploy ID.
683
+ * @param {object} router - The router.
684
+ * @param {object} confServer - The server configuration.
685
+ * @memberof ServerConfBuilder
686
+ */
687
+ const pathPortAssignmentFactory = async (deployId, router, confServer) => {
542
688
  const pathPortAssignmentData = {};
543
689
  for (const host of Object.keys(confServer)) {
544
690
  const pathPortAssignment = [];
@@ -556,15 +702,54 @@ const pathPortAssignmentFactory = (router, confServer) => {
556
702
  // logger.info('', { host, port: port + 1, path: '/peer' });
557
703
  pathPortAssignment.push({
558
704
  port: port + 1,
559
- path: '/peer',
705
+ path: `${path === '/' ? '' : path}/peer`,
560
706
  });
561
707
  }
562
708
  }
563
709
  pathPortAssignmentData[host] = pathPortAssignment;
564
710
  }
711
+ if (fs.existsSync(`./engine-private/replica`)) {
712
+ const singleReplicas = await fs.readdir(`./engine-private/replica`);
713
+ for (let replica of singleReplicas) {
714
+ if (replica.startsWith(deployId)) {
715
+ const replicaServerConf = JSON.parse(
716
+ fs.readFileSync(`./engine-private/replica/${replica}/conf.server.json`, 'utf8'),
717
+ );
718
+ for (const host of Object.keys(replicaServerConf)) {
719
+ const pathPortAssignment = [];
720
+ for (const path of Object.keys(replicaServerConf[host])) {
721
+ const { peer } = replicaServerConf[host][path];
722
+ if (!router[`${host}${path === '/' ? '' : path}`]) continue;
723
+ const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
724
+ // logger.info('', { host, port, path });
725
+ pathPortAssignment.push({
726
+ port,
727
+ path,
728
+ });
729
+
730
+ if (peer) {
731
+ // logger.info('', { host, port: port + 1, path: '/peer' });
732
+ pathPortAssignment.push({
733
+ port: port + 1,
734
+ path: `${path === '/' ? '' : path}/peer`,
735
+ });
736
+ }
737
+ }
738
+ pathPortAssignmentData[host] = pathPortAssignmentData[host].concat(pathPortAssignment);
739
+ }
740
+ }
741
+ }
742
+ }
565
743
  return pathPortAssignmentData;
566
744
  };
567
745
 
746
+ /**
747
+ * @method deployRangePortFactory
748
+ * @description Creates the deploy range port factory.
749
+ * @param {object} router - The router.
750
+ * @returns {object} - The deploy range port factory.
751
+ * @memberof ServerConfBuilder
752
+ */
568
753
  const deployRangePortFactory = (router) => {
569
754
  const ports = Object.values(router).map((p) => parseInt(p.split(':')[2]));
570
755
  const fromPort = Math.min(...ports);
@@ -572,6 +757,14 @@ const deployRangePortFactory = (router) => {
572
757
  return { ports, fromPort, toPort };
573
758
  };
574
759
 
760
+ /**
761
+ * @method buildKindPorts
762
+ * @description Builds the kind ports.
763
+ * @param {number} from - The from port.
764
+ * @param {number} to - The to port.
765
+ * @returns {string} - The kind ports.
766
+ * @memberof ServerConfBuilder
767
+ */
575
768
  const buildKindPorts = (from, to) =>
576
769
  range(parseInt(from), parseInt(to))
577
770
  .map(
@@ -587,13 +780,21 @@ const buildKindPorts = (from, to) =>
587
780
  )
588
781
  .join('\n');
589
782
 
590
- const buildPortProxyRouter = (port, proxyRouter) => {
783
+ /**
784
+ * @method buildPortProxyRouter
785
+ * @description Builds the port proxy router.
786
+ * @param {number} port - The port.
787
+ * @param {object} proxyRouter - The proxy router.
788
+ * @param {object} [options={ orderByPathLength: false }] - The options.
789
+ * @returns {object} - The port proxy router.
790
+ * @memberof ServerConfBuilder
791
+ */
792
+ const buildPortProxyRouter = (port, proxyRouter, options = { orderByPathLength: false }) => {
591
793
  const hosts = proxyRouter[port];
592
794
  const router = {};
593
795
  // build router
594
796
  Object.keys(hosts).map((hostKey) => {
595
797
  let { host, path, target, proxy, peer } = hosts[hostKey];
596
- if (process.env.NODE_ENV === 'development' && process.argv.includes('localhost')) host = `localhost`;
597
798
 
598
799
  if (!proxy.includes(port)) {
599
800
  logger.warn('Proxy port not set on conf', { port, host, path, proxy, target });
@@ -615,15 +816,38 @@ const buildPortProxyRouter = (port, proxyRouter) => {
615
816
 
616
817
  if (Object.keys(router).length === 0) return router;
617
818
 
618
- const reOrderRouter = {};
619
- for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
620
- reOrderRouter[absoluteHostKey] = router[absoluteHostKey];
819
+ if (options.orderByPathLength === true) {
820
+ const reOrderRouter = {};
821
+ for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
822
+ reOrderRouter[absoluteHostKey] = router[absoluteHostKey];
823
+ return reOrderRouter;
824
+ }
621
825
 
622
- return reOrderRouter;
826
+ return router;
623
827
  };
624
828
 
829
+ /**
830
+ * @method buildReplicaId
831
+ * @description Builds the replica ID.
832
+ * @param {object} options - The options.
833
+ * @param {string} options.deployId - The deploy ID.
834
+ * @param {string} options.replica - The replica.
835
+ * @returns {string} - The replica ID.
836
+ * @memberof ServerConfBuilder
837
+ */
625
838
  const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
626
839
 
840
+ /**
841
+ * @method getDataDeploy
842
+ * @description Gets the data deploy.
843
+ * @param {object} options - The options.
844
+ * @param {boolean} [options.buildSingleReplica=false] - The build single replica.
845
+ * @param {string} options.deployGroupId - The deploy group ID.
846
+ * @param {string} options.deployId - The deploy ID.
847
+ * @param {boolean} [options.disableSyncEnvPort=false] - The disable sync env port.
848
+ * @returns {object} - The data deploy.
849
+ * @memberof ServerConfBuilder
850
+ */
627
851
  const getDataDeploy = (
628
852
  options = {
629
853
  buildSingleReplica: false,
@@ -656,6 +880,7 @@ const getDataDeploy = (
656
880
  let buildDataDeploy = [];
657
881
  for (const deployObj of dataDeploy) {
658
882
  const serverConf = loadReplicas(
883
+ deployObj.deployId,
659
884
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployObj.deployId}/conf.server.json`, 'utf8')),
660
885
  );
661
886
  let replicaDataDeploy = [];
@@ -685,6 +910,13 @@ const getDataDeploy = (
685
910
  return buildDataDeploy;
686
911
  };
687
912
 
913
+ /**
914
+ * @method validateTemplatePath
915
+ * @description Validates the template path.
916
+ * @param {string} absolutePath - The absolute path.
917
+ * @returns {boolean} - The validation result.
918
+ * @memberof ServerConfBuilder
919
+ */
688
920
  const validateTemplatePath = (absolutePath = '') => {
689
921
  const host = 'default.net';
690
922
  const path = '/';
@@ -762,16 +994,40 @@ const validateTemplatePath = (absolutePath = '') => {
762
994
  return true;
763
995
  };
764
996
 
997
+ /**
998
+ * @method awaitDeployMonitor
999
+ * @description Waits for the deploy monitor.
1000
+ * @param {boolean} [init=false] - The init flag.
1001
+ * @param {number} [deltaMs=1000] - The delta ms.
1002
+ * @returns {Promise<void>} - The await deploy monitor.
1003
+ * @memberof ServerConfBuilder
1004
+ */
765
1005
  const awaitDeployMonitor = async (init = false, deltaMs = 1000) => {
766
1006
  if (init) UnderpostRootEnv.API.set('await-deploy', new Date().toISOString());
767
1007
  await timer(deltaMs);
768
1008
  if (UnderpostRootEnv.API.get('await-deploy')) return await awaitDeployMonitor();
769
1009
  };
770
1010
 
1011
+ /**
1012
+ * @method getCronBackUpFolder
1013
+ * @description Gets the cron back up folder.
1014
+ * @param {string} host - The host.
1015
+ * @param {string} path - The path.
1016
+ * @returns {string} - The cron back up folder.
1017
+ * @memberof ServerConfBuilder
1018
+ */
771
1019
  const getCronBackUpFolder = (host = '', path = '') => {
772
1020
  return `${host}${path.replace(/\\/g, '/').replace(`/`, '-')}`;
773
1021
  };
774
1022
 
1023
+ /**
1024
+ * @method mergeFile
1025
+ * @description Merges the file.
1026
+ * @param {Array} parts - The parts.
1027
+ * @param {string} outputFilePath - The output file path.
1028
+ * @returns {Promise<void>} - The merge file.
1029
+ * @memberof ServerConfBuilder
1030
+ */
775
1031
  const mergeFile = async (parts = [], outputFilePath) => {
776
1032
  await new Promise((resolve) => {
777
1033
  splitFile
@@ -786,8 +1042,19 @@ const mergeFile = async (parts = [], outputFilePath) => {
786
1042
  });
787
1043
  };
788
1044
 
1045
+ /**
1046
+ * @method rebuildConfFactory
1047
+ * @description Rebuilds the conf factory.
1048
+ * @param {object} options - The options.
1049
+ * @param {string} options.deployId - The deploy ID.
1050
+ * @param {string} options.valkey - The valkey.
1051
+ * @param {boolean} [options.mongo=false] - The mongo.
1052
+ * @returns {object} - The rebuild conf factory.
1053
+ * @memberof ServerConfBuilder
1054
+ */
789
1055
  const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
790
1056
  const confServer = loadReplicas(
1057
+ deployId,
791
1058
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
792
1059
  );
793
1060
  const hosts = {};
@@ -833,6 +1100,13 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
833
1100
  return { hosts };
834
1101
  };
835
1102
 
1103
+ /**
1104
+ * @method getPathsSSR
1105
+ * @description Gets the paths SSR.
1106
+ * @param {object} conf - The conf.
1107
+ * @returns {Array} - The paths SSR.
1108
+ * @memberof ServerConfBuilder
1109
+ */
836
1110
  const getPathsSSR = (conf) => {
837
1111
  const paths = ['src/client/ssr/Render.js'];
838
1112
  for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
@@ -843,19 +1117,87 @@ const getPathsSSR = (conf) => {
843
1117
  return paths;
844
1118
  };
845
1119
 
1120
+ /**
1121
+ * @method Cmd
1122
+ * @description The command factory.
1123
+ * @memberof ServerConfBuilder
1124
+ */
846
1125
  const Cmd = {
1126
+ /**
1127
+ * @method delete
1128
+ * @description Deletes the deploy.
1129
+ * @param {string} deployId - The deploy ID.
1130
+ * @returns {string} - The delete command.
1131
+ * @memberof Cmd
1132
+ */
847
1133
  delete: (deployId) => `pm2 delete ${deployId}`,
1134
+ /**
1135
+ * @method run
1136
+ * @description Runs the deploy.
1137
+ * @returns {string} - The run command.
1138
+ * @memberof Cmd
1139
+ */
848
1140
  run: () => `npm start`,
1141
+ /**
1142
+ * @method build
1143
+ * @description Builds the deploy.
1144
+ * @param {string} deployId - The deploy ID.
1145
+ * @returns {string} - The build command.
1146
+ * @memberof Cmd
1147
+ */
849
1148
  build: (deployId) => `node bin/deploy build-full-client ${deployId}${process.argv.includes('l') ? ' l' : ''}`,
1149
+ /**
1150
+ * @method conf
1151
+ * @description Configures the deploy.
1152
+ * @param {string} deployId - The deploy ID.
1153
+ * @param {string} env - The environment.
1154
+ * @returns {string} - The conf command.
1155
+ * @memberof Cmd
1156
+ */
850
1157
  conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
1158
+ /**
1159
+ * @method replica
1160
+ * @description Builds the replica.
1161
+ * @param {string} deployId - The deploy ID.
1162
+ * @param {string} host - The host.
1163
+ * @param {string} path - The path.
1164
+ * @returns {string} - The replica command.
1165
+ * @memberof Cmd
1166
+ */
851
1167
  replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
1168
+ /**
1169
+ * @method syncPorts
1170
+ * @description Syncs the ports.
1171
+ * @param {string} deployGroupId - The deploy group ID.
1172
+ * @returns {string} - The sync ports command.
1173
+ * @memberof Cmd
1174
+ */
852
1175
  syncPorts: (deployGroupId) => `node bin/deploy sync-env-port ${deployGroupId}`,
1176
+ /**
1177
+ * @method cron
1178
+ * @description Creates a cron job.
1179
+ * @param {string} deployList - The deploy list.
1180
+ * @param {string} jobList - The job list.
1181
+ * @param {string} name - The name.
1182
+ * @param {string} expression - The expression.
1183
+ * @param {object} options - The options.
1184
+ * @returns {string} - The cron command.
1185
+ * @memberof Cmd
1186
+ */
853
1187
  cron: (deployList, jobList, name, expression, options) =>
854
1188
  `pm2 start ./bin/index.js --no-autorestart --instances 1 --cron "${expression}" --name ${name} -- cron ${
855
1189
  options?.itc ? `--itc ` : ''
856
1190
  }${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
857
1191
  };
858
1192
 
1193
+ /**
1194
+ * @method splitFileFactory
1195
+ * @description Splits the file factory.
1196
+ * @param {string} name - The name.
1197
+ * @param {string} _path - The path.
1198
+ * @returns {Promise<boolean>} - The split file factory.
1199
+ * @memberof ServerConfBuilder
1200
+ */
859
1201
  const splitFileFactory = async (name, _path) => {
860
1202
  const stats = fs.statSync(_path);
861
1203
  const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
@@ -884,6 +1226,12 @@ const splitFileFactory = async (name, _path) => {
884
1226
  return false;
885
1227
  };
886
1228
 
1229
+ /**
1230
+ * @method getNpmRootPath
1231
+ * @description Gets the npm root path.
1232
+ * @returns {string} - The npm root path.
1233
+ * @memberof ServerConfBuilder
1234
+ */
887
1235
  const getNpmRootPath = () =>
888
1236
  shellExec(`npm root -g`, {
889
1237
  stdout: true,
@@ -891,8 +1239,21 @@ const getNpmRootPath = () =>
891
1239
  silent: true,
892
1240
  }).trim();
893
1241
 
1242
+ /**
1243
+ * @method getUnderpostRootPath
1244
+ * @description Gets the underpost root path.
1245
+ * @returns {string} - The underpost root path.
1246
+ * @memberof ServerConfBuilder
1247
+ */
894
1248
  const getUnderpostRootPath = () => `${getNpmRootPath()}/underpost`;
895
1249
 
1250
+ /**
1251
+ * @method writeEnv
1252
+ * @description Writes the environment variables.
1253
+ * @param {string} envPath - The environment path.
1254
+ * @param {object} envObj - The environment object.
1255
+ * @memberof ServerConfBuilder
1256
+ */
896
1257
  const writeEnv = (envPath, envObj) =>
897
1258
  fs.writeFileSync(
898
1259
  envPath,
@@ -902,6 +1263,14 @@ const writeEnv = (envPath, envObj) =>
902
1263
  'utf8',
903
1264
  );
904
1265
 
1266
+ /**
1267
+ * @method buildCliDoc
1268
+ * @description Builds the CLI documentation.
1269
+ * @param {object} program - The program.
1270
+ * @param {string} oldVersion - The old version.
1271
+ * @param {string} newVersion - The new version.
1272
+ * @memberof ServerConfBuilder
1273
+ */
905
1274
  const buildCliDoc = (program, oldVersion, newVersion) => {
906
1275
  let md = shellExec(`node bin help`, { silent: true, stdout: true }).split('Options:');
907
1276
  const baseOptions =
@@ -953,22 +1322,44 @@ const buildCliDoc = (program, oldVersion, newVersion) => {
953
1322
  ` +
954
1323
  baseOptions +
955
1324
  `
956
-
1325
+
957
1326
  <a target="_top" href="https://github.com/${process.env.GITHUB_USERNAME}/pwa-microservices-template/blob/master/cli.md">See complete CLI Docs here.</a>
958
-
1327
+
959
1328
  `
960
1329
  ).replaceAll(oldVersion, newVersion),
961
1330
  'utf8',
962
1331
  );
963
1332
  };
964
1333
 
965
- const getInstanceContext = async (options = { singleReplica, replicas, redirect: '' }) => {
966
- const { singleReplica, replicas, redirect } = options;
967
-
968
- if (singleReplica && replicas && replicas.length > 0)
969
- return {
970
- singleReplicaHost: true,
971
- };
1334
+ /**
1335
+ * @method getInstanceContext
1336
+ * @description Gets the instance context.
1337
+ * @param {object} options - The options.
1338
+ * @param {string} options.deployId - The deploy ID.
1339
+ * @param {boolean} options.singleReplica - The single replica.
1340
+ * @param {Array} options.replicas - The replicas.
1341
+ * @param {string} options.redirect - The redirect.
1342
+ * @returns {object} - The instance context.
1343
+ * @memberof ServerConfBuilder
1344
+ */
1345
+ const getInstanceContext = async (options = { deployId, singleReplica, replicas, redirect: '' }) => {
1346
+ const { deployId, singleReplica, replicas, redirect } = options;
1347
+ let singleReplicaOffsetPortSum = 0;
1348
+
1349
+ if (singleReplica && replicas && replicas.length > 0) {
1350
+ for (const replica of replicas) {
1351
+ const replicaDeployId = buildReplicaId({ deployId, replica });
1352
+ const confReplicaServer = JSON.parse(
1353
+ fs.readFileSync(`./engine-private/replica/${replicaDeployId}/conf.server.json`, 'utf8'),
1354
+ );
1355
+ for (const host of Object.keys(confReplicaServer)) {
1356
+ for (const path of Object.keys(confReplicaServer[host])) {
1357
+ singleReplicaOffsetPortSum++;
1358
+ if (confReplicaServer[host][path].peer) singleReplicaOffsetPortSum++;
1359
+ }
1360
+ }
1361
+ }
1362
+ }
972
1363
 
973
1364
  const redirectTarget = redirect
974
1365
  ? redirect[redirect.length - 1] === '/'
@@ -976,9 +1367,21 @@ const getInstanceContext = async (options = { singleReplica, replicas, redirect:
976
1367
  : redirect
977
1368
  : undefined;
978
1369
 
979
- return { redirectTarget };
1370
+ return { redirectTarget, singleReplicaOffsetPortSum };
980
1371
  };
981
1372
 
1373
+ /**
1374
+ * @method buildApiConf
1375
+ * @description Builds the API configuration.
1376
+ * @param {object} options - The options.
1377
+ * @param {string} options.deployId - The deploy ID.
1378
+ * @param {string} options.subConf - The sub configuration.
1379
+ * @param {string} options.host - The host.
1380
+ * @param {string} options.path - The path.
1381
+ * @param {string} options.origin - The origin.
1382
+ * @returns {object} - The API configuration.
1383
+ * @memberof ServerConfBuilder
1384
+ */
982
1385
  const buildApiConf = async (options = { deployId: '', subConf: '', host: '', path: '', origin: '' }) => {
983
1386
  let { deployId, subConf, host, path, origin } = options;
984
1387
  if (!deployId) deployId = process.argv[2].trim();
@@ -1007,6 +1410,18 @@ const buildApiConf = async (options = { deployId: '', subConf: '', host: '', pat
1007
1410
  );
1008
1411
  };
1009
1412
 
1413
+ /**
1414
+ * @method buildClientStaticConf
1415
+ * @description Builds the client static configuration.
1416
+ * @param {object} options - The options.
1417
+ * @param {string} options.deployId - The deploy ID.
1418
+ * @param {string} options.subConf - The sub configuration.
1419
+ * @param {string} options.apiBaseHost - The API base host.
1420
+ * @param {string} options.host - The host.
1421
+ * @param {string} options.path - The path.
1422
+ * @returns {void}
1423
+ * @memberof ServerConfBuilder
1424
+ */
1010
1425
  const buildClientStaticConf = async (options = { deployId: '', subConf: '', apiBaseHost: '', host: '', path: '' }) => {
1011
1426
  let { deployId, subConf, host, path } = options;
1012
1427
  if (!deployId) deployId = process.argv[2].trim();
@@ -1033,6 +1448,16 @@ const buildClientStaticConf = async (options = { deployId: '', subConf: '', apiB
1033
1448
  );
1034
1449
  };
1035
1450
 
1451
+ /**
1452
+ * @method isDeployRunnerContext
1453
+ * @description Checks if the deploy runner context is valid.
1454
+ * @param {string} path - The path.
1455
+ * @param {object} options - The options.
1456
+ * @returns {boolean} - The deploy runner context.
1457
+ * @memberof ServerConfBuilder
1458
+ */
1459
+ const isDeployRunnerContext = (path, options) => !options.build && path && path !== 'template-deploy';
1460
+
1036
1461
  export {
1037
1462
  Cmd,
1038
1463
  Config,
@@ -1068,4 +1493,5 @@ export {
1068
1493
  getInstanceContext,
1069
1494
  buildApiConf,
1070
1495
  buildClientStaticConf,
1496
+ isDeployRunnerContext,
1071
1497
  };