@underpostnet/underpost 2.8.1 → 2.8.5

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 (105) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/ghpkg.yml +20 -50
  3. package/.github/workflows/npmpkg.yml +67 -0
  4. package/.github/workflows/publish.yml +5 -5
  5. package/.github/workflows/pwa-microservices-template.page.yml +13 -5
  6. package/.github/workflows/pwa-microservices-template.test.yml +2 -2
  7. package/.vscode/extensions.json +17 -71
  8. package/.vscode/settings.json +14 -3
  9. package/AUTHORS.md +16 -5
  10. package/CHANGELOG.md +79 -3
  11. package/Dockerfile +24 -66
  12. package/README.md +1 -28
  13. package/bin/build.js +161 -0
  14. package/bin/db.js +2 -24
  15. package/bin/deploy.js +111 -82
  16. package/bin/file.js +59 -16
  17. package/bin/index.js +168 -58
  18. package/bin/ssl.js +19 -11
  19. package/bin/util.js +9 -97
  20. package/bin/vs.js +25 -2
  21. package/conf.js +31 -138
  22. package/docker-compose.yml +1 -1
  23. package/manifests/core/kustomization.yaml +11 -0
  24. package/manifests/core/underpost-engine-backup-access.yaml +16 -0
  25. package/manifests/core/underpost-engine-backup-pv-pvc.yaml +22 -0
  26. package/manifests/core/underpost-engine-headless-service.yaml +10 -0
  27. package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +40 -0
  28. package/manifests/core/underpost-engine-mongodb-configmap.yaml +26 -0
  29. package/manifests/core/underpost-engine-pv-pvc.yaml +23 -0
  30. package/manifests/core/underpost-engine-statefulset.yaml +91 -0
  31. package/manifests/deployment/mongo-express/deployment.yaml +60 -0
  32. package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
  33. package/manifests/kind-config.yaml +12 -0
  34. package/manifests/letsencrypt-prod.yaml +15 -0
  35. package/manifests/mariadb/config.yaml +10 -0
  36. package/manifests/mariadb/kustomization.yaml +9 -0
  37. package/manifests/mariadb/pv.yaml +12 -0
  38. package/manifests/mariadb/pvc.yaml +10 -0
  39. package/manifests/mariadb/secret.yaml +8 -0
  40. package/manifests/mariadb/service.yaml +10 -0
  41. package/manifests/mariadb/statefulset.yaml +55 -0
  42. package/manifests/mongodb/backup-access.yaml +16 -0
  43. package/manifests/mongodb/backup-cronjob.yaml +42 -0
  44. package/manifests/mongodb/backup-pv-pvc.yaml +22 -0
  45. package/manifests/mongodb/configmap.yaml +26 -0
  46. package/manifests/mongodb/headless-service.yaml +10 -0
  47. package/manifests/mongodb/kustomization.yaml +11 -0
  48. package/manifests/mongodb/pv-pvc.yaml +23 -0
  49. package/manifests/mongodb/statefulset.yaml +125 -0
  50. package/manifests/valkey/kustomization.yaml +7 -0
  51. package/manifests/valkey/service.yaml +17 -0
  52. package/manifests/valkey/statefulset.yaml +39 -0
  53. package/manifests/valkey/underpost-engine-valkey-service.yaml +17 -0
  54. package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +39 -0
  55. package/package.json +26 -31
  56. package/src/api/core/core.service.js +1 -1
  57. package/src/api/user/user.model.js +16 -3
  58. package/src/api/user/user.service.js +1 -1
  59. package/src/cli/cluster.js +154 -0
  60. package/src/cli/cron.js +90 -0
  61. package/src/cli/db.js +148 -0
  62. package/src/cli/deploy.js +277 -0
  63. package/src/cli/env.js +52 -0
  64. package/src/cli/image.js +125 -0
  65. package/src/cli/repository.js +104 -0
  66. package/src/cli/script.js +29 -0
  67. package/src/cli/secrets.js +37 -0
  68. package/src/cli/test.js +83 -0
  69. package/src/client/components/core/Auth.js +22 -4
  70. package/src/client/components/core/CalendarCore.js +115 -49
  71. package/src/client/components/core/CommonJs.js +231 -19
  72. package/src/client/components/core/Css.js +1 -0
  73. package/src/client/components/core/CssCore.js +6 -0
  74. package/src/client/components/core/DropDown.js +5 -1
  75. package/src/client/components/core/Input.js +18 -4
  76. package/src/client/components/core/Modal.js +10 -6
  77. package/src/client/components/core/Panel.js +84 -25
  78. package/src/client/components/core/PanelForm.js +4 -18
  79. package/src/client/components/core/Scroll.js +1 -0
  80. package/src/client/components/core/Translate.js +47 -9
  81. package/src/client/components/core/Validator.js +9 -1
  82. package/src/client/components/core/VanillaJs.js +0 -9
  83. package/src/client/components/core/Worker.js +34 -31
  84. package/src/client/services/default/default.management.js +4 -2
  85. package/src/client/ssr/body/CacheControl.js +2 -2
  86. package/src/db/mongo/MongooseDB.js +13 -1
  87. package/src/index.js +77 -19
  88. package/src/runtime/lampp/Lampp.js +1 -13
  89. package/src/runtime/xampp/Xampp.js +0 -13
  90. package/src/server/auth.js +3 -3
  91. package/src/server/backup.js +49 -93
  92. package/src/server/client-build.js +4 -23
  93. package/src/server/client-formatted.js +5 -3
  94. package/src/server/conf.js +193 -45
  95. package/src/server/dns.js +49 -67
  96. package/src/server/logger.js +15 -10
  97. package/src/server/network.js +17 -43
  98. package/src/server/process.js +25 -2
  99. package/src/server/proxy.js +4 -26
  100. package/src/server/runtime.js +14 -29
  101. package/src/server/ssl.js +1 -1
  102. package/src/server/valkey.js +2 -0
  103. package/src/dns.js +0 -22
  104. package/src/server/prompt-optimizer.js +0 -28
  105. package/startup.js +0 -11
@@ -1,6 +1,13 @@
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';
@@ -9,7 +16,6 @@ import colors from 'colors';
9
16
  import { loggerFactory } from './logger.js';
10
17
  import { 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);
@@ -33,21 +40,26 @@ const logger = loggerFactory(import.meta);
33
40
 
34
41
  const Config = {
35
42
  default: DefaultConf,
36
- build: async function (options = { folder: '' }) {
43
+ build: async function (options = { folder: '' }, deployContext, deployList, subConf) {
44
+ if (!deployContext) deployContext = process.argv[2];
37
45
  if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
38
46
  fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
39
- if (fs.existsSync(`./engine-private/conf/${process.argv[2]}`)) return loadConf(process.argv[2]);
40
- if (fs.existsSync(`./engine-private/replica/${process.argv[2]}`)) return loadConf(process.argv[2]);
47
+ if (fs.existsSync(`./engine-private/conf/${deployContext}`))
48
+ return loadConf(deployContext, process.env.NODE_ENV, subConf);
49
+ if (fs.existsSync(`./engine-private/replica/${deployContext}`))
50
+ return loadConf(deployContext, process.env.NODE_ENV, subConf);
41
51
 
42
- if (process.argv[2] === 'deploy') return;
52
+ if (deployContext === 'deploy') return;
43
53
 
44
- if (process.argv[2] === 'proxy') {
54
+ if (deployContext === 'proxy') {
55
+ if (!deployList) deployList = process.argv[3];
56
+ if (!subConf) subConf = process.argv[4];
45
57
  this.default.server = {};
46
- for (const deployId of process.argv[3].split(',')) {
58
+ for (const deployId of deployList.split(',')) {
47
59
  let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
48
60
  const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
49
61
  ? `./engine-private/replica/${deployId}/conf.server.json`
50
- : `./engine-private/conf/${deployId}/conf.server.dev.${process.argv[4]}.json`;
62
+ : `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
51
63
  const confDevPath = fs.existsSync(privateConfDevPath)
52
64
  ? privateConfDevPath
53
65
  : `./engine-private/conf/${deployId}/conf.server.dev.json`;
@@ -55,7 +67,7 @@ const Config = {
55
67
  if (process.env.NODE_ENV === 'development' && fs.existsSync(confDevPath)) confPath = confDevPath;
56
68
  const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
57
69
 
58
- for (const host of Object.keys(loadReplicas(serverConf))) {
70
+ for (const host of Object.keys(loadReplicas(serverConf, deployContext, subConf))) {
59
71
  if (serverConf[host]['/'])
60
72
  this.default.server[host] = {
61
73
  ...this.default.server[host],
@@ -85,7 +97,15 @@ const Config = {
85
97
  },
86
98
  };
87
99
 
88
- const loadConf = (deployId) => {
100
+ const loadConf = (deployId, envInput, subConf) => {
101
+ if (deployId === 'clean') {
102
+ shellExec(`git checkout package.json`);
103
+ shellExec(`git checkout .env.production`);
104
+ shellExec(`git checkout .env.development`);
105
+ shellExec(`git checkout .env.test`);
106
+ shellExec(`git checkout jsdoc.json`);
107
+ return;
108
+ }
89
109
  const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
90
110
  ? `./engine-private/replica/${deployId}`
91
111
  : `./engine-private/conf/${deployId}`;
@@ -102,7 +122,8 @@ const loadConf = (deployId) => {
102
122
  ? fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8')
103
123
  : JSON.stringify(Config.default[typeConf]);
104
124
  if (process.env.NODE_ENV === 'development' && typeConf === 'server') {
105
- const devConfPath = `${folder}/conf.${typeConf}.dev${process.argv[3] ? `.${process.argv[3]}` : ''}.json`;
125
+ if (!subConf) subConf = process.argv[3];
126
+ const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
106
127
  if (fs.existsSync(devConfPath)) srcConf = fs.readFileSync(devConfPath, 'utf8');
107
128
  }
108
129
  if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(JSON.parse(srcConf)), null, 4);
@@ -111,27 +132,34 @@ const loadConf = (deployId) => {
111
132
  fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
112
133
  fs.writeFileSync(`./.env.development`, fs.readFileSync(`${folder}/.env.development`, 'utf8'), 'utf8');
113
134
  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'));
135
+ const NODE_ENV = envInput || process.env.NODE_ENV;
136
+ if (NODE_ENV) {
137
+ fs.writeFileSync(`./.env`, fs.readFileSync(`${folder}/.env.${NODE_ENV}`, 'utf8'), 'utf8');
138
+ const env = dotenv.parse(fs.readFileSync(`${folder}/.env.${NODE_ENV}`, 'utf8'));
117
139
  process.env = {
118
140
  ...process.env,
119
141
  ...env,
120
142
  };
121
143
  }
122
- fs.writeFileSync(`./package.json`, fs.readFileSync(`${folder}/package.json`, 'utf8'), 'utf8');
144
+ const originPackageJson = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
145
+ const packageJson = JSON.parse(fs.readFileSync(`${folder}/package.json`, 'utf8'));
146
+ originPackageJson.scripts.start = packageJson.scripts.start;
147
+ packageJson.scripts = originPackageJson.scripts;
148
+ fs.writeFileSync(`./package.json`, JSON.stringify(packageJson, null, 4), 'utf8');
123
149
  return { folder, deployId };
124
150
  };
125
151
 
126
- const loadReplicas = (confServer) => {
152
+ const loadReplicas = (confServer, deployContext, subConf) => {
153
+ if (!deployContext) deployContext = process.argv[2];
154
+ if (!subConf) subConf = process.argv[3];
127
155
  for (const host of Object.keys(confServer)) {
128
156
  for (const path of Object.keys(confServer[host])) {
129
157
  const { replicas, singleReplica } = confServer[host][path];
130
158
  if (
131
159
  replicas &&
132
- (process.argv[2] === 'proxy' ||
160
+ (deployContext === 'proxy' ||
133
161
  !singleReplica ||
134
- (singleReplica && process.env.NODE_ENV === 'development' && !process.argv[3]))
162
+ (singleReplica && process.env.NODE_ENV === 'development' && !subConf))
135
163
  )
136
164
  for (const replicaPath of replicas) {
137
165
  confServer[host][replicaPath] = newInstance(confServer[host][path]);
@@ -480,6 +508,48 @@ const buildProxyRouter = () => {
480
508
  return proxyRouter;
481
509
  };
482
510
 
511
+ const buildKindPorts = (from, to) =>
512
+ range(parseInt(from), parseInt(to))
513
+ .map(
514
+ (port) => ` - name: 'tcp-${port}'
515
+ protocol: TCP
516
+ port: ${port}
517
+ targetPort: ${port}
518
+ - name: 'udp-${port}'
519
+ protocol: UDP
520
+ port: ${port}
521
+ targetPort: ${port}
522
+ `,
523
+ )
524
+ .join('\n');
525
+
526
+ const buildPortProxyRouter = (port, proxyRouter) => {
527
+ const hosts = proxyRouter[port];
528
+ const router = {};
529
+ // build router
530
+ Object.keys(hosts).map((hostKey) => {
531
+ let { host, path, target, proxy, peer } = hosts[hostKey];
532
+ if (process.argv.includes('localhost') && process.env.NODE_ENV === 'development') host = `localhost`;
533
+
534
+ if (!proxy.includes(port)) return;
535
+ const absoluteHost = [80, 443].includes(port)
536
+ ? `${host}${path === '/' ? '' : path}`
537
+ : `${host}:${port}${path === '/' ? '' : path}`;
538
+
539
+ if (process.argv.includes('localhost')) {
540
+ if (!(absoluteHost in router)) router[absoluteHost] = target;
541
+ } else router[absoluteHost] = target;
542
+ }); // order router
543
+
544
+ if (Object.keys(router).length === 0) return router;
545
+
546
+ const reOrderRouter = {};
547
+ for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
548
+ reOrderRouter[absoluteHostKey] = router[absoluteHostKey];
549
+
550
+ return reOrderRouter;
551
+ };
552
+
483
553
  const cliBar = async (time = 5000) => {
484
554
  // create new progress bar
485
555
  const b = new cliProgress.SingleBar({
@@ -530,7 +600,15 @@ const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1
530
600
  const getDataDeploy = (
531
601
  options = { buildSingleReplica: false, deployGroupId: '', deployId: '', disableSyncEnvPort: false },
532
602
  ) => {
533
- let dataDeploy = JSON.parse(fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.json`, 'utf8'));
603
+ let dataDeploy =
604
+ options.deployGroupId === 'dd'
605
+ ? fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.router`, 'utf8')
606
+ : fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}`, 'utf8');
607
+
608
+ dataDeploy = dataDeploy
609
+ .split(',')
610
+ .map((deployId) => deployId.trim())
611
+ .filter((deployId) => deployId);
534
612
 
535
613
  if (options.deployId) dataDeploy = dataDeploy.filter((d) => d === options.deployId);
536
614
 
@@ -588,6 +666,7 @@ const validateTemplatePath = (absolutePath = '') => {
588
666
  if (absolutePath.match('src/api') && !confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))) {
589
667
  return false;
590
668
  }
669
+ if (absolutePath.match('conf.dd-') && absolutePath.match('.js')) return false;
591
670
  if (
592
671
  absolutePath.match('src/client/services/') &&
593
672
  !clients.find((p) => absolutePath.match(`src/client/services/${p}/`))
@@ -770,9 +849,10 @@ const deployRun = async (dataDeploy, currentAttempt = 1) => {
770
849
  } else logger.info(`Deploy process successfully`);
771
850
  };
772
851
 
773
- const restoreMacroDb = async (deployGroupId = '') => {
852
+ const restoreMacroDb = async (deployGroupId = '', deployId = null) => {
774
853
  const dataDeploy = await getDataDeploy({ deployGroupId, buildSingleReplica: false });
775
854
  for (const deployGroup of dataDeploy) {
855
+ if (deployId && deployGroup.deployId !== deployId) continue;
776
856
  if (!deployGroup.replicaHost) {
777
857
  const deployServerConfPath = `./engine-private/conf/${deployGroup.deployId}/conf.server.json`;
778
858
  const serverConf = JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8'));
@@ -790,13 +870,10 @@ const restoreMacroDb = async (deployGroupId = '') => {
790
870
  }
791
871
  };
792
872
 
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
- );
873
+ const mergeFile = async (parts = [], outputFilePath) => {
797
874
  await new Promise((resolve) => {
798
875
  splitFile
799
- .mergeFiles(names, outputFilePath)
876
+ .mergeFiles(parts, outputFilePath)
800
877
  .then(() => {
801
878
  resolve();
802
879
  })
@@ -848,11 +925,13 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
848
925
  {
849
926
  if (process.argv.includes('cron')) {
850
927
  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
- );
928
+ if (fs.existsSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`)) {
929
+ const names = JSON.parse(
930
+ fs.readFileSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`, 'utf8'),
931
+ ).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
932
+
933
+ await mergeFile(names, `${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`);
934
+ }
856
935
  } else {
857
936
  cmd = `mysql -u ${user} -p${password} ${name} < ${
858
937
  backupPath ? backupPath : `./engine-private/sql-backups/${name}.sql`
@@ -863,15 +942,23 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
863
942
  backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
864
943
  }/${name}-parths.json`,
865
944
  )
866
- )
867
- await mergeBackUp(
868
- `${
869
- backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
870
- }/${name}-parths.json`,
945
+ ) {
946
+ const names = JSON.parse(
947
+ fs.readFileSync(
948
+ `${
949
+ backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
950
+ }/${name}-parths.json`,
951
+ 'utf8',
952
+ ),
953
+ ).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
954
+
955
+ await mergeFile(
956
+ names,
871
957
  `${
872
958
  backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
873
959
  }/${name}.sql`,
874
960
  );
961
+ }
875
962
  }
876
963
  }
877
964
  break;
@@ -890,6 +977,16 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
890
977
  return cmd;
891
978
  };
892
979
 
980
+ const getPathsSSR = (conf) => {
981
+ const paths = ['src/client/ssr/Render.js'];
982
+ for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
983
+ for (const o of conf.body) paths.push(`src/client/ssr/body/${o}.js`);
984
+ for (const o of Object.keys(conf.mailer)) paths.push(`src/client/ssr/mailer/${conf.mailer[o]}.js`);
985
+ for (const o of conf.offline) paths.push(`src/client/ssr/mailer/${o.client}.js`);
986
+ for (const o of conf.pages) paths.push(`src/client/ssr/pages/${o.client}.js`);
987
+ return paths;
988
+ };
989
+
893
990
  const Cmd = {
894
991
  delete: (deployId) => `pm2 delete ${deployId}`,
895
992
  run: (deployId) => `node bin/deploy run ${deployId}`,
@@ -897,13 +994,14 @@ const Cmd = {
897
994
  conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
898
995
  replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
899
996
  syncPorts: (deployGroupId) => `node bin/deploy sync-env-port ${deployGroupId}`,
900
- cron: (deployId, job, expression) => {
901
- shellExec(Cmd.delete(`${deployId}-${job}`));
902
- return `env-cmd -f .env.production pm2 start bin/cron.js --no-autorestart --instances 1 --cron "${expression}" --name ${deployId}-${job} -- ${job} ${deployId}`;
903
- },
997
+ cron: (deployList, jobList, name, expression, options) =>
998
+ `pm2 start ./bin/index.js --no-autorestart --instances 1 --cron "${expression}" --name ${name} -- cron ${
999
+ options?.disableKindCluster ? `--disable-kind-cluster ` : ''
1000
+ }${deployList} ${jobList}`,
904
1001
  };
905
1002
 
906
1003
  const fixDependencies = async () => {
1004
+ return;
907
1005
  // sed -i "$line_number s,.*,$new_text," "$file"
908
1006
  // sed -i "$line_number c \\$new_text" "$file"
909
1007
  const dep = fs.readFileSync(`./node_modules/peer/dist/module.mjs`, 'utf8');
@@ -933,6 +1031,34 @@ const maintenanceMiddleware = (req, res, port, proxyRouter) => {
933
1031
  }
934
1032
  };
935
1033
 
1034
+ const splitFileFactory = async (name, _path) => {
1035
+ const stats = fs.statSync(_path);
1036
+ const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
1037
+ const fileSizeInBytes = stats.size;
1038
+ if (fileSizeInBytes > maxSizeInBytes) {
1039
+ logger.info('splitFileFactory input', { name, from: _path });
1040
+ return await new Promise((resolve) => {
1041
+ splitFile
1042
+ .splitFileBySize(_path, maxSizeInBytes) // 50 mb
1043
+ .then((names) => {
1044
+ logger.info('splitFileFactory output', { parts: names });
1045
+ fs.writeFileSync(
1046
+ `${_path.split('/').slice(0, -1).join('/')}/${name}-parths.json`,
1047
+ JSON.stringify(names, null, 4),
1048
+ 'utf8',
1049
+ );
1050
+ fs.removeSync(_path);
1051
+ return resolve(true);
1052
+ })
1053
+ .catch((err) => {
1054
+ console.log('Error: ', err);
1055
+ return resolve(false);
1056
+ });
1057
+ });
1058
+ }
1059
+ return false;
1060
+ };
1061
+
936
1062
  const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
937
1063
  shellExec(`pm2 kill`);
938
1064
  shellExec(`node bin/deploy valkey-service`);
@@ -941,6 +1067,22 @@ const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
941
1067
  shellExec(`node bin/deploy run ${proxyDeployId} maintenance`);
942
1068
  };
943
1069
 
1070
+ const getNpmRootPath = () =>
1071
+ shellExec(`npm root -g`, {
1072
+ stdout: true,
1073
+ disableLog: true,
1074
+ silent: true,
1075
+ }).trim();
1076
+
1077
+ const writeEnv = (envPath, envObj) =>
1078
+ fs.writeFileSync(
1079
+ envPath,
1080
+ Object.keys(envObj)
1081
+ .map((key) => `${key}=${envObj[key]}`)
1082
+ .join(`\n`),
1083
+ 'utf8',
1084
+ );
1085
+
944
1086
  export {
945
1087
  Cmd,
946
1088
  Config,
@@ -967,9 +1109,15 @@ export {
967
1109
  deployRun,
968
1110
  getCronBackUpFolder,
969
1111
  getRestoreCronCmd,
970
- mergeBackUp,
1112
+ mergeFile,
971
1113
  fixDependencies,
972
1114
  getDeployId,
973
1115
  maintenanceMiddleware,
974
1116
  setUpProxyMaintenanceServer,
1117
+ getPathsSSR,
1118
+ buildKindPorts,
1119
+ buildPortProxyRouter,
1120
+ splitFileFactory,
1121
+ getNpmRootPath,
1122
+ writeEnv,
975
1123
  };
package/src/server/dns.js CHANGED
@@ -2,10 +2,9 @@ import axios from 'axios';
2
2
  import dotenv from 'dotenv';
3
3
  import fs from 'fs';
4
4
  import https from 'https';
5
-
5
+ import validator from 'validator';
6
6
  import { ip } from './network.js';
7
7
  import { loggerFactory } from './logger.js';
8
- import { isIPv4 } from 'is-ip';
9
8
  import { shellExec } from './process.js';
10
9
 
11
10
  const httpsAgent = new https.Agent({
@@ -18,10 +17,8 @@ dotenv.config();
18
17
 
19
18
  const logger = loggerFactory(import.meta);
20
19
 
21
- const Dns = {
22
- repoUrl: `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${process.env.GITHUB_DNS_REPO}.git`,
23
- callback: () => null,
24
- InitIpDaemon: async function ({ deployId }) {
20
+ class Dns {
21
+ static callback = async function (deployList) {
25
22
  // NAT-VPS modem/router device configuration:
26
23
  // LAN --> [NAT-VPS] --> WAN
27
24
  // enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
@@ -31,56 +28,55 @@ const Dns = {
31
28
  // LAN server or device's local servers port -> 3000-3100 (2999-3101)
32
29
  // DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
33
30
  // Forward the router's TCP/UDP ports to the LAN device's IP address
34
-
31
+ for (const _deployId of deployList.split(',')) {
32
+ const deployId = _deployId.trim();
35
33
  const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
36
-
37
34
  const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
38
- let confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
39
- if (confCronData.ipDaemon.disabled) return;
40
- Dns.ip = confCronData.ipDaemon.ip;
41
- logger.info(`Current ip`, Dns.ip);
42
- const callback = async () => {
43
- logger.info('init dns ip callback');
44
- await logger.setUpInfo();
45
- let testIp;
46
- try {
47
- testIp = await ip.public.ipv4();
48
- } catch (error) {
49
- logger.error(error, { testIp, stack: error.stack });
50
- }
51
- if (testIp && typeof testIp === 'string' && isIPv4(testIp) && Dns.ip !== testIp) {
52
- logger.info(`New ip`, testIp);
53
- for (const recordType of Object.keys(confCronData.records)) {
54
- switch (recordType) {
55
- case 'A':
56
- for (const dnsProvider of confCronData.records[recordType]) {
57
- if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
58
- await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
59
- }
60
- break;
35
+ const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
36
+
37
+ let testIp;
61
38
 
62
- default:
63
- break;
64
- }
39
+ try {
40
+ testIp = await ip.public.ipv4();
41
+ } catch (error) {
42
+ logger.error(error, { testIp, stack: error.stack });
43
+ }
44
+ const ipFileName = `${deployId}.ip`;
45
+ const currentIp = fs.existsSync(`./engine-private/deploy/${ipFileName}`)
46
+ ? fs.readFileSync(`./engine-private/deploy/${ipFileName}`, 'utf8')
47
+ : undefined;
48
+
49
+ if (testIp && typeof testIp === 'string' && validator.isIP(testIp) && currentIp !== testIp) {
50
+ logger.info(`new ip`, testIp);
51
+ for (const recordType of Object.keys(confCronData.records)) {
52
+ switch (recordType) {
53
+ case 'A':
54
+ for (const dnsProvider of confCronData.records[recordType]) {
55
+ if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
56
+ await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
57
+ }
58
+ break;
59
+
60
+ default:
61
+ break;
65
62
  }
66
- try {
67
- const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
68
- const response = await axios.get(ipUrlTest);
69
- const verifyIp = response.request.socket.remoteAddress;
70
- logger.info(ipUrlTest + ' IP', verifyIp);
71
- if (verifyIp === testIp) {
72
- await this.saveIp(confCronPath, confCronData, testIp);
73
- } else logger.error('ip not updated');
74
- } catch (error) {
75
- logger.error(error), 'ip not updated';
63
+ }
64
+ try {
65
+ const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
66
+ const response = await axios.get(ipUrlTest);
67
+ const verifyIp = response.request.socket.remoteAddress;
68
+ logger.info(ipUrlTest + ' IP', verifyIp);
69
+ if (verifyIp === testIp) {
70
+ fs.writeFileSync(`./engine-private/deploy/${ipFileName}`, testIp, 'utf8');
71
+ } else logger.error('ip not updated');
72
+ } catch (error) {
73
+ logger.error(error), 'ip not updated';
76
74
  }
77
75
  }
78
- };
79
- await callback();
80
- this.callback = callback;
81
- return callback;
82
- },
83
- services: {
76
+ }
77
+ };
78
+
79
+ static services = {
84
80
  updateIp: {
85
81
  dondominio: (options) => {
86
82
  const { user, api_key, host, dns, ip } = options;
@@ -101,21 +97,7 @@ const Dns = {
101
97
  });
102
98
  },
103
99
  },
104
- },
105
- saveIp: async (confCronPath, confCronData, ip) => {
106
- Dns.ip = ip;
107
- confCronData.ipDaemon.ip = ip;
108
- fs.writeFileSync(confCronPath, JSON.stringify(confCronData, null, 4), 'utf8');
109
- shellExec(
110
- `cd ./engine-private` +
111
- ` && git pull ${Dns.repoUrl}` +
112
- ` && git add . && git commit -m "update ip ${new Date().toLocaleDateString()}"` +
113
- ` && git push ${Dns.repoUrl}`,
114
- {
115
- disableLog: true,
116
- },
117
- );
118
- },
119
- };
100
+ };
101
+ }
120
102
 
121
- export { Dns };
103
+ export default Dns;
@@ -12,7 +12,6 @@ import morgan from 'morgan';
12
12
  import colorize from 'json-colorizer';
13
13
  import colors from 'colors';
14
14
  import v8 from 'v8';
15
- import isAdmin from 'is-admin';
16
15
  import { clearTerminalStringColor, formatBytes } from '../client/components/core/CommonJs.js';
17
16
 
18
17
  colors.enable();
@@ -79,18 +78,16 @@ const format = (meta) =>
79
78
  *
80
79
  * This function is used to log details about
81
80
  * the execution context, such as command-line arguments,
82
- * environment variables, the process's administrative privileges,
83
- * and the maximum available heap space size.
81
+ * environment variables, and the maximum available heap space size.
84
82
  *
85
83
  * @param {winston.Logger} logger - A pre-configured Winston logger object.
86
84
  * @memberof Logger
87
85
  */
88
86
  const setUpInfo = async (logger = new winston.Logger()) => {
89
- logger.info('npm_package_version', process.env.npm_package_version);
90
87
  logger.info('argv', process.argv);
88
+ logger.info('cwd', process.cwd());
91
89
  logger.info('platform', process.platform);
92
90
  logger.info('env', process.env.NODE_ENV);
93
- logger.info('admin', await isAdmin());
94
91
  logger.info('--max-old-space-size', {
95
92
  total_available_size: formatBytes(v8.getHeapStatistics().total_available_size),
96
93
  });
@@ -115,10 +112,10 @@ const loggerFactory = (meta = { url: '' }) => {
115
112
  // Allow the use the terminal to print the messages
116
113
  new winston.transports.Console(),
117
114
  // Allow to print all the error level messages inside the error.log file
118
- new winston.transports.File({
119
- filename: `logs/${meta}/error.log`,
120
- level: 'error',
121
- }),
115
+ // new winston.transports.File({
116
+ // filename: `logs/${meta}/error.log`,
117
+ // level: 'error',
118
+ // }),
122
119
  // Allow to print all the error message inside the all.log file
123
120
  // (also the error log that are also printed inside the error.log(
124
121
  new winston.transports.File({ filename: `logs/${meta}/all.log` }),
@@ -189,4 +186,12 @@ const underpostASCI = () => `
189
186
  ░╚═════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚═╝░░░░░░╚════╝░╚═════╝░░░░╚═╝░░░
190
187
  `;
191
188
 
192
- export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCI };
189
+ const actionInitLog = () =>
190
+ console.log(
191
+ underpostASCI() +
192
+ `
193
+ https://www.nexodev.org/docs
194
+ `,
195
+ );
196
+
197
+ export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCI, actionInitLog };