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
package/src/cli/test.js CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Test module for running tests on the application.
3
+ * @module src/cli/test.js
4
+ * @namespace UnderpostTest
5
+ */
6
+
1
7
  import { timer } from '../client/components/core/CommonJs.js';
2
8
  import { MariaDB } from '../db/mariadb/MariaDB.js';
3
9
  import { getNpmRootPath } from '../server/conf.js';
@@ -7,6 +13,11 @@ import UnderpostDeploy from './deploy.js';
7
13
 
8
14
  const logger = loggerFactory(import.meta);
9
15
 
16
+ /**
17
+ * @class UnderpostTest
18
+ * @description Manages the test of the application.
19
+ * @memberof UnderpostTest
20
+ */
10
21
  class UnderpostTest {
11
22
  static API = {
12
23
  /**
@@ -20,15 +31,35 @@ class UnderpostTest {
20
31
  * @static
21
32
  * @method setUpInfo
22
33
  * @returns {Promise<void>}
23
- * @memberof Underpost
34
+ * @memberof UnderpostTest
24
35
  */
25
36
  async setUpInfo() {
26
37
  return await setUpInfo(logger);
27
38
  },
39
+ /**
40
+ * @method run
41
+ * @description Runs the test of the application.
42
+ * @memberof UnderpostTest
43
+ */
28
44
  run() {
29
45
  actionInitLog();
30
46
  shellExec(`cd ${getNpmRootPath()}/underpost && npm run test`);
31
47
  },
48
+ /**
49
+ * @method callback
50
+ * @description Manages the test of the application.
51
+ * @param {string} deployList - The list of deployments to test.
52
+ * @param {object} options - The options for the test.
53
+ * @param {boolean} options.itc - If true, tests the inside container.
54
+ * @param {boolean} options.sh - If true, tests the shell.
55
+ * @param {boolean} options.logs - If true, tests the logs.
56
+ * @param {string} options.podName - The name of the pod to test.
57
+ * @param {string} options.podStatus - The status of the pod to test.
58
+ * @param {string} options.kindType - The type of the kind to test.
59
+ * @param {number} options.deltaMs - The delta time in milliseconds.
60
+ * @param {number} options.maxAttempts - The maximum number of attempts.
61
+ * @memberof UnderpostTest
62
+ */
32
63
  async callback(deployList = '', options = { itc: false, sh: false, logs: false }) {
33
64
  if (
34
65
  options.podName &&
@@ -86,6 +117,16 @@ class UnderpostTest {
86
117
  }
87
118
  } else return UnderpostTest.API.run();
88
119
  },
120
+ /**
121
+ * @method statusMonitor
122
+ * @description Monitors the status of a pod.
123
+ * @param {string} podName - The name of the pod to monitor.
124
+ * @param {string} status - The status of the pod to monitor.
125
+ * @param {string} kindType - The type of the kind to monitor.
126
+ * @param {number} deltaMs - The delta time in milliseconds.
127
+ * @param {number} maxAttempts - The maximum number of attempts.
128
+ * @memberof UnderpostTest
129
+ */
89
130
  statusMonitor(podName, status = 'Running', kindType = '', deltaMs = 1000, maxAttempts = 60 * 5) {
90
131
  if (!(kindType && typeof kindType === 'string')) kindType = 'pods';
91
132
  return new Promise(async (resolve) => {
@@ -690,14 +690,6 @@ const scrollBarLightRender = () => {
690
690
  .join('');
691
691
  };
692
692
 
693
- /**
694
- * Adjust hex color brightness toward white/black ("mix") or by modifying HSL lightness ("hsl").
695
- *
696
- * @param {string} hex - Color as '#rrggbb', 'rrggbb', '#rgb', or 'rgb'.
697
- * @param {number} factor - -1..1 or -100..100 (percent). Positive = lighten, negative = darken.
698
- * @param {{mode?: 'mix'|'hsl'}} [options]
699
- * @returns {string} - Adjusted color as '#rrggbb' (lowercase).
700
- */
701
693
  function adjustHex(hex, factor = 0.1, options = {}) {
702
694
  if (typeof hex !== 'string') throw new TypeError('hex must be a string');
703
695
  if (typeof factor !== 'number') throw new TypeError('factor must be a number');
@@ -831,6 +823,14 @@ const subThemeManager = {
831
823
  color: ${this.lightColor};
832
824
  background-color: ${lightenHex(this.lightColor, 0.8)};
833
825
  }
826
+ .main-sub-btn-active {
827
+ color: ${this.lightColor};
828
+ background-color: rgba(0, 0, 0, 0.3);
829
+ }
830
+ .main-sub-btn-active:hover {
831
+ color: ${this.lightColor};
832
+ background-color: rgba(0, 0, 0, 0.2);
833
+ }
834
834
  </style>`;
835
835
  };
836
836
  },
@@ -845,6 +845,14 @@ const subThemeManager = {
845
845
  color: ${lightenHex(this.darkColor, 0.8)};
846
846
  background-color: ${darkenHex(this.darkColor, 0.75)};
847
847
  }
848
+ .main-sub-btn-active {
849
+ color: ${lightenHex(this.darkColor, 0.8)};
850
+ background-color: rgba(255, 255, 255, 0.3);
851
+ }
852
+ .main-sub-btn-active:hover {
853
+ color: ${lightenHex(this.darkColor, 0.8)};
854
+ background-color: rgba(255, 255, 255, 0.2);
855
+ }
848
856
  </style>`;
849
857
  };
850
858
  },
@@ -8,7 +8,7 @@ import { htmls, s } from './VanillaJs.js';
8
8
  // https://mintlify.com/docs/quickstart
9
9
 
10
10
  const Docs = {
11
- RenderModal: async function (type, modalOptions) {
11
+ RenderModal: async function (type) {
12
12
  const docData = this.Data.find((d) => d.type === type);
13
13
  const ModalId = `modal-docs-${docData.type}`;
14
14
  const { barConfig } = await Themes[Css.currentTheme]();
@@ -35,7 +35,7 @@ const Docs = {
35
35
  observer: true,
36
36
  barMode: 'top-bottom-bar',
37
37
  query: true,
38
- ...modalOptions,
38
+ RouterInstance: Modal.Data['modal-docs'].options.RouterInstance,
39
39
  });
40
40
  Modal.Data[ModalId].onObserverListener[ModalId] = () => {
41
41
  if (s(`.iframe-${ModalId}`))
@@ -118,25 +118,17 @@ const Docs = {
118
118
  const { idModal } = options;
119
119
  this.Tokens[idModal] = options;
120
120
  setTimeout(() => {
121
- const cleanActive = () => {
122
- s(`.btn-docs-src`).classList.remove('main-btn-menu-active');
123
- s(`.btn-docs-api`).classList.remove('main-btn-menu-active');
124
- s(`.btn-docs-coverage`).classList.remove('main-btn-menu-active');
125
- };
126
121
  s(`.btn-docs-src`).onclick = async () => {
127
122
  setQueryPath({ path: 'docs', queryPath: 'src' });
128
- cleanActive();
129
- await this.RenderModal('src', options.modalOptions);
123
+ await this.RenderModal('src');
130
124
  };
131
125
  s(`.btn-docs-api`).onclick = async () => {
132
126
  setQueryPath({ path: 'docs', queryPath: 'api' });
133
- cleanActive();
134
- await this.RenderModal('api', options.modalOptions);
127
+ await this.RenderModal('api');
135
128
  };
136
129
  s(`.btn-docs-coverage`).onclick = async () => {
137
130
  setQueryPath({ path: 'docs', queryPath: 'coverage' });
138
- cleanActive();
139
- await this.RenderModal('coverage', options.modalOptions);
131
+ await this.RenderModal('coverage');
140
132
  };
141
133
 
142
134
  s(`.btn-docs-coverage-link`).onclick = () => {
@@ -21,6 +21,8 @@ import {
21
21
  getProxyPath,
22
22
  setPath,
23
23
  coreUI,
24
+ sanitizeRoute,
25
+ getQueryParams,
24
26
  } from './Router.js';
25
27
  import { NotificationManager } from './NotificationManager.js';
26
28
  import { EventsUI } from './EventsUI.js';
@@ -90,11 +92,6 @@ const Modal = {
90
92
  query: options.query ? `${window.location.search}` : undefined,
91
93
  getTop: () => {
92
94
  const result = windowGetH() - (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar);
93
- // TODO: mobile padding gap on init size top height, Iphone SE responsive case
94
- // logger.warn('getTop', {
95
- // top: result,
96
- // height: Modal.Data[idModal].getHeight(),
97
- // });
98
95
  return result;
99
96
  },
100
97
  getHeight: () => {
@@ -120,6 +117,10 @@ const Modal = {
120
117
  }px`
121
118
  : `-${ops?.open ? '0px' : originSlideMenuWidth}px`
122
119
  }`,
120
+ center: () => {
121
+ top = `${windowGetH() / 2 - height / 2}px`;
122
+ left = `${windowGetW() / 2 - width / 2}px`;
123
+ },
123
124
  };
124
125
 
125
126
  if (options && 'mode' in options) {
@@ -1169,6 +1170,7 @@ const Modal = {
1169
1170
  });
1170
1171
  EventsUI.onClick(`.action-btn-home`, async () => {
1171
1172
  await Modal.onHomeRouterEvent();
1173
+ subMenuHandler(Object.keys(options.RouterInstance.Routes()));
1172
1174
  Object.keys(this.Data[idModal].onHome).map((keyListener) => this.Data[idModal].onHome[keyListener]());
1173
1175
  });
1174
1176
  EventsUI.onClick(`.action-btn-app-icon`, () => s(`.action-btn-home`).click());
@@ -1349,7 +1351,6 @@ const Modal = {
1349
1351
  removeEvent();
1350
1352
  }
1351
1353
  });
1352
- // TODO: mobile padding gap on init size top height, Iphone SE responsive case
1353
1354
  setTimeout(window.onresize);
1354
1355
  });
1355
1356
  })();
@@ -1387,10 +1388,7 @@ const Modal = {
1387
1388
  return;
1388
1389
  }
1389
1390
 
1390
- if (idModal !== 'main-body' && options.mode !== 'view' && !options.disableCenter) {
1391
- top = `${windowGetH() / 2 - height / 2}px`;
1392
- left = `${windowGetW() / 2 - width / 2}px`;
1393
- }
1391
+ if (idModal !== 'main-body' && options.mode !== 'view' && !options.disableCenter) Modal.Data[idModal].center();
1394
1392
 
1395
1393
  const render = html` <style class="style-${idModal}">
1396
1394
  .${idModal} {
@@ -1860,26 +1858,14 @@ const Modal = {
1860
1858
  s(`.btn-maximize-${idModal}`).style.display = null;
1861
1859
 
1862
1860
  // Restore original dimensions and position
1861
+ this.Data[idModal].center();
1863
1862
  modal.style.transform = '';
1864
- modal.style.height = '';
1865
- left = 0;
1866
- width = 300;
1867
- modal.style.left = `${left}px`;
1863
+ modal.style.height = `${height}px`;
1864
+ modal.style.left = left;
1865
+ modal.style.top = top;
1868
1866
  modal.style.width = `${width}px`;
1869
1867
  modal.style.overflow = '';
1870
1868
 
1871
- // Reset drag position
1872
- dragPosition = { x: 0, y: 0 };
1873
-
1874
- // Set new position
1875
- modal.style.transform = `translate(0, 0)`;
1876
-
1877
- // Adjust top position based on top bar visibility
1878
- const heightDefaultTopBar = 40; // Default top bar height if not specified
1879
- s(`.${idModal}`).style.top = s(`.main-body-btn-ui-close`).classList.contains('hide')
1880
- ? `0px`
1881
- : `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
1882
-
1883
1869
  // Re-enable drag after restore
1884
1870
  if (dragInstance) {
1885
1871
  dragInstance.updateOptions({
@@ -2413,7 +2399,7 @@ const buildBadgeToolTipMenuOption = (id, sideKey = 'left') => {
2413
2399
  };
2414
2400
 
2415
2401
  const isSubMenuOpen = (subMenuId) => {
2416
- return s(`.down-arrow-submenu-${subMenuId}`).style.rotate === '180deg';
2402
+ return s(`.down-arrow-submenu-${subMenuId}`) && s(`.down-arrow-submenu-${subMenuId}`).style.rotate === '180deg';
2417
2403
  };
2418
2404
 
2419
2405
  const subMenuRender = async (subMenuId) => {
@@ -2425,7 +2411,15 @@ const subMenuRender = async (subMenuId) => {
2425
2411
  if (!menuBtn || !menuContainer || !arrow) return;
2426
2412
 
2427
2413
  const top = () => {
2428
- menuContainer.style.top = menuBtn.offsetTop + Modal.Data['modal-menu'].options.heightTopBar + 'px';
2414
+ let value = menuBtn.offsetTop + Modal.Data['modal-menu'].options.heightTopBar;
2415
+
2416
+ const isHidden = s('.main-body-btn-ui-open').classList.contains('hide');
2417
+ const isTopBottom = Modal.Data['modal-menu'].options.barMode === 'top-bottom-bar';
2418
+
2419
+ if (!isTopBottom && isHidden) value -= 51;
2420
+ else if (!isHidden) value += 51;
2421
+
2422
+ menuContainer.style.top = `${value}px`;
2429
2423
  };
2430
2424
 
2431
2425
  Modal.subMenuBtnClass[subMenuId] = {
@@ -2472,4 +2466,29 @@ const subMenuRender = async (subMenuId) => {
2472
2466
  }, 500);
2473
2467
  };
2474
2468
 
2475
- export { Modal, renderMenuLabel, renderViewTitle, buildBadgeToolTipMenuOption, subMenuRender, isSubMenuOpen };
2469
+ const subMenuHandler = (routes, route) => {
2470
+ route = sanitizeRoute(route);
2471
+ for (let _route of routes) {
2472
+ _route = sanitizeRoute(_route);
2473
+ if (_route !== route) {
2474
+ if (isSubMenuOpen(_route)) subMenuRender(_route);
2475
+ }
2476
+ }
2477
+ setTimeout(() => {
2478
+ let cid = getQueryParams().cid;
2479
+ if (s(`.main-sub-btn-active`)) s(`.main-sub-btn-active`).classList.remove('main-sub-btn-active');
2480
+ if (cid && s(`.btn-${route}-${cid}`)) {
2481
+ s(`.btn-${route}-${cid}`).classList.add('main-sub-btn-active');
2482
+ }
2483
+ });
2484
+ };
2485
+
2486
+ export {
2487
+ Modal,
2488
+ renderMenuLabel,
2489
+ renderViewTitle,
2490
+ buildBadgeToolTipMenuOption,
2491
+ subMenuRender,
2492
+ isSubMenuOpen,
2493
+ subMenuHandler,
2494
+ };
@@ -7,7 +7,7 @@
7
7
  import { titleFormatted } from './CommonJs.js';
8
8
  import { loggerFactory } from './Logger.js';
9
9
  import { htmls, s } from './VanillaJs.js';
10
- import { Modal } from './Modal.js';
10
+ import { Modal, subMenuHandler } from './Modal.js';
11
11
  import { Worker } from './Worker.js';
12
12
 
13
13
  const logger = loggerFactory(import.meta, { trace: true });
@@ -162,6 +162,7 @@ const Router = function (options = { Routes: () => {}, e: new PopStateEvent() })
162
162
 
163
163
  if (path === pushPath) {
164
164
  for (const event of Object.keys(RouterEvents)) RouterEvents[event](routerEvent);
165
+ subMenuHandler(Object.keys(Routes()), route);
165
166
  setDocTitle(route);
166
167
  return Routes()[`/${route}`].render();
167
168
  }
@@ -256,14 +257,15 @@ const closeModalRouteChangeEvent = (options = {}) => {
256
257
  * @param {string} options.route - The route associated with the modal view.
257
258
  * @memberof PwaRouter
258
259
  */
259
- const handleModalViewRoute = (options = { route: '' }) => {
260
- const { route } = options;
260
+ const handleModalViewRoute = (options = { RouterInstance: { Routes: () => {} }, route: '' }) => {
261
+ const { route, RouterInstance } = options;
261
262
  if (!route) return;
262
263
 
263
264
  let path = window.location.pathname;
264
265
  if (path !== '/' && path[path.length - 1] === '/') path = path.slice(0, -1);
265
266
  const proxyPath = getProxyPath();
266
267
  const newPath = `${proxyPath}${route}`;
268
+ if (RouterInstance && RouterInstance.Routes) subMenuHandler(Object.keys(RouterInstance.Routes()), route);
267
269
 
268
270
  if (path !== newPath) {
269
271
  setPath(newPath);
@@ -311,4 +313,5 @@ export {
311
313
  getProxyPath,
312
314
  setPath,
313
315
  setQueryParams,
316
+ sanitizeRoute,
314
317
  };