underpost 2.8.1 → 2.8.41

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 (74) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/ghpkg.yml +14 -11
  3. package/.github/workflows/pwa-microservices-template.page.yml +10 -3
  4. package/.vscode/extensions.json +17 -71
  5. package/.vscode/settings.json +10 -4
  6. package/AUTHORS.md +16 -5
  7. package/CHANGELOG.md +63 -3
  8. package/Dockerfile +41 -62
  9. package/README.md +1 -28
  10. package/bin/build.js +278 -0
  11. package/bin/db.js +2 -24
  12. package/bin/deploy.js +105 -55
  13. package/bin/file.js +33 -4
  14. package/bin/index.js +33 -51
  15. package/bin/ssl.js +19 -11
  16. package/bin/util.js +9 -89
  17. package/bin/vs.js +25 -2
  18. package/conf.js +31 -138
  19. package/docker-compose.yml +1 -1
  20. package/manifests/core/kustomization.yaml +11 -0
  21. package/manifests/core/underpost-engine-backup-access.yaml +16 -0
  22. package/manifests/core/underpost-engine-backup-pv-pvc.yaml +22 -0
  23. package/manifests/core/underpost-engine-headless-service.yaml +10 -0
  24. package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +40 -0
  25. package/manifests/core/underpost-engine-mongodb-configmap.yaml +26 -0
  26. package/manifests/core/underpost-engine-pv-pvc.yaml +23 -0
  27. package/manifests/core/underpost-engine-statefulset.yaml +91 -0
  28. package/manifests/deployment/mongo-express.yaml +60 -0
  29. package/manifests/deployment/phpmyadmin.yaml +54 -0
  30. package/manifests/kind-config.yaml +12 -0
  31. package/manifests/letsencrypt-prod.yaml +15 -0
  32. package/manifests/mariadb/config.yaml +10 -0
  33. package/manifests/mariadb/kustomization.yaml +9 -0
  34. package/manifests/mariadb/pv.yaml +12 -0
  35. package/manifests/mariadb/pvc.yaml +10 -0
  36. package/manifests/mariadb/secret.yaml +8 -0
  37. package/manifests/mariadb/service.yaml +10 -0
  38. package/manifests/mariadb/statefulset.yaml +55 -0
  39. package/manifests/valkey/kustomization.yaml +7 -0
  40. package/manifests/valkey/underpost-engine-valkey-service.yaml +17 -0
  41. package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +39 -0
  42. package/package.json +115 -136
  43. package/src/api/user/user.model.js +16 -3
  44. package/src/api/user/user.service.js +1 -1
  45. package/src/client/components/core/CalendarCore.js +115 -49
  46. package/src/client/components/core/CommonJs.js +150 -19
  47. package/src/client/components/core/CssCore.js +6 -0
  48. package/src/client/components/core/DropDown.js +5 -1
  49. package/src/client/components/core/Input.js +17 -3
  50. package/src/client/components/core/Modal.js +10 -5
  51. package/src/client/components/core/Panel.js +84 -25
  52. package/src/client/components/core/PanelForm.js +4 -18
  53. package/src/client/components/core/Translate.js +43 -9
  54. package/src/client/components/core/Validator.js +9 -1
  55. package/src/client/services/default/default.management.js +4 -2
  56. package/src/db/mongo/MongooseDB.js +13 -1
  57. package/src/index.js +8 -1
  58. package/src/runtime/lampp/Lampp.js +1 -13
  59. package/src/runtime/xampp/Xampp.js +0 -13
  60. package/src/server/auth.js +3 -3
  61. package/src/server/client-build.js +3 -13
  62. package/src/server/conf.js +296 -29
  63. package/src/server/dns.js +2 -3
  64. package/src/server/logger.js +10 -5
  65. package/src/server/network.js +0 -36
  66. package/src/server/process.js +25 -2
  67. package/src/server/project.js +39 -0
  68. package/src/server/proxy.js +4 -26
  69. package/src/server/runtime.js +6 -7
  70. package/src/server/ssl.js +1 -1
  71. package/src/server/valkey.js +2 -0
  72. package/startup.cjs +12 -0
  73. package/src/server/prompt-optimizer.js +0 -28
  74. package/startup.js +0 -11
@@ -1,4 +1,4 @@
1
- import { validatePassword } from './CommonJs.js';
1
+ import { isChileanIdentityDocument, validatePassword } from './CommonJs.js';
2
2
  import { renderStatus } from './Css.js';
3
3
  import { loggerFactory } from './Logger.js';
4
4
  import { textFormatted, Translate } from './Translate.js';
@@ -58,6 +58,14 @@ const Validator = {
58
58
  if (!validator.isLength(s(`.${validatorData.id}`).value, rule.options))
59
59
  errorMessage += this.renderErrorMessage(rule);
60
60
  break;
61
+
62
+ case 'isChileanIdentityDocument': {
63
+ if (!isChileanIdentityDocument(s(`.${validatorData.id}`).value)) {
64
+ errorMessage += this.renderErrorMessage(undefined, Translate.Render('invalid-identity-document'));
65
+ }
66
+
67
+ break;
68
+ }
61
69
  default:
62
70
  if (
63
71
  validator[rule.type] &&
@@ -1,6 +1,6 @@
1
1
  import { AgGrid } from '../../components/core/AgGrid.js';
2
2
  import { BtnIcon } from '../../components/core/BtnIcon.js';
3
- import { getId, timer } from '../../components/core/CommonJs.js';
3
+ import { getId, getValueFromJoinString, timer } from '../../components/core/CommonJs.js';
4
4
  import { darkTheme } from '../../components/core/Css.js';
5
5
  import { EventsUI } from '../../components/core/EventsUI.js';
6
6
  import { loggerFactory } from '../../components/core/Logger.js';
@@ -88,7 +88,9 @@ const DefaultManagement = {
88
88
  ${Translate.Render('confirm-delete-item')}
89
89
  ${Object.keys(params.data).length > 0
90
90
  ? html`<br />
91
- "${params.data[Object.keys(params.data)[0]]}"`
91
+ "${options.defaultColKeyFocus
92
+ ? getValueFromJoinString(params.data, options.defaultColKeyFocus)
93
+ : params.data[Object.keys(params.data)[0]]}"`
92
94
  : ''}
93
95
  </div>
94
96
  `;
@@ -9,7 +9,12 @@ const MongooseDB = {
9
9
  connect: async (host, name) => {
10
10
  const uri = `${host}/${name}`;
11
11
  // logger.info('MongooseDB connect', { host, name, uri });
12
- return await mongoose.createConnection(uri).asPromise();
12
+ return await mongoose
13
+ .createConnection(uri, {
14
+ // useNewUrlParser: true,
15
+ // useUnifiedTopology: true,
16
+ })
17
+ .asPromise();
13
18
  return new Promise((resolve, reject) =>
14
19
  mongoose
15
20
  .connect(
@@ -67,8 +72,15 @@ const MongooseDB = {
67
72
  shellExec(`sudo rm -r /var/lib/mongodb`);
68
73
  // restore lib
69
74
  // shellExec(`sudo chown -R mongodb:mongodb /var/lib/mongodb/*`);
75
+ // mongod --repair
70
76
 
71
77
  if (process.argv.includes('legacy')) {
78
+ // TODO:
79
+ if (process.argv.includes('rocky')) {
80
+ // https://github.com/mongodb/mongodb-selinux
81
+ // https://www.mongodb.com/docs/v7.0/tutorial/install-mongodb-enterprise-on-red-hat/
82
+ shellExec(`sudo chown -R mongod:mongod /var/lib/mongo`);
83
+ }
72
84
  logger.info('install legacy 4.4');
73
85
  shellExec(`wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -`);
74
86
 
package/src/index.js CHANGED
@@ -4,7 +4,9 @@
4
4
  * @namespace Underpost
5
5
  */
6
6
 
7
+ import { runTest } from './server/conf.js';
7
8
  import { loggerFactory, setUpInfo } from './server/logger.js';
9
+ import Project from './server/project.js';
8
10
 
9
11
  const logger = loggerFactory(import.meta);
10
12
 
@@ -20,7 +22,8 @@ class Underpost {
20
22
  * @type {String}
21
23
  * @memberof Underpost
22
24
  */
23
- static version = 'v2.8.1';
25
+ static version = 'v2.8.41';
26
+ static project = Project;
24
27
 
25
28
  constructor() {}
26
29
 
@@ -40,6 +43,10 @@ class Underpost {
40
43
  static async setUpInfo() {
41
44
  return await setUpInfo(logger);
42
45
  }
46
+
47
+ static runTest() {
48
+ return runTest(Underpost.version);
49
+ }
43
50
  }
44
51
 
45
52
  const up = Underpost;
@@ -1,5 +1,4 @@
1
1
  import fs from 'fs-extra';
2
- import { network } from '../../server/network.js';
3
2
  import { shellCd, shellExec } from '../../server/process.js';
4
3
  import { timer } from '../../client/components/core/CommonJs.js';
5
4
  import { loggerFactory } from '../../server/logger.js';
@@ -39,20 +38,9 @@ const Lampp = {
39
38
  );
40
39
 
41
40
  shellExec(cmd);
42
- await network.port.portClean(3306);
43
- for (const port of this.ports) await network.port.portClean(port);
44
41
  cmd = `sudo /opt/lampp/lampp start`;
45
42
  if (this.router) fs.writeFileSync(`./tmp/lampp-router.conf`, this.router, 'utf-8');
46
- shellExec(cmd, { async: true });
47
- if (options && options.daemon) this.daemon();
48
- },
49
- daemon: async function () {
50
- await timer(1000 * 60 * 2); // 2 minutes
51
- for (const port of this.ports) {
52
- const [portStatus] = await network.port.status([port]);
53
- if (!portStatus.open) return await this.initService();
54
- }
55
- this.daemon();
43
+ shellExec(cmd);
56
44
  },
57
45
  enabled: () => fs.existsSync(`/opt/lampp/apache2/conf/httpd.conf`),
58
46
  appendRouter: function (render) {
@@ -1,7 +1,5 @@
1
1
  import fs from 'fs-extra';
2
- import { network } from '../../server/network.js';
3
2
  import { shellExec } from '../../server/process.js';
4
- import { timer } from '../../client/components/core/CommonJs.js';
5
3
 
6
4
  const Xampp = {
7
5
  ports: [],
@@ -16,20 +14,9 @@ const Xampp = {
16
14
  fs.writeFileSync(`C:/xampp/apache/conf/extra/httpd-ssl.conf`, this.router || '', 'utf8');
17
15
  cmd = `C:/xampp/xampp_stop.exe`;
18
16
  shellExec(cmd);
19
- await network.port.portClean(3306);
20
- for (const port of this.ports) await network.port.portClean(port);
21
17
  cmd = `C:/xampp/xampp_start.exe`;
22
18
  if (this.router) fs.writeFileSync(`./tmp/xampp-router.conf`, this.router, 'utf-8');
23
19
  shellExec(cmd);
24
- if (options && options.daemon) this.daemon();
25
- },
26
- daemon: async function () {
27
- await timer(1000 * 60 * 2); // 2 minutes
28
- for (const port of this.ports) {
29
- const [portStatus] = await network.port.status([port]);
30
- if (!portStatus.open) return await this.initService();
31
- }
32
- this.daemon();
33
20
  },
34
21
  enabled: () => fs.existsSync(`C:/xampp/apache/conf/httpd.conf`),
35
22
  appendRouter: function (render) {
@@ -9,7 +9,7 @@ import jwt from 'jsonwebtoken';
9
9
  import { loggerFactory } from './logger.js';
10
10
  import crypto from 'crypto';
11
11
  import { userRoleEnum } from '../api/user/user.model.js';
12
- import { validatePassword } from '../client/components/core/CommonJs.js';
12
+ import { commonAdminGuard, commonModeratorGuard, validatePassword } from '../client/components/core/CommonJs.js';
13
13
 
14
14
  dotenv.config();
15
15
 
@@ -162,7 +162,7 @@ const authMiddleware = (req, res, next) => {
162
162
  */
163
163
  const adminGuard = (req, res, next) => {
164
164
  try {
165
- if (!(userRoleEnum.indexOf(req.auth.user.role) === userRoleEnum.indexOf('admin')))
165
+ if (!commonAdminGuard(req.auth.user.role))
166
166
  return res.status(403).json({ status: 'error', message: 'Insufficient permission' });
167
167
  return next();
168
168
  } catch (error) {
@@ -194,7 +194,7 @@ const adminGuard = (req, res, next) => {
194
194
  */
195
195
  const moderatorGuard = (req, res, next) => {
196
196
  try {
197
- if (!(userRoleEnum.indexOf(req.auth.user.role) <= userRoleEnum.indexOf('moderator')))
197
+ if (!commonModeratorGuard(req.auth.user.role))
198
198
  return res.status(403).json({ status: 'error', message: 'Insufficient permission' });
199
199
  return next();
200
200
  } catch (error) {
@@ -50,10 +50,10 @@ const fullBuild = async ({
50
50
  buildAcmeChallengePath(acmeChallengeFullPath);
51
51
 
52
52
  if (publicClientId && publicClientId.startsWith('html-website-templates')) {
53
- if (!fs.existsSync(`/dd/html-website-templates/`))
54
- shellExec(`cd /dd && git clone https://github.com/designmodo/html-website-templates.git`);
53
+ if (!fs.existsSync(`/home/dd/html-website-templates/`))
54
+ shellExec(`cd /home/dd && git clone https://github.com/designmodo/html-website-templates.git`);
55
55
  if (!fs.existsSync(`${rootClientPath}/index.php`)) {
56
- fs.copySync(`/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
56
+ fs.copySync(`/home/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
57
57
  shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
58
58
  // git remote add origin git@github.com:<username>/<repo>.git
59
59
  fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
@@ -545,17 +545,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
545
545
  let siteMapSrc = await new Promise((resolve) =>
546
546
  streamToPromise(Readable.from(siteMapLinks).pipe(siteMapStream)).then((data) => resolve(data.toString())),
547
547
  );
548
- switch (publicClientId) {
549
- case 'underpost':
550
- siteMapSrc = siteMapSrc.replaceAll(
551
- `</urlset>`,
552
- `${fs.readFileSync(`./src/client/public/underpost/sitemap-template.txt`, 'utf8')} </urlset>`,
553
- );
554
- break;
555
548
 
556
- default:
557
- break;
558
- }
559
549
  // Return a promise that resolves with your XML string
560
550
  fs.writeFileSync(`${rootClientPath}/sitemap.xml`, siteMapSrc, 'utf8');
561
551
  if (xslUrl)
@@ -1,15 +1,21 @@
1
1
  import fs from 'fs-extra';
2
2
  import dotenv from 'dotenv';
3
- import { capFirst, getCapVariableName, newInstance, range, timer } from '../client/components/core/CommonJs.js';
3
+ import {
4
+ capFirst,
5
+ getCapVariableName,
6
+ newInstance,
7
+ orderArrayFromAttrInt,
8
+ range,
9
+ timer,
10
+ } from '../client/components/core/CommonJs.js';
4
11
  import * as dir from 'path';
5
12
  import cliProgress from 'cli-progress';
6
13
  import cliSpinners from 'cli-spinners';
7
14
  import logUpdate from 'log-update';
8
15
  import colors from 'colors';
9
- import { loggerFactory } from './logger.js';
10
- import { shellExec } from './process.js';
16
+ import { actionInitLog, loggerFactory } from './logger.js';
17
+ import { pbcopy, shellExec } from './process.js';
11
18
  import { DefaultConf } from '../../conf.js';
12
- import ncp from 'copy-paste';
13
19
  import read from 'read';
14
20
  import splitFile from 'split-file';
15
21
  import axios from 'axios';
@@ -18,13 +24,14 @@ import { ssrFactory } from './client-formatted.js';
18
24
 
19
25
  // axios.defaults.baseURL = BASE_URL;
20
26
 
21
- const httpsAgent = new https.Agent({
22
- rejectUnauthorized: false,
23
- });
27
+ // const httpsAgent = new https.Agent({
28
+ // rejectUnauthorized: false,
29
+ // });
24
30
 
25
- axios.defaults.httpsAgent = httpsAgent;
31
+ // axios.defaults.httpsAgent = httpsAgent;
26
32
 
27
33
  colors.enable();
34
+
28
35
  dotenv.config();
29
36
 
30
37
  const logger = loggerFactory(import.meta);
@@ -85,7 +92,7 @@ const Config = {
85
92
  },
86
93
  };
87
94
 
88
- const loadConf = (deployId) => {
95
+ const loadConf = (deployId, envInput) => {
89
96
  const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
90
97
  ? `./engine-private/replica/${deployId}`
91
98
  : `./engine-private/conf/${deployId}`;
@@ -111,9 +118,10 @@ const loadConf = (deployId) => {
111
118
  fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
112
119
  fs.writeFileSync(`./.env.development`, fs.readFileSync(`${folder}/.env.development`, 'utf8'), 'utf8');
113
120
  fs.writeFileSync(`./.env.test`, fs.readFileSync(`${folder}/.env.test`, 'utf8'), 'utf8');
114
- if (process.env.NODE_ENV) {
115
- fs.writeFileSync(`./.env`, fs.readFileSync(`${folder}/.env.${process.env.NODE_ENV}`, 'utf8'), 'utf8');
116
- const env = dotenv.parse(fs.readFileSync(`${folder}/.env.${process.env.NODE_ENV}`, 'utf8'));
121
+ const NODE_ENV = envInput || process.env.NODE_ENV;
122
+ if (NODE_ENV) {
123
+ fs.writeFileSync(`./.env`, fs.readFileSync(`${folder}/.env.${NODE_ENV}`, 'utf8'), 'utf8');
124
+ const env = dotenv.parse(fs.readFileSync(`${folder}/.env.${NODE_ENV}`, 'utf8'));
117
125
  process.env = {
118
126
  ...process.env,
119
127
  ...env,
@@ -480,6 +488,44 @@ const buildProxyRouter = () => {
480
488
  return proxyRouter;
481
489
  };
482
490
 
491
+ const buildKindPorts = (from, to) =>
492
+ range(parseInt(from), parseInt(to))
493
+ .map(
494
+ (port) => ` - name: 'tcp-${port}'
495
+ protocol: TCP
496
+ port: ${port}
497
+ targetPort: ${port}
498
+ - name: 'udp-${port}'
499
+ protocol: UDP
500
+ port: ${port}
501
+ targetPort: ${port}
502
+ `,
503
+ )
504
+ .join('\n');
505
+
506
+ const buildPortProxyRouter = (port, proxyRouter) => {
507
+ const hosts = proxyRouter[port];
508
+ const router = {};
509
+ // build router
510
+ Object.keys(hosts).map((hostKey) => {
511
+ let { host, path, target, proxy, peer } = hosts[hostKey];
512
+ if (process.env.NODE_ENV === 'development') host = `localhost`;
513
+
514
+ if (!proxy.includes(port)) return;
515
+ const absoluteHost = [80, 443].includes(port)
516
+ ? `${host}${path === '/' ? '' : path}`
517
+ : `${host}:${port}${path === '/' ? '' : path}`;
518
+
519
+ if (!(absoluteHost in router)) router[absoluteHost] = target;
520
+ }); // order router
521
+
522
+ if (Object.keys(router).length === 0) return router;
523
+
524
+ for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
525
+ router[absoluteHostKey] = router[absoluteHostKey];
526
+ return router;
527
+ };
528
+
483
529
  const cliBar = async (time = 5000) => {
484
530
  // create new progress bar
485
531
  const b = new cliProgress.SingleBar({
@@ -588,6 +634,7 @@ const validateTemplatePath = (absolutePath = '') => {
588
634
  if (absolutePath.match('src/api') && !confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))) {
589
635
  return false;
590
636
  }
637
+ if (absolutePath.match('conf.dd-') && absolutePath.match('.js')) return false;
591
638
  if (
592
639
  absolutePath.match('src/client/services/') &&
593
640
  !clients.find((p) => absolutePath.match(`src/client/services/${p}/`))
@@ -770,9 +817,10 @@ const deployRun = async (dataDeploy, currentAttempt = 1) => {
770
817
  } else logger.info(`Deploy process successfully`);
771
818
  };
772
819
 
773
- const restoreMacroDb = async (deployGroupId = '') => {
820
+ const restoreMacroDb = async (deployGroupId = '', deployId = null) => {
774
821
  const dataDeploy = await getDataDeploy({ deployGroupId, buildSingleReplica: false });
775
822
  for (const deployGroup of dataDeploy) {
823
+ if (deployId && deployGroup.deployId !== deployId) continue;
776
824
  if (!deployGroup.replicaHost) {
777
825
  const deployServerConfPath = `./engine-private/conf/${deployGroup.deployId}/conf.server.json`;
778
826
  const serverConf = JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8'));
@@ -790,13 +838,10 @@ const restoreMacroDb = async (deployGroupId = '') => {
790
838
  }
791
839
  };
792
840
 
793
- const mergeBackUp = async (baseBackJsonPath, outputFilePath) => {
794
- const names = JSON.parse(fs.readFileSync(baseBackJsonPath, 'utf8')).map((p) =>
795
- p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'),
796
- );
841
+ const mergeFile = async (parts = [], outputFilePath) => {
797
842
  await new Promise((resolve) => {
798
843
  splitFile
799
- .mergeFiles(names, outputFilePath)
844
+ .mergeFiles(parts, outputFilePath)
800
845
  .then(() => {
801
846
  resolve();
802
847
  })
@@ -848,11 +893,13 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
848
893
  {
849
894
  if (process.argv.includes('cron')) {
850
895
  cmd = `mysql -u ${user} -p${password} ${name} < ${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`;
851
- if (fs.existsSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`))
852
- await mergeBackUp(
853
- `${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`,
854
- `${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`,
855
- );
896
+ if (fs.existsSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`)) {
897
+ const names = JSON.parse(
898
+ fs.readFileSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`, 'utf8'),
899
+ ).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
900
+
901
+ await mergeFile(names, `${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`);
902
+ }
856
903
  } else {
857
904
  cmd = `mysql -u ${user} -p${password} ${name} < ${
858
905
  backupPath ? backupPath : `./engine-private/sql-backups/${name}.sql`
@@ -863,15 +910,23 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
863
910
  backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
864
911
  }/${name}-parths.json`,
865
912
  )
866
- )
867
- await mergeBackUp(
868
- `${
869
- backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
870
- }/${name}-parths.json`,
913
+ ) {
914
+ const names = JSON.parse(
915
+ fs.readFileSync(
916
+ `${
917
+ backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
918
+ }/${name}-parths.json`,
919
+ 'utf8',
920
+ ),
921
+ ).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
922
+
923
+ await mergeFile(
924
+ names,
871
925
  `${
872
926
  backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
873
927
  }/${name}.sql`,
874
928
  );
929
+ }
875
930
  }
876
931
  }
877
932
  break;
@@ -890,6 +945,16 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
890
945
  return cmd;
891
946
  };
892
947
 
948
+ const getPathsSSR = (conf) => {
949
+ const paths = ['src/client/ssr/Render.js'];
950
+ for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
951
+ for (const o of conf.body) paths.push(`src/client/ssr/body/${o}.js`);
952
+ for (const o of Object.keys(conf.mailer)) paths.push(`src/client/ssr/mailer/${conf.mailer[o]}.js`);
953
+ for (const o of conf.offline) paths.push(`src/client/ssr/mailer/${o.client}.js`);
954
+ for (const o of conf.pages) paths.push(`src/client/ssr/pages/${o.client}.js`);
955
+ return paths;
956
+ };
957
+
893
958
  const Cmd = {
894
959
  delete: (deployId) => `pm2 delete ${deployId}`,
895
960
  run: (deployId) => `node bin/deploy run ${deployId}`,
@@ -904,6 +969,7 @@ const Cmd = {
904
969
  };
905
970
 
906
971
  const fixDependencies = async () => {
972
+ return;
907
973
  // sed -i "$line_number s,.*,$new_text," "$file"
908
974
  // sed -i "$line_number c \\$new_text" "$file"
909
975
  const dep = fs.readFileSync(`./node_modules/peer/dist/module.mjs`, 'utf8');
@@ -933,6 +999,34 @@ const maintenanceMiddleware = (req, res, port, proxyRouter) => {
933
999
  }
934
1000
  };
935
1001
 
1002
+ const splitFileFactory = async (name, _path) => {
1003
+ const stats = fs.statSync(_path);
1004
+ const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
1005
+ const fileSizeInBytes = stats.size;
1006
+ if (fileSizeInBytes > maxSizeInBytes) {
1007
+ logger.info('splitFileFactory input', { name, from: _path });
1008
+ return await new Promise((resolve) => {
1009
+ splitFile
1010
+ .splitFileBySize(_path, maxSizeInBytes) // 50 mb
1011
+ .then((names) => {
1012
+ logger.info('splitFileFactory output', { parts: names });
1013
+ fs.writeFileSync(
1014
+ `${_path.split('/').slice(0, -1).join('/')}/${name}-parths.json`,
1015
+ JSON.stringify(names, null, 4),
1016
+ 'utf8',
1017
+ );
1018
+ fs.removeSync(_path);
1019
+ return resolve(true);
1020
+ })
1021
+ .catch((err) => {
1022
+ console.log('Error: ', err);
1023
+ return resolve(false);
1024
+ });
1025
+ });
1026
+ }
1027
+ return false;
1028
+ };
1029
+
936
1030
  const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
937
1031
  shellExec(`pm2 kill`);
938
1032
  shellExec(`node bin/deploy valkey-service`);
@@ -941,6 +1035,168 @@ const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
941
1035
  shellExec(`node bin/deploy run ${proxyDeployId} maintenance`);
942
1036
  };
943
1037
 
1038
+ const repoClone = (gitUri = 'underpostnet/pwa-microservices-template') => {
1039
+ const repoName = gitUri.split('/').pop();
1040
+ if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
1041
+ shellExec(
1042
+ `git clone https://${process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''}github.com/${gitUri}.git`,
1043
+ );
1044
+ if (process.env.GITHUB_TOKEN) {
1045
+ shellExec(
1046
+ `git clone https://${
1047
+ process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
1048
+ }github.com/${gitUri}-private.git`,
1049
+ );
1050
+ fs.moveSync(`./${repoName}-private`, `./${repoName}/engine-private`, {
1051
+ overwrite: true,
1052
+ });
1053
+ }
1054
+ };
1055
+
1056
+ const repoPull = (repoPath = './', gitUri = 'underpostnet/pwa-microservices-template') => {
1057
+ shellExec(`cd ${repoPath} && git pull https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}.git`, {
1058
+ disableLog: true,
1059
+ });
1060
+ };
1061
+
1062
+ const commitData = {
1063
+ feat: {
1064
+ description: 'A new feature',
1065
+ title: 'Features',
1066
+ emoji: '✨',
1067
+ },
1068
+ fix: {
1069
+ description: 'A bug fix',
1070
+ title: 'Bug Fixes',
1071
+ emoji: '🐛',
1072
+ },
1073
+ docs: {
1074
+ description: 'Documentation only changes',
1075
+ title: 'Documentation',
1076
+ emoji: '📚',
1077
+ },
1078
+ style: {
1079
+ description:
1080
+ 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
1081
+ title: 'Styles',
1082
+ emoji: '💎',
1083
+ },
1084
+ refactor: {
1085
+ description: 'A code change that neither fixes a bug nor adds a feature',
1086
+ title: 'Code Refactoring',
1087
+ emoji: '📦',
1088
+ },
1089
+ perf: {
1090
+ description: 'A code change that improves performance',
1091
+ title: 'Performance Improvements',
1092
+ emoji: '⚡️',
1093
+ },
1094
+ cd: {
1095
+ description:
1096
+ 'Changes to our Continuous Delivery configuration files and scripts (example scopes: Jenkins, Spinnaker, ArgoCD)',
1097
+ title: 'Continuous Delivery',
1098
+ emoji: '🚀',
1099
+ },
1100
+ test: {
1101
+ description: 'Adding missing tests or correcting existing tests',
1102
+ title: 'Tests',
1103
+ emoji: '🚨',
1104
+ },
1105
+ build: {
1106
+ description: 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)',
1107
+ title: 'Builds',
1108
+ emoji: '🛠',
1109
+ },
1110
+ ci: {
1111
+ description:
1112
+ 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)',
1113
+ title: 'Continuous Integrations',
1114
+ emoji: '⚙️',
1115
+ },
1116
+ chore: {
1117
+ description: "Other changes that don't modify src or test files",
1118
+ title: 'Chores',
1119
+ emoji: '♻️',
1120
+ },
1121
+ revert: {
1122
+ description: 'Reverts a previous commit',
1123
+ title: 'Reverts',
1124
+ emoji: '🗑',
1125
+ },
1126
+ backup: {
1127
+ description: 'Changes related to backups, including creation, restoration, and maintenance.',
1128
+ title: 'Backups',
1129
+ emoji: '💾',
1130
+ },
1131
+ };
1132
+
1133
+ const repoCommit = (
1134
+ repoPath = './',
1135
+ commitType = 'feat',
1136
+ subModule = '',
1137
+ message = '',
1138
+ options = {
1139
+ copy: false,
1140
+ info: false,
1141
+ empty: false,
1142
+ },
1143
+ ) => {
1144
+ if (options.info) return logger.info('', commitData);
1145
+ const _message = `${commitType}${subModule ? `(${subModule})` : ''}${process.argv.includes('!') ? '!' : ''}: ${
1146
+ commitData[commitType].emoji
1147
+ } ${message ? message : commitData[commitType].description}`;
1148
+ if (options.copy) return pbcopy(_message);
1149
+ shellExec(`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}-m "${_message}"`);
1150
+ };
1151
+
1152
+ const repoPush = (repoPath = './', gitUri = 'underpostnet/pwa-microservices-template') => {
1153
+ shellExec(`cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}.git`, {
1154
+ disableLog: true,
1155
+ });
1156
+ logger.info(
1157
+ 'commit url',
1158
+ `http://github.com/${gitUri}/commit/${shellExec(`cd ${repoPath} && git rev-parse --verify HEAD`, {
1159
+ stdout: true,
1160
+ }).trim()}`,
1161
+ );
1162
+ };
1163
+
1164
+ const getNpmRootPath = () =>
1165
+ shellExec(`npm root -g`, {
1166
+ stdout: true,
1167
+ }).trim();
1168
+
1169
+ const newProject = (repositoryName, version) => {
1170
+ return new Promise(async (resolve, reject) => {
1171
+ try {
1172
+ const exeRootPath = `${getNpmRootPath()}/underpost`;
1173
+ // const exeRootPath = '/home/dd/pwa-microservices-template';
1174
+ actionInitLog(version);
1175
+ await logger.setUpInfo();
1176
+ const destFolder = `${process.cwd()}/${repositoryName}`;
1177
+ logger.info('Note: This process may take several minutes to complete');
1178
+ logger.info('build app', { destFolder });
1179
+ fs.mkdirSync(destFolder, { recursive: true });
1180
+ fs.copySync(exeRootPath, destFolder);
1181
+ if (fs.existsSync(`${destFolder}/node_modules`)) fs.removeSync(`${destFolder}/node_modules`);
1182
+ fs.writeFileSync(`${destFolder}/.gitignore`, fs.readFileSync(`${exeRootPath}/.dockerignore`, 'utf8'), 'utf8');
1183
+ shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
1184
+ shellExec(`cd ${destFolder} && npm install`);
1185
+ shellExec(`cd ${destFolder} && npm run build`);
1186
+ shellExec(`cd ${destFolder} && npm run dev`);
1187
+ return resolve();
1188
+ } catch (error) {
1189
+ logger.error(error, error.stack);
1190
+ return reject(error.message);
1191
+ }
1192
+ });
1193
+ };
1194
+
1195
+ const runTest = (version) => {
1196
+ actionInitLog(version);
1197
+ shellExec(`cd ${getNpmRootPath()}/underpost && npm run test`);
1198
+ };
1199
+
944
1200
  export {
945
1201
  Cmd,
946
1202
  Config,
@@ -967,9 +1223,20 @@ export {
967
1223
  deployRun,
968
1224
  getCronBackUpFolder,
969
1225
  getRestoreCronCmd,
970
- mergeBackUp,
1226
+ mergeFile,
971
1227
  fixDependencies,
972
1228
  getDeployId,
973
1229
  maintenanceMiddleware,
974
1230
  setUpProxyMaintenanceServer,
1231
+ getPathsSSR,
1232
+ buildKindPorts,
1233
+ buildPortProxyRouter,
1234
+ splitFileFactory,
1235
+ repoClone,
1236
+ repoPull,
1237
+ repoCommit,
1238
+ repoPush,
1239
+ newProject,
1240
+ runTest,
1241
+ getNpmRootPath,
975
1242
  };