underpost 2.8.0 → 2.8.6

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 (119) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/ghpkg.yml +19 -49
  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 +12 -4
  6. package/.github/workflows/pwa-microservices-template.test.yml +2 -2
  7. package/.vscode/extensions.json +17 -71
  8. package/.vscode/settings.json +20 -4
  9. package/AUTHORS.md +16 -5
  10. package/CHANGELOG.md +103 -3
  11. package/Dockerfile +24 -66
  12. package/README.md +1 -28
  13. package/bin/build.js +186 -0
  14. package/bin/db.js +2 -24
  15. package/bin/deploy.js +168 -157
  16. package/bin/file.js +59 -16
  17. package/bin/hwt.js +0 -10
  18. package/bin/index.js +201 -61
  19. package/bin/ssl.js +19 -11
  20. package/bin/util.js +24 -101
  21. package/bin/vs.js +26 -2
  22. package/conf.js +30 -132
  23. package/docker-compose.yml +1 -1
  24. package/manifests/deployment/mongo-express/deployment.yaml +60 -0
  25. package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
  26. package/manifests/kind-config-dev.yaml +12 -0
  27. package/manifests/kind-config.yaml +12 -0
  28. package/manifests/letsencrypt-prod.yaml +15 -0
  29. package/manifests/mariadb/config.yaml +10 -0
  30. package/manifests/mariadb/kustomization.yaml +9 -0
  31. package/manifests/mariadb/pv.yaml +12 -0
  32. package/manifests/mariadb/pvc.yaml +10 -0
  33. package/manifests/mariadb/secret.yaml +8 -0
  34. package/manifests/mariadb/service.yaml +10 -0
  35. package/manifests/mariadb/statefulset.yaml +55 -0
  36. package/manifests/mongodb/backup-access.yaml +16 -0
  37. package/manifests/mongodb/backup-cronjob.yaml +42 -0
  38. package/manifests/mongodb/backup-pv-pvc.yaml +22 -0
  39. package/manifests/mongodb/configmap.yaml +26 -0
  40. package/manifests/mongodb/headless-service.yaml +10 -0
  41. package/manifests/mongodb/kustomization.yaml +11 -0
  42. package/manifests/mongodb/pv-pvc.yaml +23 -0
  43. package/manifests/mongodb/statefulset.yaml +125 -0
  44. package/manifests/mongodb-4.4/kustomization.yaml +7 -0
  45. package/manifests/mongodb-4.4/pv-pvc.yaml +23 -0
  46. package/manifests/mongodb-4.4/service-deployment.yaml +63 -0
  47. package/manifests/valkey/kustomization.yaml +7 -0
  48. package/manifests/valkey/service.yaml +17 -0
  49. package/manifests/valkey/statefulset.yaml +39 -0
  50. package/package.json +133 -134
  51. package/src/api/core/core.service.js +1 -1
  52. package/src/api/user/user.model.js +16 -3
  53. package/src/api/user/user.service.js +1 -1
  54. package/src/cli/cluster.js +202 -0
  55. package/src/cli/cron.js +90 -0
  56. package/src/cli/db.js +212 -0
  57. package/src/cli/deploy.js +318 -0
  58. package/src/cli/env.js +52 -0
  59. package/src/cli/fs.js +149 -0
  60. package/src/cli/image.js +148 -0
  61. package/src/cli/repository.js +125 -0
  62. package/src/cli/script.js +53 -0
  63. package/src/cli/secrets.js +37 -0
  64. package/src/cli/test.js +118 -0
  65. package/src/client/components/core/Account.js +4 -2
  66. package/src/client/components/core/Auth.js +24 -6
  67. package/src/client/components/core/CalendarCore.js +127 -50
  68. package/src/client/components/core/CommonJs.js +282 -19
  69. package/src/client/components/core/Css.js +2 -1
  70. package/src/client/components/core/CssCore.js +8 -4
  71. package/src/client/components/core/Docs.js +1 -1
  72. package/src/client/components/core/DropDown.js +5 -1
  73. package/src/client/components/core/Input.js +22 -6
  74. package/src/client/components/core/JoyStick.js +8 -5
  75. package/src/client/components/core/LoadingAnimation.js +8 -1
  76. package/src/client/components/core/Modal.js +47 -18
  77. package/src/client/components/core/Panel.js +93 -31
  78. package/src/client/components/core/PanelForm.js +27 -19
  79. package/src/client/components/core/Scroll.js +1 -0
  80. package/src/client/components/core/SignUp.js +4 -1
  81. package/src/client/components/core/Translate.js +61 -9
  82. package/src/client/components/core/Validator.js +9 -1
  83. package/src/client/components/core/VanillaJs.js +0 -9
  84. package/src/client/components/core/Worker.js +34 -31
  85. package/src/client/public/default/plantuml/client-conf.svg +1 -1
  86. package/src/client/public/default/plantuml/server-conf.svg +1 -1
  87. package/src/client/public/default/plantuml/server-schema.svg +1 -1
  88. package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
  89. package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
  90. package/src/client/services/core/core.service.js +15 -8
  91. package/src/client/services/default/default.management.js +4 -2
  92. package/src/client/ssr/Render.js +4 -1
  93. package/src/client/ssr/body/CacheControl.js +2 -2
  94. package/src/client/ssr/body/DefaultSplashScreen.js +3 -3
  95. package/src/client/ssr/offline/Maintenance.js +63 -0
  96. package/src/client/sw/default.sw.js +26 -6
  97. package/src/db/mongo/MongooseDB.js +29 -1
  98. package/src/index.js +91 -17
  99. package/src/runtime/lampp/Lampp.js +1 -13
  100. package/src/runtime/xampp/Xampp.js +0 -13
  101. package/src/server/auth.js +3 -3
  102. package/src/server/backup.js +49 -93
  103. package/src/server/client-build.js +41 -50
  104. package/src/server/client-formatted.js +6 -3
  105. package/src/server/client-icons.js +1 -1
  106. package/src/server/conf.js +207 -57
  107. package/src/server/dns.js +30 -55
  108. package/src/server/downloader.js +0 -8
  109. package/src/server/logger.js +22 -15
  110. package/src/server/network.js +17 -43
  111. package/src/server/process.js +25 -2
  112. package/src/server/proxy.js +4 -26
  113. package/src/server/runtime.js +30 -30
  114. package/src/server/ssl.js +1 -1
  115. package/src/server/valkey.js +3 -0
  116. package/test/api.test.js +0 -8
  117. package/src/dns.js +0 -22
  118. package/src/server/prompt-optimizer.js +0 -28
  119. package/startup.js +0 -11
@@ -21,6 +21,7 @@ import swaggerAutoGen from 'swagger-autogen';
21
21
  import { SitemapStream, streamToPromise } from 'sitemap';
22
22
  import { Readable } from 'stream';
23
23
  import { buildIcons, buildTextImg, getBufferPngText } from './client-icons.js';
24
+ import Underpost from '../index.js';
24
25
 
25
26
  dotenv.config();
26
27
 
@@ -50,10 +51,10 @@ const fullBuild = async ({
50
51
  buildAcmeChallengePath(acmeChallengeFullPath);
51
52
 
52
53
  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`);
54
+ if (!fs.existsSync(`/home/dd/html-website-templates/`))
55
+ shellExec(`cd /home/dd && git clone https://github.com/designmodo/html-website-templates.git`);
55
56
  if (!fs.existsSync(`${rootClientPath}/index.php`)) {
56
- fs.copySync(`/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
57
+ fs.copySync(`/home/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
57
58
  shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
58
59
  // git remote add origin git@github.com:<username>/<repo>.git
59
60
  fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
@@ -191,8 +192,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
191
192
 
192
193
  if (redirect || disabledRebuild) continue;
193
194
 
194
- if (fullBuildEnabled) {
195
- // !(confServer[host]['/'] && confServer[host]['/'].liteBuild)
195
+ if (fullBuildEnabled)
196
196
  await fullBuild({
197
197
  path,
198
198
  logger,
@@ -205,14 +205,6 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
205
205
  iconsBuild,
206
206
  metadata,
207
207
  });
208
- if (apis && false)
209
- for (const apiBuildScript of apis) {
210
- const scriptPath = `src/api/${apiBuildScript}/${apiBuildScript}.build.js`;
211
- if (fs.existsSync(`./${scriptPath}`)) {
212
- shellExec(`node ${scriptPath}`);
213
- }
214
- }
215
- }
216
208
 
217
209
  if (components)
218
210
  for (const module of Object.keys(components)) {
@@ -259,20 +251,6 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
259
251
  'services',
260
252
  baseHost,
261
253
  );
262
- if (module === 'core' && (process.env.NODE_ENV === 'production' || process.argv.includes('static'))) {
263
- if (apiBaseHost)
264
- jsSrc = jsSrc.replace(
265
- 'const getBaseHost = () => location.host;',
266
- `const getBaseHost = () => '${apiBaseHost}';`,
267
- );
268
- if (apiBaseProxyPath) {
269
- jsSrc = jsSrc.replace('${getProxyPath()}api/', `${apiBaseProxyPath}${process.env.BASE_API}/`);
270
- jsSrc = jsSrc.replace(
271
- "const getWsBasePath = () => (getProxyPath() !== '/' ? `${getProxyPath()}socket.io/` : undefined);",
272
- `const getWsBasePath = () => '${apiBaseProxyPath}socket.io/';`,
273
- );
274
- }
275
- }
276
254
  fs.writeFileSync(
277
255
  jsPublicPath,
278
256
  minifyBuild || process.env.NODE_ENV === 'production' ? UglifyJS.minify(jsSrc).code : jsSrc,
@@ -465,10 +443,11 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
465
443
  case 'DefaultSplashScreen':
466
444
  if (backgroundImage) {
467
445
  ssrHeadComponents += SrrComponent({
468
- base64BackgroundImage: `data:image/${backgroundImage.split('.').pop()};base64,${fs
469
- .readFileSync(backgroundImage)
470
- .toString('base64')}`,
446
+ backgroundImage: (path === '/' ? path : `${path}/`) + backgroundImage,
471
447
  });
448
+ // `data:image/${backgroundImage.split('.').pop()};base64,${fs
449
+ // .readFileSync()
450
+ // .toString('base64')}`,
472
451
  break;
473
452
  } else {
474
453
  ssrHeadComponents += SrrComponent({ metadata });
@@ -480,7 +459,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
480
459
  bgColor: metadata?.themeColor ? metadata.themeColor : '#ececec',
481
460
  });
482
461
  ssrHeadComponents += SrrComponent({
483
- base64BackgroundImage: `data:image/png;base64,${bufferBackgroundImage.toString('base64')}`,
462
+ backgroundImage: `data:image/png;base64,${bufferBackgroundImage.toString('base64')}`,
484
463
  });
485
464
  }
486
465
 
@@ -495,7 +474,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
495
474
  }
496
475
 
497
476
  default:
498
- ssrBodyComponents += SrrComponent({ ssrPath, host, path, ttiLoadTimeLimit });
477
+ ssrBodyComponents += SrrComponent({
478
+ ssrPath,
479
+ host,
480
+ path,
481
+ ttiLoadTimeLimit,
482
+ version: Underpost.version,
483
+ });
499
484
  break;
500
485
  }
501
486
  }
@@ -515,6 +500,15 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
515
500
  ssrPath,
516
501
  ssrHeadComponents,
517
502
  ssrBodyComponents,
503
+ renderPayload: {
504
+ apiBaseProxyPath,
505
+ apiBaseHost,
506
+ apiBasePath: process.env.BASE_API,
507
+ version: Underpost.version,
508
+ },
509
+ renderApi: {
510
+ JSONweb,
511
+ },
518
512
  });
519
513
 
520
514
  fs.writeFileSync(
@@ -544,17 +538,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
544
538
  let siteMapSrc = await new Promise((resolve) =>
545
539
  streamToPromise(Readable.from(siteMapLinks).pipe(siteMapStream)).then((data) => resolve(data.toString())),
546
540
  );
547
- switch (publicClientId) {
548
- case 'underpost':
549
- siteMapSrc = siteMapSrc.replaceAll(
550
- `</urlset>`,
551
- `${fs.readFileSync(`./src/client/public/underpost/sitemap-template.txt`, 'utf8')} </urlset>`,
552
- );
553
- break;
554
541
 
555
- default:
556
- break;
557
- }
558
542
  // Return a promise that resolves with your XML string
559
543
  fs.writeFileSync(`${rootClientPath}/sitemap.xml`, siteMapSrc, 'utf8');
560
544
  if (xslUrl)
@@ -725,6 +709,15 @@ root file where the route starts, such as index.js, app.js, routes.js, etc ... *
725
709
  ssrPath,
726
710
  ssrHeadComponents: '',
727
711
  ssrBodyComponents: SsrComponent(),
712
+ renderPayload: {
713
+ apiBaseProxyPath,
714
+ apiBaseHost,
715
+ apiBasePath: process.env.BASE_API,
716
+ version: Underpost.version,
717
+ },
718
+ renderApi: {
719
+ JSONweb,
720
+ },
728
721
  });
729
722
 
730
723
  const buildPath = `${
@@ -757,16 +750,14 @@ root file where the route starts, such as index.js, app.js, routes.js, etc ... *
757
750
  }
758
751
 
759
752
  {
760
- const PRE_CACHED_JSON = `PRE_CACHED_RESOURCES = ${JSONweb(uniqueArray(PRE_CACHED_RESOURCES))}`;
761
- const PROXY_PATH = `PROXY_PATH = '${path}'`;
753
+ const renderPayload = {
754
+ PRE_CACHED_RESOURCES: uniqueArray(PRE_CACHED_RESOURCES),
755
+ PROXY_PATH: path,
756
+ };
762
757
  fs.writeFileSync(
763
758
  `${rootClientPath}/sw.js`,
764
- fs
765
- .readFileSync(`${rootClientPath}/sw.js`, 'utf8')
766
- .replaceAll(`PRE_CACHED_RESOURCES = []`, PRE_CACHED_JSON)
767
- .replaceAll(`PRE_CACHED_RESOURCES=[]`, PRE_CACHED_JSON)
768
- .replaceAll(`PROXY_PATH = '/'`, PROXY_PATH)
769
- .replaceAll(`PROXY_PATH='/'`, PROXY_PATH),
759
+ `self.renderPayload = ${JSONweb(renderPayload)};
760
+ ${fs.readFileSync(`${rootClientPath}/sw.js`, 'utf8')}`,
770
761
  'utf8',
771
762
  );
772
763
  }
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  import fs from 'fs-extra';
4
+ import vm from 'node:vm';
5
+ import Underpost from '../index.js';
4
6
 
5
7
  const srcFormatted = (src) =>
6
8
  src
@@ -48,9 +50,10 @@ const viewFormatted = (src, dists, proxyPath, baseHost = '') => {
48
50
  };
49
51
 
50
52
  const ssrFactory = async (componentPath = `./src/client/ssr/Render.js`) => {
51
- let SrrComponent = () => {};
52
- eval(await srcFormatted(fs.readFileSync(componentPath, 'utf8')));
53
- return SrrComponent;
53
+ const context = { SrrComponent: () => {}, npm_package_version: Underpost.version };
54
+ vm.createContext(context);
55
+ vm.runInContext(await srcFormatted(fs.readFileSync(componentPath, 'utf8')), context);
56
+ return context.SrrComponent;
54
57
  };
55
58
 
56
59
  export { srcFormatted, JSONweb, componentFormatted, viewFormatted, ssrFactory };
@@ -141,7 +141,7 @@ const buildIcons = async ({
141
141
  for (const file of response.files)
142
142
  fs.writeFileSync(`./src/client/public/${publicClientId}/${file.name}`, file.contents, 'utf8');
143
143
 
144
- const ssrPath = `./src/client/ssr/components/head/Pwa${getCapVariableName(publicClientId)}.js`;
144
+ const ssrPath = `./src/client/ssr/head/Pwa${getCapVariableName(publicClientId)}.js`;
145
145
  if (!fs.existsSync(ssrPath))
146
146
  fs.writeFileSync(ssrPath, 'SrrComponent = () => html`' + response.html.join(`\n`) + '`;', 'utf8');
147
147
  } catch (error) {
@@ -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,22 +16,13 @@ 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';
16
- import https from 'https';
17
22
  import { ssrFactory } from './client-formatted.js';
18
23
 
19
- // axios.defaults.baseURL = BASE_URL;
20
-
21
- const httpsAgent = new https.Agent({
22
- rejectUnauthorized: false,
23
- });
24
-
25
- axios.defaults.httpsAgent = httpsAgent;
26
-
27
24
  colors.enable();
25
+
28
26
  dotenv.config();
29
27
 
30
28
  const logger = loggerFactory(import.meta);
@@ -33,21 +31,26 @@ const logger = loggerFactory(import.meta);
33
31
 
34
32
  const Config = {
35
33
  default: DefaultConf,
36
- build: async function (options = { folder: '' }) {
34
+ build: async function (options = { folder: '' }, deployContext, deployList, subConf) {
35
+ if (!deployContext) deployContext = process.argv[2];
37
36
  if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
38
37
  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]);
38
+ if (fs.existsSync(`./engine-private/conf/${deployContext}`))
39
+ return loadConf(deployContext, process.env.NODE_ENV, subConf);
40
+ if (fs.existsSync(`./engine-private/replica/${deployContext}`))
41
+ return loadConf(deployContext, process.env.NODE_ENV, subConf);
41
42
 
42
- if (process.argv[2] === 'deploy') return;
43
+ if (deployContext === 'deploy') return;
43
44
 
44
- if (process.argv[2] === 'proxy') {
45
+ if (deployContext === 'proxy') {
46
+ if (!deployList) deployList = process.argv[3];
47
+ if (!subConf) subConf = process.argv[4];
45
48
  this.default.server = {};
46
- for (const deployId of process.argv[3].split(',')) {
49
+ for (const deployId of deployList.split(',')) {
47
50
  let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
48
51
  const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
49
52
  ? `./engine-private/replica/${deployId}/conf.server.json`
50
- : `./engine-private/conf/${deployId}/conf.server.dev.${process.argv[4]}.json`;
53
+ : `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
51
54
  const confDevPath = fs.existsSync(privateConfDevPath)
52
55
  ? privateConfDevPath
53
56
  : `./engine-private/conf/${deployId}/conf.server.dev.json`;
@@ -55,7 +58,7 @@ const Config = {
55
58
  if (process.env.NODE_ENV === 'development' && fs.existsSync(confDevPath)) confPath = confDevPath;
56
59
  const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
57
60
 
58
- for (const host of Object.keys(loadReplicas(serverConf))) {
61
+ for (const host of Object.keys(loadReplicas(serverConf, deployContext, subConf))) {
59
62
  if (serverConf[host]['/'])
60
63
  this.default.server[host] = {
61
64
  ...this.default.server[host],
@@ -85,7 +88,15 @@ const Config = {
85
88
  },
86
89
  };
87
90
 
88
- const loadConf = (deployId) => {
91
+ const loadConf = (deployId, envInput, subConf) => {
92
+ if (deployId === 'clean') {
93
+ shellExec(`git checkout package.json`);
94
+ shellExec(`git checkout .env.production`);
95
+ shellExec(`git checkout .env.development`);
96
+ shellExec(`git checkout .env.test`);
97
+ shellExec(`git checkout jsdoc.json`);
98
+ return;
99
+ }
89
100
  const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
90
101
  ? `./engine-private/replica/${deployId}`
91
102
  : `./engine-private/conf/${deployId}`;
@@ -102,7 +113,8 @@ const loadConf = (deployId) => {
102
113
  ? fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8')
103
114
  : JSON.stringify(Config.default[typeConf]);
104
115
  if (process.env.NODE_ENV === 'development' && typeConf === 'server') {
105
- const devConfPath = `${folder}/conf.${typeConf}.dev${process.argv[3] ? `.${process.argv[3]}` : ''}.json`;
116
+ if (!subConf) subConf = process.argv[3];
117
+ const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
106
118
  if (fs.existsSync(devConfPath)) srcConf = fs.readFileSync(devConfPath, 'utf8');
107
119
  }
108
120
  if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(JSON.parse(srcConf)), null, 4);
@@ -111,27 +123,34 @@ const loadConf = (deployId) => {
111
123
  fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
112
124
  fs.writeFileSync(`./.env.development`, fs.readFileSync(`${folder}/.env.development`, 'utf8'), 'utf8');
113
125
  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'));
126
+ const NODE_ENV = envInput || process.env.NODE_ENV;
127
+ if (NODE_ENV) {
128
+ fs.writeFileSync(`./.env`, fs.readFileSync(`${folder}/.env.${NODE_ENV}`, 'utf8'), 'utf8');
129
+ const env = dotenv.parse(fs.readFileSync(`${folder}/.env.${NODE_ENV}`, 'utf8'));
117
130
  process.env = {
118
131
  ...process.env,
119
132
  ...env,
120
133
  };
121
134
  }
122
- fs.writeFileSync(`./package.json`, fs.readFileSync(`${folder}/package.json`, 'utf8'), 'utf8');
135
+ const originPackageJson = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
136
+ const packageJson = JSON.parse(fs.readFileSync(`${folder}/package.json`, 'utf8'));
137
+ originPackageJson.scripts.start = packageJson.scripts.start;
138
+ packageJson.scripts = originPackageJson.scripts;
139
+ fs.writeFileSync(`./package.json`, JSON.stringify(packageJson, null, 4), 'utf8');
123
140
  return { folder, deployId };
124
141
  };
125
142
 
126
- const loadReplicas = (confServer) => {
143
+ const loadReplicas = (confServer, deployContext, subConf) => {
144
+ if (!deployContext) deployContext = process.argv[2];
145
+ if (!subConf) subConf = process.argv[3];
127
146
  for (const host of Object.keys(confServer)) {
128
147
  for (const path of Object.keys(confServer[host])) {
129
148
  const { replicas, singleReplica } = confServer[host][path];
130
149
  if (
131
150
  replicas &&
132
- (process.argv[2] === 'proxy' ||
151
+ (deployContext === 'proxy' ||
133
152
  !singleReplica ||
134
- (singleReplica && process.env.NODE_ENV === 'development' && !process.argv[3]))
153
+ (singleReplica && process.env.NODE_ENV === 'development' && !subConf))
135
154
  )
136
155
  for (const replicaPath of replicas) {
137
156
  confServer[host][replicaPath] = newInstance(confServer[host][path]);
@@ -253,8 +272,8 @@ const buildClientSrc = async (
253
272
  }
254
273
 
255
274
  fs.writeFileSync(
256
- `./src/client/ssr/components/head/${toClientVariableName}Scripts.js`,
257
- formattedSrc(fs.readFileSync(`./src/client/ssr/components/head/${fromClientVariableName}Scripts.js`, 'utf8')),
275
+ `./src/client/ssr/head/${toClientVariableName}Scripts.js`,
276
+ formattedSrc(fs.readFileSync(`./src/client/ssr/head/${fromClientVariableName}Scripts.js`, 'utf8')),
258
277
  'utf8',
259
278
  );
260
279
 
@@ -473,13 +492,55 @@ const buildProxyRouter = () => {
473
492
  title: 'Site in maintenance',
474
493
  ssrPath: '/',
475
494
  ssrHeadComponents: '',
476
- ssrBodyComponents: (await ssrFactory(`./src/client/ssr/body/Maintenance.js`))(),
495
+ ssrBodyComponents: (await ssrFactory(`./src/client/ssr/offline/Maintenance.js`))(),
477
496
  });
478
497
  })();
479
498
 
480
499
  return proxyRouter;
481
500
  };
482
501
 
502
+ const buildKindPorts = (from, to) =>
503
+ range(parseInt(from), parseInt(to))
504
+ .map(
505
+ (port) => ` - name: 'tcp-${port}'
506
+ protocol: TCP
507
+ port: ${port}
508
+ targetPort: ${port}
509
+ - name: 'udp-${port}'
510
+ protocol: UDP
511
+ port: ${port}
512
+ targetPort: ${port}
513
+ `,
514
+ )
515
+ .join('\n');
516
+
517
+ const buildPortProxyRouter = (port, proxyRouter) => {
518
+ const hosts = proxyRouter[port];
519
+ const router = {};
520
+ // build router
521
+ Object.keys(hosts).map((hostKey) => {
522
+ let { host, path, target, proxy, peer } = hosts[hostKey];
523
+ if (process.argv.includes('localhost') && process.env.NODE_ENV === 'development') host = `localhost`;
524
+
525
+ if (!proxy.includes(port)) return;
526
+ const absoluteHost = [80, 443].includes(port)
527
+ ? `${host}${path === '/' ? '' : path}`
528
+ : `${host}:${port}${path === '/' ? '' : path}`;
529
+
530
+ if (process.argv.includes('localhost')) {
531
+ if (!(absoluteHost in router)) router[absoluteHost] = target;
532
+ } else router[absoluteHost] = target;
533
+ }); // order router
534
+
535
+ if (Object.keys(router).length === 0) return router;
536
+
537
+ const reOrderRouter = {};
538
+ for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
539
+ reOrderRouter[absoluteHostKey] = router[absoluteHostKey];
540
+
541
+ return reOrderRouter;
542
+ };
543
+
483
544
  const cliBar = async (time = 5000) => {
484
545
  // create new progress bar
485
546
  const b = new cliProgress.SingleBar({
@@ -528,9 +589,25 @@ const cliSpinner = async (time = 5000, message0, message1, color, type = 'dots')
528
589
  const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
529
590
 
530
591
  const getDataDeploy = (
531
- options = { buildSingleReplica: false, deployGroupId: '', deployId: '', disableSyncEnvPort: false },
592
+ options = {
593
+ buildSingleReplica: false,
594
+ deployGroupId: '',
595
+ deployId: '',
596
+ disableSyncEnvPort: false,
597
+ deployIdConcat: [],
598
+ },
532
599
  ) => {
533
- let dataDeploy = JSON.parse(fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.json`, 'utf8'));
600
+ let dataDeploy =
601
+ options.deployGroupId === 'dd'
602
+ ? fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.router`, 'utf8')
603
+ : fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}`, 'utf8');
604
+
605
+ dataDeploy = dataDeploy
606
+ .split(',')
607
+ .map((deployId) => deployId.trim())
608
+ .filter((deployId) => deployId);
609
+
610
+ if (options.deployIdConcat) dataDeploy = dataDeploy.concat(options.deployIdConcat);
534
611
 
535
612
  if (options.deployId) dataDeploy = dataDeploy.filter((d) => d === options.deployId);
536
613
 
@@ -588,6 +665,7 @@ const validateTemplatePath = (absolutePath = '') => {
588
665
  if (absolutePath.match('src/api') && !confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))) {
589
666
  return false;
590
667
  }
668
+ if (absolutePath.match('conf.dd-') && absolutePath.match('.js')) return false;
591
669
  if (
592
670
  absolutePath.match('src/client/services/') &&
593
671
  !clients.find((p) => absolutePath.match(`src/client/services/${p}/`))
@@ -764,15 +842,16 @@ const deployRun = async (dataDeploy, currentAttempt = 1) => {
764
842
  if (failed.length > 0) {
765
843
  for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
766
844
  if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
767
- if (process.argv.includes('manual')) await read({ prompt: 'Press enter to retry failed processes\n' });
845
+ await read({ prompt: 'Press enter to retry failed processes\n' });
768
846
  currentAttempt++;
769
847
  await deployRun(failed, currentAttempt);
770
848
  } else logger.info(`Deploy process successfully`);
771
849
  };
772
850
 
773
- const restoreMacroDb = async (deployGroupId = '') => {
851
+ const restoreMacroDb = async (deployGroupId = '', deployId = null) => {
774
852
  const dataDeploy = await getDataDeploy({ deployGroupId, buildSingleReplica: false });
775
853
  for (const deployGroup of dataDeploy) {
854
+ if (deployId && deployGroup.deployId !== deployId) continue;
776
855
  if (!deployGroup.replicaHost) {
777
856
  const deployServerConfPath = `./engine-private/conf/${deployGroup.deployId}/conf.server.json`;
778
857
  const serverConf = JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8'));
@@ -790,13 +869,10 @@ const restoreMacroDb = async (deployGroupId = '') => {
790
869
  }
791
870
  };
792
871
 
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
- );
872
+ const mergeFile = async (parts = [], outputFilePath) => {
797
873
  await new Promise((resolve) => {
798
874
  splitFile
799
- .mergeFiles(names, outputFilePath)
875
+ .mergeFiles(parts, outputFilePath)
800
876
  .then(() => {
801
877
  resolve();
802
878
  })
@@ -848,11 +924,13 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
848
924
  {
849
925
  if (process.argv.includes('cron')) {
850
926
  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
- );
927
+ if (fs.existsSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`)) {
928
+ const names = JSON.parse(
929
+ fs.readFileSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`, 'utf8'),
930
+ ).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
931
+
932
+ await mergeFile(names, `${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`);
933
+ }
856
934
  } else {
857
935
  cmd = `mysql -u ${user} -p${password} ${name} < ${
858
936
  backupPath ? backupPath : `./engine-private/sql-backups/${name}.sql`
@@ -863,15 +941,23 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
863
941
  backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
864
942
  }/${name}-parths.json`,
865
943
  )
866
- )
867
- await mergeBackUp(
868
- `${
869
- backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
870
- }/${name}-parths.json`,
944
+ ) {
945
+ const names = JSON.parse(
946
+ fs.readFileSync(
947
+ `${
948
+ backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
949
+ }/${name}-parths.json`,
950
+ 'utf8',
951
+ ),
952
+ ).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
953
+
954
+ await mergeFile(
955
+ names,
871
956
  `${
872
957
  backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
873
958
  }/${name}.sql`,
874
959
  );
960
+ }
875
961
  }
876
962
  }
877
963
  break;
@@ -890,20 +976,31 @@ const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deplo
890
976
  return cmd;
891
977
  };
892
978
 
979
+ const getPathsSSR = (conf) => {
980
+ const paths = ['src/client/ssr/Render.js'];
981
+ for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
982
+ for (const o of conf.body) paths.push(`src/client/ssr/body/${o}.js`);
983
+ for (const o of Object.keys(conf.mailer)) paths.push(`src/client/ssr/mailer/${conf.mailer[o]}.js`);
984
+ for (const o of conf.offline) paths.push(`src/client/ssr/mailer/${o.client}.js`);
985
+ for (const o of conf.pages) paths.push(`src/client/ssr/pages/${o.client}.js`);
986
+ return paths;
987
+ };
988
+
893
989
  const Cmd = {
894
990
  delete: (deployId) => `pm2 delete ${deployId}`,
895
- run: (deployId) => `node bin/deploy run ${deployId}`,
991
+ run: () => `npm start`,
896
992
  build: (deployId) => `node bin/deploy build-full-client ${deployId}${process.argv.includes('l') ? ' l' : ''}`,
897
993
  conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
898
994
  replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
899
995
  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
- },
996
+ cron: (deployList, jobList, name, expression, options) =>
997
+ `pm2 start ./bin/index.js --no-autorestart --instances 1 --cron "${expression}" --name ${name} -- cron ${
998
+ options?.itc ? `--itc ` : ''
999
+ }${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
904
1000
  };
905
1001
 
906
1002
  const fixDependencies = async () => {
1003
+ return;
907
1004
  // sed -i "$line_number s,.*,$new_text," "$file"
908
1005
  // sed -i "$line_number c \\$new_text" "$file"
909
1006
  const dep = fs.readFileSync(`./node_modules/peer/dist/module.mjs`, 'utf8');
@@ -933,14 +1030,60 @@ const maintenanceMiddleware = (req, res, port, proxyRouter) => {
933
1030
  }
934
1031
  };
935
1032
 
1033
+ const splitFileFactory = async (name, _path) => {
1034
+ const stats = fs.statSync(_path);
1035
+ const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
1036
+ const fileSizeInBytes = stats.size;
1037
+ if (fileSizeInBytes > maxSizeInBytes) {
1038
+ logger.info('splitFileFactory input', { name, from: _path });
1039
+ return await new Promise((resolve) => {
1040
+ splitFile
1041
+ .splitFileBySize(_path, maxSizeInBytes) // 50 mb
1042
+ .then((names) => {
1043
+ logger.info('splitFileFactory output', { parts: names });
1044
+ fs.writeFileSync(
1045
+ `${_path.split('/').slice(0, -1).join('/')}/${name}-parths.json`,
1046
+ JSON.stringify(names, null, 4),
1047
+ 'utf8',
1048
+ );
1049
+ fs.removeSync(_path);
1050
+ return resolve(true);
1051
+ })
1052
+ .catch((err) => {
1053
+ console.log('Error: ', err);
1054
+ return resolve(false);
1055
+ });
1056
+ });
1057
+ }
1058
+ return false;
1059
+ };
1060
+
936
1061
  const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
937
1062
  shellExec(`pm2 kill`);
938
1063
  shellExec(`node bin/deploy valkey-service`);
939
1064
  const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
940
1065
  shellExec(`node bin/deploy conf ${proxyDeployId} production`);
941
- shellExec(`node bin/deploy run ${proxyDeployId} maintenance`);
1066
+ shellExec(`npm start ${proxyDeployId} maintenance`);
942
1067
  };
943
1068
 
1069
+ const getNpmRootPath = () =>
1070
+ shellExec(`npm root -g`, {
1071
+ stdout: true,
1072
+ disableLog: true,
1073
+ silent: true,
1074
+ }).trim();
1075
+
1076
+ const getUnderpostRootPath = () => `${getNpmRootPath()}/underpost`;
1077
+
1078
+ const writeEnv = (envPath, envObj) =>
1079
+ fs.writeFileSync(
1080
+ envPath,
1081
+ Object.keys(envObj)
1082
+ .map((key) => `${key}=${envObj[key]}`)
1083
+ .join(`\n`),
1084
+ 'utf8',
1085
+ );
1086
+
944
1087
  export {
945
1088
  Cmd,
946
1089
  Config,
@@ -967,9 +1110,16 @@ export {
967
1110
  deployRun,
968
1111
  getCronBackUpFolder,
969
1112
  getRestoreCronCmd,
970
- mergeBackUp,
1113
+ mergeFile,
971
1114
  fixDependencies,
972
1115
  getDeployId,
973
1116
  maintenanceMiddleware,
974
1117
  setUpProxyMaintenanceServer,
1118
+ getPathsSSR,
1119
+ buildKindPorts,
1120
+ buildPortProxyRouter,
1121
+ splitFileFactory,
1122
+ getNpmRootPath,
1123
+ getUnderpostRootPath,
1124
+ writeEnv,
975
1125
  };