@underpostnet/underpost 2.8.5 → 2.8.7

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 (109) hide show
  1. package/.github/workflows/ghpkg.yml +1 -1
  2. package/.github/workflows/npmpkg.yml +1 -1
  3. package/.github/workflows/pwa-microservices-template.page.yml +1 -1
  4. package/.vscode/extensions.json +3 -2
  5. package/.vscode/settings.json +6 -0
  6. package/CHANGELOG.md +44 -0
  7. package/Dockerfile +9 -10
  8. package/README.md +39 -2
  9. package/bin/build.js +31 -6
  10. package/bin/deploy.js +1404 -202
  11. package/bin/file.js +8 -0
  12. package/bin/hwt.js +0 -10
  13. package/bin/index.js +1 -187
  14. package/bin/util.js +0 -7
  15. package/bin/vs.js +1 -0
  16. package/cli.md +451 -0
  17. package/conf.js +0 -2
  18. package/docker-compose.yml +1 -1
  19. package/jsdoc.json +1 -1
  20. package/manifests/calico-custom-resources.yaml +25 -0
  21. package/manifests/deployment/adminer/deployment.yaml +32 -0
  22. package/manifests/deployment/adminer/kustomization.yaml +7 -0
  23. package/manifests/deployment/adminer/service.yaml +13 -0
  24. package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
  25. package/manifests/deployment/fastapi/backend-service.yml +19 -0
  26. package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
  27. package/manifests/deployment/fastapi/frontend-service.yml +15 -0
  28. package/manifests/deployment/kafka/deployment.yaml +69 -0
  29. package/manifests/kind-config-dev.yaml +12 -0
  30. package/manifests/kubeadm-calico-config.yaml +119 -0
  31. package/manifests/mongodb/kustomization.yaml +2 -2
  32. package/manifests/mongodb-4.4/kustomization.yaml +7 -0
  33. package/manifests/mongodb-4.4/service-deployment.yaml +63 -0
  34. package/manifests/postgresql/configmap.yaml +9 -0
  35. package/manifests/postgresql/kustomization.yaml +10 -0
  36. package/manifests/postgresql/pv.yaml +15 -0
  37. package/manifests/postgresql/pvc.yaml +13 -0
  38. package/manifests/{core/underpost-engine-headless-service.yaml → postgresql/service.yaml} +3 -3
  39. package/manifests/postgresql/statefulset.yaml +37 -0
  40. package/manifests/valkey/statefulset.yaml +6 -4
  41. package/package.json +10 -14
  42. package/src/api/default/default.service.js +1 -1
  43. package/src/api/user/user.service.js +14 -11
  44. package/src/cli/cluster.js +298 -63
  45. package/src/cli/cron.js +39 -8
  46. package/src/cli/db.js +118 -44
  47. package/src/cli/deploy.js +312 -102
  48. package/src/cli/env.js +9 -3
  49. package/src/cli/fs.js +161 -0
  50. package/src/cli/image.js +45 -104
  51. package/src/cli/index.js +312 -0
  52. package/src/cli/monitor.js +236 -0
  53. package/src/cli/repository.js +26 -2
  54. package/src/cli/script.js +25 -1
  55. package/src/cli/test.js +39 -4
  56. package/src/client/components/core/Account.js +28 -24
  57. package/src/client/components/core/Blockchain.js +1 -1
  58. package/src/client/components/core/CalendarCore.js +14 -73
  59. package/src/client/components/core/CommonJs.js +54 -2
  60. package/src/client/components/core/Css.js +0 -1
  61. package/src/client/components/core/CssCore.js +10 -4
  62. package/src/client/components/core/Docs.js +1 -2
  63. package/src/client/components/core/EventsUI.js +3 -3
  64. package/src/client/components/core/FileExplorer.js +86 -78
  65. package/src/client/components/core/Input.js +4 -2
  66. package/src/client/components/core/JoyStick.js +2 -2
  67. package/src/client/components/core/LoadingAnimation.js +3 -12
  68. package/src/client/components/core/LogIn.js +3 -3
  69. package/src/client/components/core/LogOut.js +1 -1
  70. package/src/client/components/core/Modal.js +44 -14
  71. package/src/client/components/core/Panel.js +26 -66
  72. package/src/client/components/core/PanelForm.js +22 -15
  73. package/src/client/components/core/Recover.js +3 -3
  74. package/src/client/components/core/RichText.js +1 -11
  75. package/src/client/components/core/Router.js +3 -1
  76. package/src/client/components/core/SignUp.js +2 -2
  77. package/src/client/components/default/RoutesDefault.js +3 -2
  78. package/src/client/services/core/core.service.js +15 -10
  79. package/src/client/services/default/default.management.js +45 -38
  80. package/src/client/ssr/Render.js +6 -1
  81. package/src/client/ssr/body/CacheControl.js +2 -3
  82. package/src/client/sw/default.sw.js +3 -3
  83. package/src/db/mongo/MongooseDB.js +17 -1
  84. package/src/index.js +25 -1
  85. package/src/mailer/MailerProvider.js +3 -0
  86. package/src/runtime/lampp/Dockerfile +65 -0
  87. package/src/server/backup.js +3 -3
  88. package/src/server/client-build.js +45 -23
  89. package/src/server/client-formatted.js +2 -1
  90. package/src/server/conf.js +110 -16
  91. package/src/server/dns.js +74 -43
  92. package/src/server/downloader.js +0 -8
  93. package/src/server/json-schema.js +77 -0
  94. package/src/server/network.js +7 -122
  95. package/src/server/peer.js +2 -2
  96. package/src/server/proxy.js +4 -4
  97. package/src/server/runtime.js +40 -12
  98. package/src/server/start.js +122 -0
  99. package/src/server/valkey.js +25 -11
  100. package/test/api.test.js +0 -8
  101. package/manifests/core/kustomization.yaml +0 -11
  102. package/manifests/core/underpost-engine-backup-access.yaml +0 -16
  103. package/manifests/core/underpost-engine-backup-pv-pvc.yaml +0 -22
  104. package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +0 -40
  105. package/manifests/core/underpost-engine-mongodb-configmap.yaml +0 -26
  106. package/manifests/core/underpost-engine-statefulset.yaml +0 -91
  107. package/manifests/valkey/underpost-engine-valkey-service.yaml +0 -17
  108. package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +0 -39
  109. /package/manifests/{core/underpost-engine-pv-pvc.yaml → mongodb-4.4/pv-pvc.yaml} +0 -0
@@ -0,0 +1,77 @@
1
+ function isPlainObject(obj) {
2
+ return obj ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype : false;
3
+ }
4
+
5
+ const supportType = ['string', 'number', 'array', 'object', 'boolean', 'integer'];
6
+
7
+ function getType(type) {
8
+ if (!type) type = 'string';
9
+ if (supportType.indexOf(type) !== -1) {
10
+ return type;
11
+ }
12
+ return typeof type;
13
+ }
14
+
15
+ function isSchema(object) {
16
+ if (supportType.indexOf(object.type) !== -1) {
17
+ return true;
18
+ }
19
+ return false;
20
+ }
21
+
22
+ function handleSchema(json, schema) {
23
+ Object.assign(schema, json);
24
+ if (schema.type === 'object') {
25
+ delete schema.properties;
26
+ parse(json.properties, schema);
27
+ }
28
+ if (schema.type === 'array') {
29
+ delete schema.items;
30
+ schema.items = {};
31
+ parse(json.items, schema.items);
32
+ }
33
+ }
34
+
35
+ function handleArray(arr, schema) {
36
+ schema.type = 'array';
37
+ let props = (schema.items = {});
38
+ parse(arr[0], props);
39
+ }
40
+
41
+ function handleObject(json, schema) {
42
+ if (isSchema(json)) {
43
+ return handleSchema(json, schema);
44
+ }
45
+ schema.type = 'object';
46
+ schema.required = [];
47
+ let props = (schema.properties = {});
48
+ for (let key in json) {
49
+ let item = json[key];
50
+ let curSchema = (props[key] = {});
51
+ if (key[0] === '*') {
52
+ delete props[key];
53
+ key = key.substr(1);
54
+ schema.required.push(key);
55
+ curSchema = props[key] = {};
56
+ }
57
+ parse(item, curSchema);
58
+ }
59
+ }
60
+
61
+ function parse(json, schema) {
62
+ if (Array.isArray(json)) {
63
+ handleArray(json, schema);
64
+ } else if (isPlainObject(json)) {
65
+ handleObject(json, schema);
66
+ } else {
67
+ schema.type = getType(json);
68
+ }
69
+ }
70
+
71
+ function ejs(data) {
72
+ let JsonSchema = {};
73
+ parse(data, JsonSchema);
74
+ return JsonSchema;
75
+ }
76
+
77
+ export { ejs };
@@ -1,123 +1,18 @@
1
- import fs from 'fs-extra';
2
-
3
- import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
1
+ import Underpost from '../index.js';
4
2
  import { actionInitLog, loggerFactory } from './logger.js';
5
- import { DataBaseProvider } from '../db/DataBaseProvider.js';
6
- import { getDeployId } from './conf.js';
7
-
8
- // Network Address Translation Management
9
-
10
- // import dotenv from 'dotenv';
11
- // dotenv.config();
12
3
 
13
4
  const logger = loggerFactory(import.meta);
14
5
 
15
- const ip = {
16
- public: {
17
- get: async () => await publicIp(), // => 'fe80::200:f8ff:fe21:67cf'
18
- ipv4: async () => await publicIpv4(), // => '46.5.21.123'
19
- ipv6: async () => await publicIpv6(), // => 'fe80::200:f8ff:fe21:67cf'
20
- },
21
- };
22
-
23
- let ipInstance = '';
24
- const networkRouter = {};
25
-
26
6
  const logRuntimeRouter = () => {
27
7
  const displayLog = {};
28
8
 
29
- for (const host of Object.keys(networkRouter))
30
- for (const path of Object.keys(networkRouter[host]))
31
- displayLog[networkRouter[host][path].publicHost] = networkRouter[host][path].local;
9
+ for (const host of Object.keys(Underpost.deployNetwork))
10
+ for (const path of Object.keys(Underpost.deployNetwork[host]))
11
+ displayLog[Underpost.deployNetwork[host][path].publicHost] = Underpost.deployNetwork[host][path].local;
32
12
 
33
13
  logger.info('Runtime network', displayLog);
34
14
  };
35
15
 
36
- const saveRuntimeRouter = async () => {
37
- try {
38
- const deployId = process.env.DEFAULT_DEPLOY_ID;
39
- const host = process.env.DEFAULT_DEPLOY_HOST;
40
- const path = process.env.DEFAULT_DEPLOY_PATH;
41
- const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
42
- if (!deployId || !host || !path || !fs.existsSync(confServerPath)) {
43
- // logger.warn('default deploy instance not found');
44
- return;
45
- }
46
- const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
47
- const { db } = confServer[host][path];
48
-
49
- let closeConn;
50
- if (!DataBaseProvider.instance[`${host}${path}`]) {
51
- await DataBaseProvider.load({ apis: ['instance'], host, path, db });
52
- closeConn = true;
53
- }
54
-
55
- /** @type {import('../api/instance/instance.model.js').InstanceModel} */
56
- const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
57
-
58
- for (const _host of Object.keys(networkRouter)) {
59
- for (const _path of Object.keys(networkRouter[_host])) {
60
- const body = {
61
- host: _host,
62
- path: _path,
63
- deployId: getDeployId(),
64
- client: networkRouter[_host][_path].client,
65
- runtime: networkRouter[_host][_path].runtime,
66
- port: networkRouter[_host][_path].port,
67
- apis: networkRouter[_host][_path].apis,
68
- };
69
- const instance = await Instance.findOne({ deployId: body.deployId, host: _host, path: _path });
70
- if (instance) {
71
- await Instance.findByIdAndUpdate(instance._id, body);
72
- } else {
73
- await new Instance(body).save();
74
- }
75
- }
76
- }
77
-
78
- if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
79
- } catch (error) {
80
- logger.error(error, error.stack);
81
- }
82
- };
83
-
84
- const netWorkCron = [];
85
-
86
- const saveRuntimeCron = async () => {
87
- try {
88
- const deployId = process.env.DEFAULT_DEPLOY_ID;
89
- const host = process.env.DEFAULT_DEPLOY_HOST;
90
- const path = process.env.DEFAULT_DEPLOY_PATH;
91
- const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
92
- const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
93
- const { db } = confServer[host][path];
94
-
95
- let closeConn;
96
- if (!DataBaseProvider.instance[`${host}${path}`]) {
97
- await DataBaseProvider.load({ apis: ['cron'], host, path, db });
98
- closeConn = true;
99
- }
100
-
101
- /** @type {import('../api/cron/cron.model.js').CronModel} */
102
- const Cron = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Cron;
103
-
104
- // await Cron.insertMany(netWorkCron);
105
-
106
- for (const cronInstance of netWorkCron) {
107
- const cron = await Cron.findOne({ deployId: cronInstance.deployId, jobId: cronInstance.jobId });
108
- if (cron) {
109
- await Cron.findByIdAndUpdate(cron._id, cronInstance);
110
- } else {
111
- await new Cron(cronInstance).save();
112
- }
113
- }
114
-
115
- if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
116
- } catch (error) {
117
- logger.error(error, error.stack);
118
- }
119
- };
120
-
121
16
  const listenServerFactory = (logic = async () => {}) => {
122
17
  return {
123
18
  listen: async (...args) => (
@@ -150,13 +45,12 @@ const listenPortController = async (server, port, metadata) =>
150
45
  if (error.length > 0) throw new Error('Listen port controller requires values: ' + error.join(', '));
151
46
 
152
47
  server.listen(port, () => {
153
- if (!networkRouter[host]) networkRouter[host] = {};
154
- networkRouter[host][path] = {
48
+ if (!Underpost.deployNetwork[host]) Underpost.deployNetwork[host] = {};
49
+ Underpost.deployNetwork[host][path] = {
155
50
  meta,
156
51
  client,
157
52
  runtime,
158
53
  port,
159
- public: `http://${ipInstance}:${port}${path}`,
160
54
  publicHost:
161
55
  port === 80
162
56
  ? `http://${host}${path}`
@@ -175,13 +69,4 @@ const listenPortController = async (server, port, metadata) =>
175
69
  }
176
70
  });
177
71
 
178
- export {
179
- ip,
180
- listenPortController,
181
- networkRouter,
182
- netWorkCron,
183
- saveRuntimeRouter,
184
- logRuntimeRouter,
185
- listenServerFactory,
186
- saveRuntimeCron,
187
- };
72
+ export { listenPortController, logRuntimeRouter, listenServerFactory };
@@ -2,7 +2,7 @@ import { PeerServer } from 'peer';
2
2
  import dotenv from 'dotenv';
3
3
  import { loggerFactory } from './logger.js';
4
4
  import fs from 'fs-extra';
5
- import { listenServerFactory } from './network.js';
5
+ import UnderpostStartUp from './start.js';
6
6
 
7
7
  dotenv.config();
8
8
 
@@ -25,7 +25,7 @@ const createPeerServer = async ({ port, devPort, origins, host, path }) => {
25
25
  // cert: fs.readFileSync(''),
26
26
  // ca: fs.readFileSync(''),
27
27
  };
28
- const peerServer = listenServerFactory(() => PeerServer(options));
28
+ const peerServer = UnderpostStartUp.API.listenServerFactory(() => PeerServer(options));
29
29
 
30
30
  return { options, peerServer, meta: import.meta };
31
31
  };
@@ -5,9 +5,9 @@ import dotenv from 'dotenv';
5
5
 
6
6
  import { createProxyMiddleware } from 'http-proxy-middleware';
7
7
  import { loggerFactory, loggerMiddleware } from './logger.js';
8
- import { listenPortController } from './network.js';
9
8
  import { createSslServer, sslRedirectMiddleware } from './ssl.js';
10
9
  import { buildPortProxyRouter, buildProxyRouter, maintenanceMiddleware } from './conf.js';
10
+ import UnderpostStartUp from './start.js';
11
11
 
12
12
  dotenv.config();
13
13
 
@@ -71,11 +71,11 @@ const buildProxy = async () => {
71
71
  switch (port) {
72
72
  case 443:
73
73
  const { ServerSSL } = await createSslServer(app, hosts);
74
- await listenPortController(ServerSSL, port, runningData);
74
+ await UnderpostStartUp.API.listenPortController(ServerSSL, port, runningData);
75
75
  break;
76
76
 
77
77
  default:
78
- await listenPortController(app, port, runningData);
78
+ await UnderpostStartUp.API.listenPortController(app, port, runningData);
79
79
 
80
80
  break;
81
81
  }
@@ -83,7 +83,7 @@ const buildProxy = async () => {
83
83
  break;
84
84
 
85
85
  default:
86
- await listenPortController(app, port, runningData);
86
+ await UnderpostStartUp.API.listenPortController(app, port, runningData);
87
87
 
88
88
  break;
89
89
  }
@@ -9,7 +9,7 @@ import compression from 'compression';
9
9
 
10
10
  import { createServer } from 'http';
11
11
  import { getRootDirectory } from './process.js';
12
- import { listenPortController, saveRuntimeRouter, logRuntimeRouter, listenServerFactory } from './network.js';
12
+ import UnderpostStartUp from './start.js';
13
13
  import { loggerFactory, loggerMiddleware } from './logger.js';
14
14
  import { getCapVariableName, newInstance } from '../client/components/core/CommonJs.js';
15
15
  import { Xampp } from '../runtime/xampp/Xampp.js';
@@ -19,7 +19,9 @@ import { DataBaseProvider } from '../db/DataBaseProvider.js';
19
19
  import { createPeerServer } from './peer.js';
20
20
  import { Lampp } from '../runtime/lampp/Lampp.js';
21
21
  import { getDeployId } from './conf.js';
22
- import { ssrFactory } from './client-formatted.js';
22
+ import { JSONweb, ssrFactory } from './client-formatted.js';
23
+ import Underpost from '../index.js';
24
+ import { createValkeyConnection } from './valkey.js';
23
25
 
24
26
  dotenv.config();
25
27
 
@@ -40,7 +42,6 @@ const buildRuntime = async () => {
40
42
  // logger.info('promCounterOption', promCounterOption);
41
43
 
42
44
  const requestCounter = new promClient.Counter(promCounterOption);
43
- const ipInstance = ''; // await ip.public.ipv4();
44
45
  const initPort = parseInt(process.env.PORT) + 1;
45
46
  let currentPort = initPort;
46
47
  const confServer = JSON.parse(fs.readFileSync(`./conf/conf.server.json`, 'utf8'));
@@ -67,6 +68,7 @@ const buildRuntime = async () => {
67
68
  peer,
68
69
  singleReplica,
69
70
  replicas,
71
+ valkey,
70
72
  } = confServer[host][path];
71
73
 
72
74
  if (singleReplica && replicas && replicas.length > 0 && !singleReplicaHosts.includes(host)) {
@@ -140,6 +142,8 @@ const buildRuntime = async () => {
140
142
  // if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
141
143
  // $_SERVER['HTTPS'] = 'on';
142
144
  // }
145
+ // For plugins:
146
+ // define( 'FS_METHOD', 'direct' );
143
147
 
144
148
  // ErrorDocument 404 /custom_404.html
145
149
  // ErrorDocument 500 /custom_50x.html
@@ -182,7 +186,11 @@ const buildRuntime = async () => {
182
186
  // RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
183
187
  // RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
184
188
 
185
- await listenPortController(listenServerFactory(), port, runningData);
189
+ await UnderpostStartUp.API.listenPortController(
190
+ UnderpostStartUp.API.listenServerFactory(),
191
+ port,
192
+ runningData,
193
+ );
186
194
  break;
187
195
  case 'xampp':
188
196
  if (!Xampp.enabled()) continue;
@@ -229,7 +237,11 @@ const buildRuntime = async () => {
229
237
  // if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
230
238
  // $_SERVER['HTTPS'] = 'on';
231
239
  // }
232
- await listenPortController(listenServerFactory(), port, runningData);
240
+ await UnderpostStartUp.API.listenPortController(
241
+ UnderpostStartUp.API.listenServerFactory(),
242
+ port,
243
+ runningData,
244
+ );
233
245
  break;
234
246
  case 'nodejs':
235
247
  const app = express();
@@ -282,7 +294,7 @@ const buildRuntime = async () => {
282
294
  currentPort += 2;
283
295
  const staticPort = newInstance(currentPort);
284
296
 
285
- await listenPortController(app, staticPort, runningData);
297
+ await UnderpostStartUp.API.listenPortController(app, staticPort, runningData);
286
298
  currentPort++;
287
299
  continue;
288
300
  }
@@ -333,7 +345,7 @@ const buildRuntime = async () => {
333
345
  // }),
334
346
  // );
335
347
 
336
- await listenPortController(app, port, runningData);
348
+ await UnderpostStartUp.API.listenPortController(app, port, runningData);
337
349
  break;
338
350
  }
339
351
 
@@ -353,6 +365,9 @@ const buildRuntime = async () => {
353
365
 
354
366
  if (db && apis) await DataBaseProvider.load({ apis, host, path, db });
355
367
 
368
+ // valkey server
369
+ await createValkeyConnection({ host, path }, valkey);
370
+
356
371
  if (mailer) {
357
372
  const mailerSsrConf = confSSR[getCapVariableName(client)];
358
373
  await MailerProvider.load({
@@ -384,6 +399,13 @@ const buildRuntime = async () => {
384
399
  ssrPath,
385
400
  ssrHeadComponents: '',
386
401
  ssrBodyComponents: (await ssrFactory(`./src/client/ssr/body/404.js`))(),
402
+ renderPayload: {
403
+ apiBasePath: process.env.BASE_API,
404
+ version: Underpost.version,
405
+ },
406
+ renderApi: {
407
+ JSONweb,
408
+ },
387
409
  });
388
410
  const path404 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/404/index.html`;
389
411
  const page404 = fs.existsSync(path404) ? `${path === '/' ? '' : path}/404` : undefined;
@@ -400,6 +422,13 @@ const buildRuntime = async () => {
400
422
  ssrPath,
401
423
  ssrHeadComponents: '',
402
424
  ssrBodyComponents: (await ssrFactory(`./src/client/ssr/body/500.js`))(),
425
+ renderPayload: {
426
+ apiBasePath: process.env.BASE_API,
427
+ version: Underpost.version,
428
+ },
429
+ renderApi: {
430
+ JSONweb,
431
+ },
403
432
  });
404
433
  const path500 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/500/index.html`;
405
434
  const page500 = fs.existsSync(path500) ? `${path === '/' ? '' : path}/500` : undefined;
@@ -427,7 +456,7 @@ const buildRuntime = async () => {
427
456
  port,
428
457
  origins,
429
458
  });
430
- await listenPortController(listenServerFactory(), port, {
459
+ await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), port, {
431
460
  runtime: 'nodejs',
432
461
  client: null,
433
462
  host,
@@ -447,7 +476,7 @@ const buildRuntime = async () => {
447
476
  path,
448
477
  });
449
478
 
450
- await listenPortController(peerServer, peerPort, {
479
+ await UnderpostStartUp.API.listenPortController(peerServer, peerPort, {
451
480
  runtime: 'nodejs',
452
481
  client: null,
453
482
  host,
@@ -456,7 +485,7 @@ const buildRuntime = async () => {
456
485
  });
457
486
  }
458
487
 
459
- await listenPortController(server, port, runningData);
488
+ await UnderpostStartUp.API.listenPortController(server, port, runningData);
460
489
 
461
490
  break;
462
491
  default:
@@ -469,8 +498,7 @@ const buildRuntime = async () => {
469
498
  if (Xampp.enabled() && Xampp.router) Xampp.initService();
470
499
  if (Lampp.enabled() && Lampp.router) Lampp.initService();
471
500
 
472
- saveRuntimeRouter();
473
- logRuntimeRouter();
501
+ UnderpostStartUp.API.logRuntimeRouter();
474
502
  };
475
503
 
476
504
  export { buildRuntime };
@@ -0,0 +1,122 @@
1
+ import UnderpostDeploy from '../cli/deploy.js';
2
+ import fs from 'fs-extra';
3
+ import { awaitDeployMonitor } from './conf.js';
4
+ import { actionInitLog, loggerFactory } from './logger.js';
5
+ import { shellCd, shellExec } from './process.js';
6
+ import UnderpostRootEnv from '../cli/env.js';
7
+
8
+ const logger = loggerFactory(import.meta);
9
+
10
+ class UnderpostStartUp {
11
+ static API = {
12
+ logRuntimeRouter: () => {
13
+ const displayLog = {};
14
+
15
+ for (const host of Object.keys(UnderpostDeploy.NETWORK))
16
+ for (const path of Object.keys(UnderpostDeploy.NETWORK[host]))
17
+ displayLog[UnderpostDeploy.NETWORK[host][path].publicHost] = UnderpostDeploy.NETWORK[host][path].local;
18
+
19
+ logger.info('Runtime network', displayLog);
20
+ },
21
+ listenServerFactory: (logic = async () => {}) => {
22
+ return {
23
+ listen: async (...args) => {
24
+ const msDelta = 1000;
25
+ const msMax = 30 * 24 * 60 * 60 * 1000; // ~ 1 month
26
+ let msCount = 0;
27
+ setInterval(() => {
28
+ msCount += msDelta;
29
+ if (msCount >= msMax) {
30
+ const message = 'Listen server factory timeout';
31
+ logger.error(message);
32
+ throw new Error(message);
33
+ }
34
+ }, msDelta);
35
+ return logic ? await logic(...args) : undefined, args[1]();
36
+ },
37
+ };
38
+ },
39
+ listenPortController: async (server, port, metadata) =>
40
+ new Promise((resolve) => {
41
+ try {
42
+ if (port === ':') {
43
+ server.listen(port, actionInitLog);
44
+ return resolve(true);
45
+ }
46
+
47
+ const { host, path, client, runtime, meta } = metadata;
48
+ const error = [];
49
+ if (port === undefined) error.push(`port`);
50
+ if (host === undefined) error.push(`host`);
51
+ if (path === undefined) error.push(`path`);
52
+ if (client === undefined) error.push(`client`);
53
+ if (runtime === undefined) error.push(`runtime`);
54
+ if (meta === undefined) error.push(`meta`);
55
+ if (error.length > 0) throw new Error('Listen port controller requires values: ' + error.join(', '));
56
+
57
+ server.listen(port, () => {
58
+ if (!UnderpostDeploy.NETWORK[host]) UnderpostDeploy.NETWORK[host] = {};
59
+ UnderpostDeploy.NETWORK[host][path] = {
60
+ meta,
61
+ client,
62
+ runtime,
63
+ port,
64
+ publicHost:
65
+ port === 80
66
+ ? `http://${host}${path}`
67
+ : port === 443
68
+ ? `https://${host}${path}`
69
+ : `http://${host}:${port}${path}`,
70
+ local: `http://localhost:${port}${path}`,
71
+ apis: metadata.apis,
72
+ };
73
+
74
+ return resolve(true);
75
+ });
76
+ } catch (error) {
77
+ logger.error(error, { metadata, port, stack: error.stack });
78
+ resolve(false);
79
+ }
80
+ }),
81
+
82
+ async callback(deployId = 'default', env = 'development', options = { build: false, run: false }) {
83
+ if (options.build === true) await UnderpostStartUp.API.build(deployId, env);
84
+ if (options.run === true) await UnderpostStartUp.API.run(deployId, env);
85
+ },
86
+ async build(deployId = 'default', env = 'development') {
87
+ const buildBasePath = `/home/dd`;
88
+ const repoName = `engine-${deployId.split('-')[1]}`;
89
+ shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
90
+ shellExec(`cd ${buildBasePath} && sudo mv ./${repoName} ./engine`);
91
+ shellExec(`cd ${buildBasePath}/engine && underpost clone underpostnet/${repoName}-private`);
92
+ shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
93
+ shellCd(`${buildBasePath}/engine`);
94
+ shellExec(`npm install`);
95
+ shellExec(`node bin/deploy conf ${deployId} ${env}`);
96
+ if (fs.existsSync('./engine-private/itc-scripts')) {
97
+ const itcScripts = await fs.readdir('./engine-private/itc-scripts');
98
+ for (const itcScript of itcScripts)
99
+ if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
100
+ }
101
+ shellExec(`node bin/deploy build-full-client ${deployId}`);
102
+ },
103
+ async run(deployId = 'default', env = 'development') {
104
+ const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
105
+ if (fs.existsSync(`./engine-private/replica`)) {
106
+ const replicas = await fs.readdir(`./engine-private/replica`);
107
+ for (const replica of replicas) {
108
+ if (!replica.match(deployId)) continue;
109
+ shellExec(`node bin/deploy conf ${replica} ${env}`);
110
+ shellExec(`npm ${runCmd} deploy deploy-id:${replica}`, { async: true });
111
+ await awaitDeployMonitor(true);
112
+ }
113
+ }
114
+ shellExec(`node bin/deploy conf ${deployId} ${env}`);
115
+ shellExec(`npm ${runCmd} deploy deploy-id:${deployId}`, { async: true });
116
+ await awaitDeployMonitor(true);
117
+ UnderpostRootEnv.API.set('container-status', `${deployId}-${env}-running-deployment`);
118
+ },
119
+ };
120
+ }
121
+
122
+ export default UnderpostStartUp;
@@ -5,12 +5,24 @@ import { loggerFactory } from './logger.js';
5
5
 
6
6
  const logger = loggerFactory(import.meta);
7
7
 
8
+ const ValkeyInstances = {};
9
+
8
10
  let valkeyEnabled = true;
9
11
 
10
12
  const disableValkeyErrorMessage = 'valkey is not enabled';
11
13
 
12
14
  const isValkeyEnable = () => valkeyEnabled;
13
15
 
16
+ const createValkeyConnection = async (
17
+ instance = { host: '', port: 0 },
18
+ valkeyServerConnectionOptions = { host: '', port: 0 },
19
+ ) => {
20
+ ValkeyInstances[`${instance.host}${instance.path}`] = await ValkeyAPI.valkeyClientFactory(
21
+ valkeyServerConnectionOptions,
22
+ );
23
+ return ValkeyInstances[`${instance.host}${instance.path}`];
24
+ };
25
+
14
26
  const selectDtoFactory = (payload, select) => {
15
27
  const result = {};
16
28
  for (const key of Object.keys(select)) {
@@ -19,10 +31,12 @@ const selectDtoFactory = (payload, select) => {
19
31
  return result;
20
32
  };
21
33
 
22
- const valkeyClientFactory = async () => {
34
+ const valkeyClientFactory = async (options) => {
23
35
  const valkey = new Valkey({
24
36
  // port: 6379,
25
37
  // host: 'service-valkey.default.svc.cluster.local',
38
+ port: options?.port ? options.port : undefined,
39
+ host: options?.port ? options.host : undefined,
26
40
  retryStrategy: (attempt) => {
27
41
  if (attempt === 1) {
28
42
  valkey.disconnect();
@@ -46,12 +60,12 @@ const valkeyClientFactory = async () => {
46
60
  return valkey;
47
61
  };
48
62
 
49
- const getValkeyObject = async (key = '') => {
63
+ const getValkeyObject = async (options = { host: '', port: 0 }, key = '') => {
50
64
  if (!valkeyEnabled) {
51
65
  logger.warn(disableValkeyErrorMessage + ' get', key);
52
66
  return null;
53
67
  }
54
- const object = await valkey.get(key);
68
+ const object = await ValkeyInstances[`${options.host}${options.path}`].get(key);
55
69
  try {
56
70
  return JSON.parse(object);
57
71
  } catch (error) {
@@ -60,19 +74,19 @@ const getValkeyObject = async (key = '') => {
60
74
  }
61
75
  };
62
76
 
63
- const setValkeyObject = async (key = '', payload = {}) => {
77
+ const setValkeyObject = async (options = { host: '', port: 0 }, key = '', payload = {}) => {
64
78
  if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
65
- return await valkey.set(key, JSON.stringify(payload));
79
+ return await ValkeyInstances[`${options.host}${options.path}`].set(key, JSON.stringify(payload));
66
80
  };
67
81
 
68
- const updateValkeyObject = async (key = '', payload = {}) => {
82
+ const updateValkeyObject = async (options = { host: '', port: 0 }, key = '', payload = {}) => {
69
83
  if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
70
- const object = await getValkeyObject(key, valkey);
84
+ const object = await getValkeyObject(key);
71
85
  object.updatedAt = new Date().toISOString();
72
- return await valkey.set(key, JSON.stringify({ ...object, ...payload }));
86
+ return await ValkeyInstances[`${options.host}${options.path}`].set(key, JSON.stringify({ ...object, ...payload }));
73
87
  };
74
88
 
75
- const valkeyObjectFactory = async (module = '', options = { host: 'localhost', object: {} }) => {
89
+ const valkeyObjectFactory = async (options = { host: 'localhost', object: {} }, module = '') => {
76
90
  if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
77
91
  const idoDate = new Date().toISOString();
78
92
  options.object = options.object || {};
@@ -112,10 +126,9 @@ const ValkeyAPI = {
112
126
  setValkeyObject,
113
127
  valkeyObjectFactory,
114
128
  updateValkeyObject,
129
+ createValkeyConnection,
115
130
  };
116
131
 
117
- const valkey = await ValkeyAPI.valkeyClientFactory();
118
-
119
132
  export {
120
133
  valkeyClientFactory,
121
134
  selectDtoFactory,
@@ -124,5 +137,6 @@ export {
124
137
  valkeyObjectFactory,
125
138
  updateValkeyObject,
126
139
  isValkeyEnable,
140
+ createValkeyConnection,
127
141
  ValkeyAPI,
128
142
  };
package/test/api.test.js CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import axios from 'axios';
4
4
  import dotenv from 'dotenv';
5
- import https from 'https';
6
5
 
7
6
  import { expect } from 'chai';
8
7
  import { loggerFactory } from '../src/server/logger.js';
@@ -20,13 +19,6 @@ const BASE_URL =
20
19
  ? `http://localhost:${PORT}/${process.env.BASE_API}`
21
20
  : `https://www.nexodev.org/api`;
22
21
 
23
- axios.defaults.baseURL = BASE_URL;
24
-
25
- const httpsAgent = new https.Agent({
26
- rejectUnauthorized: false,
27
- });
28
- axios.defaults.httpsAgent = httpsAgent;
29
-
30
22
  describe(`GET 'Test' API Request `, async () => {
31
23
  {
32
24
  const url = `${BASE_URL}/test/youtube-id/?url=https://www.youtube.com/watch?v=o4f42SbyDMk`;