underpost 3.2.21 → 3.2.28

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 (55) hide show
  1. package/.github/workflows/ghpkg.ci.yml +1 -1
  2. package/.github/workflows/gitlab.ci.yml +1 -1
  3. package/.github/workflows/npmpkg.ci.yml +1 -1
  4. package/.github/workflows/publish.ci.yml +2 -2
  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 +178 -1
  8. package/CLI-HELP.md +58 -2
  9. package/README.md +3 -2
  10. package/baremetal/commission-workflows.json +1 -0
  11. package/bin/build.js +13 -1
  12. package/docker-compose.yml +224 -0
  13. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  14. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  15. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  16. package/package.json +27 -15
  17. package/scripts/kubeadm-node-setup.sh +317 -0
  18. package/scripts/rocky-kickstart.sh +877 -185
  19. package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
  20. package/scripts/test-monitor.sh +242 -78
  21. package/src/cli/baremetal.js +717 -16
  22. package/src/cli/cluster.js +3 -1
  23. package/src/cli/deploy.js +11 -10
  24. package/src/cli/docker-compose.js +591 -0
  25. package/src/cli/fs.js +35 -11
  26. package/src/cli/index.js +83 -0
  27. package/src/cli/kickstart.js +142 -20
  28. package/src/cli/monitor.js +114 -29
  29. package/src/cli/repository.js +75 -11
  30. package/src/cli/run.js +275 -6
  31. package/src/cli/ssh.js +190 -0
  32. package/src/cli/static.js +2 -2
  33. package/src/client/components/core/PanelForm.js +44 -44
  34. package/src/{server → client-builder}/client-build-docs.js +15 -5
  35. package/src/{server → client-builder}/client-build-live.js +3 -3
  36. package/src/{server → client-builder}/client-build.js +25 -22
  37. package/src/{server → client-builder}/client-dev-server.js +3 -3
  38. package/src/{server → client-builder}/client-icons.js +2 -2
  39. package/src/{server → client-builder}/ssr.js +5 -5
  40. package/src/client.build.js +1 -1
  41. package/src/client.dev.js +1 -1
  42. package/src/index.js +12 -1
  43. package/src/mailer/EmailRender.js +1 -1
  44. package/src/{server → projects/underpost}/catalog-underpost.js +1 -2
  45. package/src/runtime/express/Express.js +2 -2
  46. package/src/runtime/nginx/Nginx.js +250 -0
  47. package/src/server/catalog.js +7 -14
  48. package/src/server/conf.js +61 -12
  49. package/src/server/start.js +17 -5
  50. package/src/server.js +1 -1
  51. package/test/deploy-monitor.test.js +33 -5
  52. package/typedoc.json +3 -1
  53. package/src/server/ipfs-client.js +0 -597
  54. /package/src/client/ssr/{Render.js → RootDocument.js} +0 -0
  55. /package/src/{server → client-builder}/client-formatted.js +0 -0
package/src/cli/static.js CHANGED
@@ -6,10 +6,10 @@
6
6
  import fs from 'fs-extra';
7
7
  import path from 'path';
8
8
  import express from 'express';
9
- import { ssrFactory } from '../server/ssr.js';
9
+ import { ssrFactory } from '../client-builder/ssr.js';
10
10
  import { shellExec } from '../server/process.js';
11
11
  import Underpost from '../index.js';
12
- import { JSONweb } from '../server/client-formatted.js';
12
+ import { JSONweb } from '../client-builder/client-formatted.js';
13
13
  import { loggerFactory, loggerMiddleware } from '../server/logger.js';
14
14
  const logger = loggerFactory(import.meta);
15
15
  /**
@@ -73,7 +73,7 @@ class PanelForm {
73
73
  parentIdModal: undefined,
74
74
  route: 'home',
75
75
  htmlFormHeader: async () => '',
76
- firsUpdateEvent: async () => { },
76
+ firsUpdateEvent: async () => {},
77
77
  share: {
78
78
  copyLink: false,
79
79
  copySourceMd: false,
@@ -196,12 +196,12 @@ class PanelForm {
196
196
  <img
197
197
  class="abs center"
198
198
  style="${renderCssAttr({
199
- style: {
200
- width: '100px',
201
- height: '100px',
202
- opacity: 0.2,
203
- },
204
- })}"
199
+ style: {
200
+ width: '100px',
201
+ height: '100px',
202
+ opacity: 0.2,
203
+ },
204
+ })}"
205
205
  src="${defaultUrlImage}"
206
206
  />
207
207
  `,
@@ -382,15 +382,15 @@ class PanelForm {
382
382
  // It will be filtered from the tags array to keep visibility control separate from content tags
383
383
  const tags = data.tags
384
384
  ? uniqueArray(
385
- data.tags
386
- .replaceAll('/', ',')
387
- .replaceAll('-', ',')
388
- .replaceAll(' ', ',')
389
- .split(',')
390
- .map((t) => t.trim())
391
- .filter((t) => t)
392
- .concat(prefixTags),
393
- )
385
+ data.tags
386
+ .replaceAll('/', ',')
387
+ .replaceAll('-', ',')
388
+ .replaceAll(' ', ',')
389
+ .split(',')
390
+ .map((t) => t.trim())
391
+ .filter((t) => t)
392
+ .concat(prefixTags),
393
+ )
394
394
  : prefixTags;
395
395
  let originObj, originFileObj, indexOriginObj;
396
396
  if (editId) {
@@ -432,8 +432,8 @@ class PanelForm {
432
432
  // In edit mode, null means user cleared the file - we need to tell server to remove it
433
433
  const isFileCleared = data.fileId === null && editId;
434
434
  await (async () => {
435
- // When file is null and not the first iteration or not in edit mode, skip upload
436
- if (!file && !isFileCleared) return;
435
+ // When file is null, no markdown content, and not clearing a file, skip upload
436
+ if (!file && !isFileCleared && !hasMdContent) return;
437
437
  // When user cleared file in edit mode, set fileId=null so server removes the reference
438
438
  if (isFileCleared) {
439
439
  fileId = null;
@@ -489,8 +489,8 @@ class PanelForm {
489
489
  message: documentMessage,
490
490
  data: documentData,
491
491
  } = originObj && indexFormDoc === 0
492
- ? await DocumentService.put({ id: originObj._id, body })
493
- : await DocumentService.post({
492
+ ? await DocumentService.put({ id: originObj._id, body })
493
+ : await DocumentService.post({
494
494
  body,
495
495
  });
496
496
  const newDoc = {
@@ -518,12 +518,12 @@ class PanelForm {
518
518
  fileId: {
519
519
  fileBlob: file
520
520
  ? {
521
- data: {
522
- data: await getDataFromInputFile(file),
523
- },
524
- mimetype: file.type,
525
- name: file.name,
526
- }
521
+ data: {
522
+ data: await getDataFromInputFile(file),
523
+ },
524
+ mimetype: file.type,
525
+ name: file.name,
526
+ }
527
527
  : undefined,
528
528
  filePlain: undefined,
529
529
  },
@@ -742,36 +742,36 @@ class PanelForm {
742
742
  <div
743
743
  class="in fll ssr-shimmer-search-box"
744
744
  style="${renderCssAttr({
745
- style: {
746
- width: '80%',
747
- height: '30px',
748
- top: '-13px',
749
- left: '10px',
750
- },
751
- })}"
745
+ style: {
746
+ width: '80%',
747
+ height: '30px',
748
+ top: '-13px',
749
+ left: '10px',
750
+ },
751
+ })}"
752
752
  ></div>
753
753
  </div>`,
754
754
  createdAt: html`<div class="fl">
755
755
  <div
756
756
  class="in fll ssr-shimmer-search-box"
757
757
  style="${renderCssAttr({
758
- style: {
759
- width: '50%',
760
- height: '30px',
761
- left: '-5px',
762
- },
763
- })}"
758
+ style: {
759
+ width: '50%',
760
+ height: '30px',
761
+ left: '-5px',
762
+ },
763
+ })}"
764
764
  ></div>
765
765
  </div>`,
766
766
  mdFileId: html`<div class="fl section-mp">
767
767
  <div
768
768
  class="in fll ssr-shimmer-search-box"
769
769
  style="${renderCssAttr({
770
- style: {
771
- width: '80%',
772
- height: '30px',
773
- },
774
- })}"
770
+ style: {
771
+ width: '80%',
772
+ height: '30px',
773
+ },
774
+ })}"
775
775
  ></div>
776
776
  </div>`.repeat(random(2, 4)),
777
777
  ssr: true,
@@ -2,13 +2,13 @@
2
2
 
3
3
  /**
4
4
  * Module for building project documentation (JSDoc, Swagger, Coverage).
5
- * @module src/server/client-build-docs.js
5
+ * @module src/client-builder/client-build-docs.js
6
6
  * @namespace clientBuildDocs
7
7
  */
8
8
 
9
9
  import fs from 'fs-extra';
10
- import { shellExec } from './process.js';
11
- import { loggerFactory } from './logger.js';
10
+ import { shellExec } from '../server/process.js';
11
+ import { loggerFactory } from '../server/logger.js';
12
12
  import { JSONweb } from './client-formatted.js';
13
13
  import { ssrFactory } from './ssr.js';
14
14
 
@@ -396,10 +396,20 @@ const buildCoverage = async ({ docs, docsDestination }) => {
396
396
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
397
397
  if (pkg.scripts && pkg.scripts.coverage) {
398
398
  logger.info('generating coverage report', coveragePath);
399
- shellExec(`cd ${coveragePath} && npm run coverage`, { silent: true });
399
+ try {
400
+ await shellExec(`cd ${coveragePath} && npm run coverage`, { silent: true });
401
+ } catch (err) {
402
+ logger.warn('coverage generation failed (non-fatal), skipping:', err.message);
403
+ return;
404
+ }
400
405
  } else if (pkg.scripts && pkg.scripts.test) {
401
406
  logger.info('generating coverage via test', coveragePath);
402
- shellExec(`cd ${coveragePath} && npm test`, { silent: true, silentOnError: true });
407
+ try {
408
+ await shellExec(`cd ${coveragePath} && npm test`, { silent: true, silentOnError: true });
409
+ } catch (err) {
410
+ logger.warn('coverage generation failed (non-fatal), skipping:', err.message);
411
+ return;
412
+ }
403
413
  }
404
414
  }
405
415
  }
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Module for live building client-side code
3
- * @module src/server/client-build-live.js
3
+ * @module src/client-builder/client-build-live.js
4
4
  * @namespace clientLiveBuild
5
5
  */
6
6
 
7
7
  import fs from 'fs-extra';
8
- import { Config, loadConf, readConfJson } from './conf.js';
9
- import { loggerFactory } from './logger.js';
8
+ import { Config, loadConf, readConfJson } from '../server/conf.js';
9
+ import { loggerFactory } from '../server/logger.js';
10
10
  import { buildClient } from './client-build.js';
11
11
 
12
12
  const logger = loggerFactory(import.meta);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Manages the client-side build process, including full builds and incremental builds.
3
- * @module server/client-build.js
3
+ * @module src/client-builder/client-build.js
4
4
  * @namespace clientBuild
5
5
  */
6
6
 
@@ -8,18 +8,18 @@
8
8
 
9
9
  import fs from 'fs-extra';
10
10
  import { transformClientJs, JSONweb } from './client-formatted.js';
11
- import { loggerFactory } from './logger.js';
11
+ import { loggerFactory } from '../server/logger.js';
12
12
  import {
13
13
  getCapVariableName,
14
14
  newInstance,
15
15
  orderArrayFromAttrInt,
16
16
  uniqueArray,
17
17
  } from '../client/components/core/CommonJs.js';
18
- import { readConfJson } from './conf.js';
18
+ import { readConfJson } from '../server/conf.js';
19
19
  import { minify } from 'html-minifier-terser';
20
20
  import AdmZip from 'adm-zip';
21
21
  import * as dir from 'path';
22
- import { shellExec } from './process.js';
22
+ import { shellExec } from '../server/process.js';
23
23
  import { SitemapStream, streamToPromise } from 'sitemap';
24
24
  import { Readable } from 'stream';
25
25
  import { buildIcons } from './client-icons.js';
@@ -751,8 +751,9 @@ const buildClient = async (
751
751
  )
752
752
  )
753
753
  for (const view of views) {
754
- const buildPath = `${rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
755
- }${view.path === '/' ? view.path : `${view.path}/`}`;
754
+ const buildPath = `${
755
+ rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
756
+ }${view.path === '/' ? view.path : `${view.path}/`}`;
756
757
 
757
758
  if (!fs.existsSync(buildPath)) fs.mkdirSync(buildPath, { recursive: true });
758
759
 
@@ -768,8 +769,9 @@ const buildClient = async (
768
769
  fs.writeFileSync(`${buildPath}${buildId}.js`, jsSrc, 'utf8');
769
770
  const title = metadata.title ? metadata.title : title;
770
771
 
771
- const canonicalURL = `https://${host}${path}${view.path === '/' ? (path === '/' ? '' : '/') : path === '/' ? `${view.path.slice(1)}/` : `${view.path}/`
772
- }`;
772
+ const canonicalURL = `https://${host}${path}${
773
+ view.path === '/' ? (path === '/' ? '' : '/') : path === '/' ? `${view.path.slice(1)}/` : `${view.path}/`
774
+ }`;
773
775
 
774
776
  let ssrHeadComponents = ``;
775
777
  let ssrBodyComponents = ``;
@@ -903,12 +905,12 @@ const buildClient = async (
903
905
  `${buildPath}index.html`,
904
906
  minifyBuild
905
907
  ? await minify(htmlSrc, {
906
- minifyCSS: true,
907
- minifyJS: true,
908
- collapseBooleanAttributes: true,
909
- collapseInlineTagWhitespace: true,
910
- collapseWhitespace: true,
911
- })
908
+ minifyCSS: true,
909
+ minifyJS: true,
910
+ collapseBooleanAttributes: true,
911
+ collapseInlineTagWhitespace: true,
912
+ collapseWhitespace: true,
913
+ })
912
914
  : htmlSrc,
913
915
  'utf8',
914
916
  );
@@ -997,8 +999,9 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
997
999
  renderApi: { JSONweb },
998
1000
  });
999
1001
 
1000
- const buildPath = `${rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
1001
- }${view.path === '/' ? view.path : `${view.path}/`}`;
1002
+ const buildPath = `${
1003
+ rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
1004
+ }${view.path === '/' ? view.path : `${view.path}/`}`;
1002
1005
 
1003
1006
  const indexUrl = buildIndexUrl(view.path);
1004
1007
  if (view.offlineDefault) {
@@ -1018,12 +1021,12 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
1018
1021
  buildHtmlPath,
1019
1022
  minifyBuild
1020
1023
  ? await minify(htmlSrc, {
1021
- minifyCSS: true,
1022
- minifyJS: true,
1023
- collapseBooleanAttributes: true,
1024
- collapseInlineTagWhitespace: true,
1025
- collapseWhitespace: true,
1026
- })
1024
+ minifyCSS: true,
1025
+ minifyJS: true,
1026
+ collapseBooleanAttributes: true,
1027
+ collapseInlineTagWhitespace: true,
1028
+ collapseWhitespace: true,
1029
+ })
1027
1030
  : htmlSrc,
1028
1031
  'utf8',
1029
1032
  );
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Module for creating a client-side development server
3
- * @module src/server/client-dev-server.js
3
+ * @module src/client-builder/client-dev-server.js
4
4
  * @namespace clientDevServer
5
5
  */
6
6
  import fs from 'fs-extra';
7
7
  import nodemon from 'nodemon';
8
8
  import dotenv from 'dotenv';
9
- import { shellExec } from './process.js';
10
- import { loggerFactory } from './logger.js';
9
+ import { shellExec } from '../server/process.js';
10
+ import { loggerFactory } from '../server/logger.js';
11
11
  import Underpost from '../index.js';
12
12
 
13
13
  const logger = loggerFactory(import.meta);
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Module for building client-side icons
3
- * @module src/server/client-icons.js
3
+ * @module src/client-builder/client-icons.js
4
4
  * @namespace clientIcons
5
5
  */
6
6
  import { favicons } from 'favicons';
7
- import { loggerFactory } from './logger.js';
7
+ import { loggerFactory } from '../server/logger.js';
8
8
  import fs from 'fs-extra';
9
9
  import { getCapVariableName } from '../client/components/core/CommonJs.js';
10
10
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Module for managing server side rendering
3
- * @module src/server/ssr.js
3
+ * @module src/client-builder/ssr.js
4
4
  * @namespace ServerSideRendering
5
5
  */
6
6
 
@@ -10,19 +10,19 @@ import vm from 'node:vm';
10
10
  import Underpost from '../index.js';
11
11
 
12
12
  import { srcFormatted, JSONweb } from './client-formatted.js';
13
- import { loggerFactory } from './logger.js';
14
- import { getRootDirectory } from './process.js';
13
+ import { loggerFactory } from '../server/logger.js';
14
+ import { getRootDirectory } from '../server/process.js';
15
15
 
16
16
  const logger = loggerFactory(import.meta);
17
17
 
18
18
  /**
19
19
  * Creates a server-side rendering component function from a given file path.
20
20
  * It reads the component file, formats it, and executes it in a sandboxed Node.js VM context to extract the component.
21
- * @param {string} [componentPath='./src/client/ssr/Render.js'] - The path to the SSR component file.
21
+ * @param {string} [componentPath='./src/client/ssr/RootDocument.js'] - The path to the SSR component file.
22
22
  * @returns {Promise<Function>} A promise that resolves to the SSR component function.
23
23
  * @memberof ServerSideRendering
24
24
  */
25
- const ssrFactory = async (componentPath = `./src/client/ssr/Render.js`) => {
25
+ const ssrFactory = async (componentPath = `./src/client/ssr/RootDocument.js`) => {
26
26
  const context = { SrrComponent: () => {}, npm_package_version: Underpost.version };
27
27
  vm.createContext(context);
28
28
  vm.runInContext(await srcFormatted(fs.readFileSync(componentPath, 'utf8')), context);
@@ -6,7 +6,7 @@
6
6
  import { loggerFactory } from './server/logger.js';
7
7
  import { Config } from './server/conf.js';
8
8
  import { ProcessController } from './server/process.js';
9
- import { clientLiveBuild } from './server/client-build-live.js';
9
+ import { clientLiveBuild } from './client-builder/client-build-live.js';
10
10
 
11
11
  await Config.build();
12
12
 
package/src/client.dev.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import { loggerFactory } from './server/logger.js';
7
7
  import { ProcessController } from './server/process.js';
8
8
  import { Config, buildClientStaticConf } from './server/conf.js';
9
- import { createClientDevServer } from './server/client-dev-server.js';
9
+ import { createClientDevServer } from './client-builder/client-dev-server.js';
10
10
 
11
11
  const logger = loggerFactory(import.meta);
12
12
 
package/src/index.js CHANGED
@@ -10,6 +10,7 @@ import UnderpostKickStart from './cli/kickstart.js';
10
10
  import UnderpostCluster from './cli/cluster.js';
11
11
  import UnderpostDB from './cli/db.js';
12
12
  import UnderpostDeploy from './cli/deploy.js';
13
+ import UnderpostDockerCompose from './cli/docker-compose.js';
13
14
  import UnderpostKubectl from './cli/kubectl.js';
14
15
  import UnderpostRootEnv from './cli/env.js';
15
16
  import UnderpostFileStorage from './cli/fs.js';
@@ -44,7 +45,7 @@ class Underpost {
44
45
  * @type {String}
45
46
  * @memberof Underpost
46
47
  */
47
- static version = 'v3.2.21';
48
+ static version = 'v3.2.28';
48
49
 
49
50
  /**
50
51
  * Required Node.js major version
@@ -146,6 +147,15 @@ class Underpost {
146
147
  static get deploy() {
147
148
  return UnderpostDeploy.API;
148
149
  }
150
+ /**
151
+ * Docker Compose pipeline cli API
152
+ * @static
153
+ * @type {UnderpostDockerCompose.API}
154
+ * @memberof Underpost
155
+ */
156
+ static get dockerCompose() {
157
+ return UnderpostDockerCompose.API;
158
+ }
149
159
  /**
150
160
  * File Storage cli API
151
161
  * @static
@@ -321,6 +331,7 @@ export {
321
331
  UnderpostCluster,
322
332
  UnderpostDB,
323
333
  UnderpostDeploy,
334
+ UnderpostDockerCompose,
324
335
  UnderpostKubectl,
325
336
  UnderpostRootEnv,
326
337
  UnderpostFileStorage,
@@ -1,4 +1,4 @@
1
- import { ssrFactory } from '../server/ssr.js';
1
+ import { ssrFactory } from '../client-builder/ssr.js';
2
2
 
3
3
  /**
4
4
  * Module for handling the rendering and styling of HTML emails using SSR components.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Underpost platform content catalog — the base `pwa-microservices-template`.
3
3
  *
4
- * @module src/server/catalog-underpost.js
4
+ * @module src/projects/underpost/catalog-underpost.js
5
5
  * @namespace UnderpostCatalog
6
6
  */
7
7
 
@@ -11,7 +11,6 @@
11
11
  * @memberof UnderpostCatalog
12
12
  */
13
13
  const TEMPLATE_RESTORE_PATHS = [
14
- `./src/server/catalog-underpost.js`,
15
14
  `./.github/workflows/pwa-microservices-template-page.cd.yml`,
16
15
  `./.github/workflows/pwa-microservices-template-test.ci.yml`,
17
16
  `./.github/workflows/npmpkg.ci.yml`,
@@ -19,8 +19,8 @@ import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
19
19
  import { createPeerServer } from '../../server/peer.js';
20
20
  import { createValkeyConnection } from '../../server/valkey.js';
21
21
  import { applySecurity, authMiddlewareFactory } from '../../server/auth.js';
22
- import { ssrMiddlewareFactory } from '../../server/ssr.js';
23
- import { buildSwaggerUiOptions } from '../../server/client-build-docs.js';
22
+ import { ssrMiddlewareFactory } from '../../client-builder/ssr.js';
23
+ import { buildSwaggerUiOptions } from '../../client-builder/client-build-docs.js';
24
24
 
25
25
  import { shellExec } from '../../server/process.js';
26
26
  import { devProxyHostFactory, isDevProxyContext, isTlsDevProxy } from '../../server/conf.js';