underpost 2.7.7 → 2.7.9

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 (79) hide show
  1. package/.github/workflows/ghpkg.yml +115 -0
  2. package/.github/workflows/publish.yml +20 -3
  3. package/.github/workflows/pwa-microservices-template.page.yml +54 -0
  4. package/.github/workflows/pwa-microservices-template.test.yml +30 -0
  5. package/.vscode/settings.json +6 -0
  6. package/CHANGELOG.md +64 -16
  7. package/bin/cron.js +47 -0
  8. package/bin/db.js +9 -1
  9. package/bin/deploy.js +207 -11
  10. package/bin/file.js +17 -1
  11. package/bin/index.js +1 -1
  12. package/bin/util.js +22 -0
  13. package/conf.js +18 -4
  14. package/docker-compose.yml +1 -1
  15. package/package.json +3 -3
  16. package/src/api/core/core.router.js +9 -9
  17. package/src/api/core/core.service.js +6 -4
  18. package/src/api/default/default.service.js +4 -4
  19. package/src/api/file/file.service.js +3 -3
  20. package/src/api/user/user.service.js +7 -7
  21. package/src/client/components/core/Css.js +0 -222
  22. package/src/client/components/core/CssCore.js +30 -3
  23. package/src/client/components/core/Docs.js +110 -10
  24. package/src/client/components/core/Modal.js +224 -22
  25. package/src/client/components/core/Panel.js +1 -1
  26. package/src/client/components/core/PanelForm.js +2 -1
  27. package/src/client/components/core/Responsive.js +15 -0
  28. package/src/client/components/core/RichText.js +4 -2
  29. package/src/client/components/core/Translate.js +6 -2
  30. package/src/client/components/core/WebComponent.js +44 -0
  31. package/src/client/components/core/Worker.js +12 -4
  32. package/src/client/public/default/plantuml/client-conf.svg +1 -1
  33. package/src/client/public/default/plantuml/client-schema.svg +1 -1
  34. package/src/client/public/default/plantuml/cron-conf.svg +1 -1
  35. package/src/client/public/default/plantuml/cron-schema.svg +1 -1
  36. package/src/client/public/default/plantuml/server-conf.svg +1 -1
  37. package/src/client/public/default/plantuml/server-schema.svg +1 -1
  38. package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
  39. package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
  40. package/src/client/public/default/site.webmanifest +69 -0
  41. package/src/client/services/default/default.management.js +118 -120
  42. package/src/client/ssr/Render.js +224 -3
  43. package/src/client/ssr/common/Alert.js +75 -0
  44. package/src/client/ssr/common/SsrCore.js +91 -0
  45. package/src/client/ssr/common/Translate.js +26 -0
  46. package/src/client/ssr/common/Worker.js +28 -0
  47. package/src/client/ssr/{body-components → components/body}/CacheControl.js +1 -1
  48. package/src/client/ssr/{body-components → components/body}/DefaultSplashScreen.js +15 -4
  49. package/src/client/ssr/components/head/Pwa.js +146 -0
  50. package/src/client/ssr/pages/404.js +12 -0
  51. package/src/client/ssr/pages/500.js +12 -0
  52. package/src/client/ssr/pages/maintenance.js +14 -0
  53. package/src/client/ssr/pages/offline.js +21 -0
  54. package/src/client/sw/default.sw.js +13 -9
  55. package/src/db/DataBaseProvider.js +12 -1
  56. package/src/db/mongo/MongooseDB.js +0 -1
  57. package/src/mailer/EmailRender.js +1 -1
  58. package/src/server/backup.js +82 -70
  59. package/src/server/client-build-live.js +6 -0
  60. package/src/server/client-build.js +76 -73
  61. package/src/server/client-formatted.js +11 -1
  62. package/src/server/client-icons.js +1 -1
  63. package/src/server/conf.js +60 -12
  64. package/src/server/crypto.js +91 -0
  65. package/src/server/dns.js +42 -13
  66. package/src/server/network.js +94 -7
  67. package/src/server/proxy.js +27 -27
  68. package/src/server/runtime.js +27 -8
  69. package/.github/workflows/test.yml +0 -80
  70. package/src/client/ssr/head-components/Microdata.js +0 -11
  71. package/src/cron.js +0 -30
  72. package/src/server/cron.js +0 -35
  73. /package/src/client/ssr/{email-components → components/email}/DefaultRecoverEmail.js +0 -0
  74. /package/src/client/ssr/{email-components → components/email}/DefaultVerifyEmail.js +0 -0
  75. /package/src/client/ssr/{head-components → components/head}/Css.js +0 -0
  76. /package/src/client/ssr/{head-components → components/head}/DefaultScripts.js +0 -0
  77. /package/src/client/ssr/{head-components → components/head}/Production.js +0 -0
  78. /package/src/client/ssr/{head-components → components/head}/PwaDefault.js +0 -0
  79. /package/src/client/ssr/{head-components → components/head}/Seo.js +0 -0
@@ -0,0 +1,21 @@
1
+ import { htmls, loggerFactory } from '../common/SsrCore.js';
2
+ import { Alert } from '../common/Alert.js';
3
+ import { Translate } from '../common/Translate.js';
4
+ import { Worker } from '../common/Worker.js';
5
+ /*imports*/
6
+
7
+ const logger = loggerFactory({ url: location.toString() });
8
+
9
+ window.onload = () =>
10
+ Worker.instance({
11
+ render: async () => {
12
+ window.ononline = async () => {
13
+ location.href = location.pathname.split('/')[1] ? `/${location.pathname.split('/')[1].split('.')[0]}` : '/';
14
+ };
15
+ window.onoffline = async () => {
16
+ htmls(`.page-render`, html`${await Alert.noInternet({ Translate })}`);
17
+ };
18
+ if (navigator.onLine && !location.hostname.match('localhost')) window.ononline();
19
+ else window.onoffline();
20
+ },
21
+ });
@@ -37,6 +37,8 @@ even while offline, can asynchronously save files and many other things)
37
37
 
38
38
  const logger = loggerFactory(import.meta);
39
39
 
40
+ const PROXY_PATH = '/';
41
+
40
42
  self.addEventListener('install', (event) => {
41
43
  // Activate right away
42
44
  self.skipWaiting();
@@ -179,15 +181,17 @@ self.addEventListener('fetch', (event) => {
179
181
  }
180
182
 
181
183
  logger.error('Fetch failed; returning offline page instead.', { error, path });
182
-
183
- // const cache = await caches.open(CACHE_NAME);
184
- // const cachedResponse = await cache.match(OFFLINE_URL);
185
- // return cachedResponse;
186
-
187
- const response = new Response(JSON.stringify({ status: 'error', message: 'offline test response' }));
188
- // response.status = 200;
189
- response.headers.set('Content-Type', 'application/json');
190
- return response;
184
+ try {
185
+ const cache = await caches.open(`${PROXY_PATH}offline.html`);
186
+ const cachedResponse = await cache.match(`${PROXY_PATH}offline.html`);
187
+ return cachedResponse;
188
+ } catch (error) {
189
+ logger.error('Error opening cache for offline page', { error, path });
190
+ const response = new Response(JSON.stringify({ status: 'error', message: 'offline test response' }));
191
+ // response.status = 200;
192
+ response.headers.set('Content-Type', 'application/json');
193
+ return response;
194
+ }
191
195
  }
192
196
  })(),
193
197
  );
@@ -18,7 +18,18 @@ const DataBaseProvider = {
18
18
  case 'mongoose':
19
19
  {
20
20
  const conn = await MongooseDB.connect(db.host, db.name);
21
- this.instance[`${host}${path}`][db.provider] = await MongooseDB.loadModels({ conn, apis });
21
+ this.instance[`${host}${path}`][db.provider] = {
22
+ models: await MongooseDB.loadModels({ conn, apis }),
23
+ connection: conn,
24
+ close: async () => {
25
+ return await new Promise((resolve) => {
26
+ DataBaseProvider.instance[`${host}${path}`][db.provider].connection.close().then(() => {
27
+ // logger.info('Mongoose connection is disconnected', db);
28
+ return resolve();
29
+ });
30
+ });
31
+ },
32
+ };
22
33
  }
23
34
  break;
24
35
  default:
@@ -1,5 +1,4 @@
1
1
  import mongoose from 'mongoose';
2
- import cron from 'node-cron';
3
2
  import { loggerFactory } from '../../server/logger.js';
4
3
  import { getCapVariableName } from '../../client/components/core/CommonJs.js';
5
4
  import { shellCd, shellExec } from '../../server/process.js';
@@ -59,7 +59,7 @@ const EmailRender = {
59
59
  for (const templateKey of Object.keys(options.templates)) {
60
60
  const ssrEmailComponent = options.templates[templateKey];
61
61
  let SrrComponent;
62
- eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/email-components/${ssrEmailComponent}.js`, 'utf8')));
62
+ eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/components/email/${ssrEmailComponent}.js`, 'utf8')));
63
63
  templates[templateKey] = SrrComponent(this, options);
64
64
  }
65
65
  return templates;
@@ -9,100 +9,112 @@ dotenv.config();
9
9
  const logger = loggerFactory(import.meta);
10
10
 
11
11
  const BackUpManagement = {
12
- repoUrl: `https://${process.env.GITHUB_BACKUP_TOKEN}@github.com/${process.env.GITHUB_BACKUP_USERNAME}/${process.env.GITHUB_BACKUP_REPO}.git`,
13
- Init: async function () {
14
- await this.Callback();
15
- return this.Callback;
16
- },
17
- Callback: async function () {
18
- const privateCronConfPath = `./engine-private/conf/${process.argv[2]}/conf.cron.json`;
12
+ repoUrl: `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${process.env.GITHUB_BACKUP_REPO}.git`,
13
+ Init: async function ({ deployId }) {
14
+ const Callback = async function () {
15
+ const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
19
16
 
20
- const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
17
+ const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
21
18
 
22
- const { backups } = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
19
+ const { backups } = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
23
20
 
24
- if (!backups) return;
21
+ if (!backups) return;
25
22
 
26
- const currentDate = new Date().getTime();
23
+ logger.info('init backups callback');
24
+ await logger.setUpInfo();
27
25
 
28
- if (!fs.existsSync('./engine-private/cron-backups'))
29
- fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
26
+ const currentDate = new Date().getTime();
30
27
 
31
- for (const deployGroupData of backups) {
32
- const { deployGroupId } = deployGroupData;
33
- const dataDeploy = getDataDeploy({ deployGroupId });
28
+ if (!fs.existsSync('./engine-private/cron-backups'))
29
+ fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
34
30
 
35
- for (const deployObj of dataDeploy) {
36
- const { deployId, replicaHost } = deployObj;
31
+ for (const deployGroupData of backups) {
32
+ const { deployGroupId } = deployGroupData;
33
+ const dataDeploy = getDataDeploy({ deployGroupId });
37
34
 
38
- if (replicaHost) continue;
35
+ for (const deployObj of dataDeploy) {
36
+ const { deployId, replicaHost } = deployObj;
39
37
 
40
- const confServer = JSON.parse(
41
- fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
42
- ? fs.readFileSync(`./engine-private/replica/${deployId}/conf.server.json`, 'utf8')
43
- : fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
44
- );
38
+ if (replicaHost) continue;
45
39
 
46
- for (const host of Object.keys(confServer))
47
- for (const path of Object.keys(confServer[host])) {
48
- // retention policy
49
- let { db, backupFrequency, maxBackupRetention, singleReplica, wp, git, directory } = confServer[host][path];
40
+ const confServer = JSON.parse(
41
+ fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
42
+ ? fs.readFileSync(`./engine-private/replica/${deployId}/conf.server.json`, 'utf8')
43
+ : fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
44
+ );
50
45
 
51
- if (!db || singleReplica) continue;
46
+ for (const host of Object.keys(confServer))
47
+ for (const path of Object.keys(confServer[host])) {
48
+ // retention policy
49
+ let { db, backupFrequency, maxBackupRetention, singleReplica, wp, git, directory } =
50
+ confServer[host][path];
52
51
 
53
- if (!backupFrequency) backupFrequency = 'daily';
54
- if (!maxBackupRetention) maxBackupRetention = 5;
52
+ if (!db || singleReplica) continue;
55
53
 
56
- const backUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
57
- if (!fs.existsSync(backUpPath)) fs.mkdirSync(`${backUpPath}`, { recursive: true });
58
- // .isDirectory()
59
- const files = await fs.readdir(backUpPath, { withFileTypes: true });
54
+ if (!backupFrequency) backupFrequency = 'daily';
55
+ if (!maxBackupRetention) maxBackupRetention = 5;
60
56
 
61
- const currentBackupsDirs = files
62
- .map((fileObj) => parseInt(fileObj.name))
63
- .sort((a, b) => a - b)
64
- .reverse();
57
+ const backUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
58
+ if (!fs.existsSync(backUpPath)) fs.mkdirSync(`${backUpPath}`, { recursive: true });
59
+ // .isDirectory()
60
+ const files = await fs.readdir(backUpPath, { withFileTypes: true });
65
61
 
66
- switch (backupFrequency) {
67
- case 'daily':
62
+ const currentBackupsDirs = files
63
+ .map((fileObj) => parseInt(fileObj.name))
64
+ .sort((a, b) => a - b)
65
+ .reverse();
68
66
 
69
- default:
70
- // if (currentBackupsDirs[0] && currentDate - currentBackupsDirs[0] < 1000 * 60 * 60 * 24) continue;
71
- break;
72
- }
67
+ switch (backupFrequency) {
68
+ case 'daily':
73
69
 
74
- for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
75
- const removePathRetention = `${backUpPath}/${retentionPath}`;
76
- logger.info('Remove backup folder', removePathRetention);
77
- fs.removeSync(removePathRetention);
78
- }
70
+ default:
71
+ // if (currentBackupsDirs[0] && currentDate - currentBackupsDirs[0] < 1000 * 60 * 60 * 24) continue;
72
+ break;
73
+ }
74
+
75
+ for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
76
+ const removePathRetention = `${backUpPath}/${retentionPath}`;
77
+ logger.info('Remove backup folder', removePathRetention);
78
+ fs.removeSync(removePathRetention);
79
+ }
79
80
 
80
- fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
81
+ fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
81
82
 
82
- shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
83
+ shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
83
84
 
84
- if (wp) {
85
- const repoUrl = `https://${process.env.GITHUB_BACKUP_TOKEN}@github.com/${
86
- process.env.GITHUB_BACKUP_USERNAME
87
- }/${git.split('/').pop()}.git`;
85
+ if (wp) {
86
+ const repoUrl = `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${git
87
+ .split('/')
88
+ .pop()}.git`;
88
89
 
89
- shellExec(
90
- `cd ${directory}` +
91
- ` && git pull ${repoUrl}` +
92
- ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
93
- ` && git push ${repoUrl}`,
94
- );
90
+ shellExec(
91
+ `cd ${directory}` +
92
+ ` && git pull ${repoUrl}` +
93
+ ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
94
+ ` && git push ${repoUrl}`,
95
+ {
96
+ disableLog: true,
97
+ },
98
+ );
99
+ }
95
100
  }
96
- }
101
+ }
97
102
  }
98
- }
99
- shellExec(
100
- `cd ./engine-private/cron-backups` +
101
- ` && git pull ${BackUpManagement.repoUrl}` +
102
- ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
103
- ` && git push ${BackUpManagement.repoUrl}`,
104
- );
103
+ shellExec(
104
+ `cd ./engine-private/cron-backups` +
105
+ ` && git pull ${BackUpManagement.repoUrl}` +
106
+ ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
107
+ ` && git push ${BackUpManagement.repoUrl}`,
108
+ {
109
+ disableLog: true,
110
+ },
111
+ );
112
+ };
113
+ await Callback();
114
+ BackUpManagement.Callback = Callback;
115
+ return Callback;
105
116
  },
117
+ Callback: async function (params) {},
106
118
  };
107
119
 
108
120
  export { BackUpManagement };
@@ -71,6 +71,12 @@ const clientLiveBuild = async () => {
71
71
  } else if (srcPath.split('src')[1].startsWith(`\\client\\sw`)) {
72
72
  const publicBuildPath = `./public/${baseHost}/sw.js`;
73
73
  liveClientBuildPaths.push({ srcBuildPath, publicBuildPath });
74
+ } else if (
75
+ srcPath.split('src')[1].startsWith(`\\client\\offline`) &&
76
+ srcPath.split('src')[1].startsWith(`index.js`)
77
+ ) {
78
+ const publicBuildPath = `./public/${baseHost}/offline.js`;
79
+ liveClientBuildPaths.push({ srcBuildPath, publicBuildPath });
74
80
  } else if (srcPath.split('src')[1].startsWith(`\\client`) && srcPath.slice(-9) === '.index.js') {
75
81
  for (const view of views) {
76
82
  const publicBuildPath = `./public/${baseHost}${view.path === '/' ? '' : view.path}/${clientId}.index.js`;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  import fs from 'fs-extra';
4
- import { srcFormatted, componentFormatted, viewFormatted } from './client-formatted.js';
4
+ import { srcFormatted, componentFormatted, viewFormatted, ssrFactory } from './client-formatted.js';
5
5
  import { loggerFactory } from './logger.js';
6
6
  import { cap, newInstance, orderArrayFromAttrInt, titleFormatted } from '../client/components/core/CommonJs.js';
7
7
  import UglifyJS from 'uglify-js';
@@ -52,7 +52,7 @@ const fullBuild = async ({
52
52
  if (!fs.existsSync(defaultBaseIconPath))
53
53
  await buildTextImg(metadata.title, { debugFilename: defaultBaseIconPath });
54
54
 
55
- if (path === '/' && !fs.existsSync(`./src/client/public/${publicClientId}/site.webmanifest`))
55
+ if (!fs.existsSync(`./src/client/public/${publicClientId}/site.webmanifest`))
56
56
  await buildIcons({ publicClientId, metadata });
57
57
  }
58
58
  fs.copySync(
@@ -112,6 +112,16 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
112
112
  const enableLiveRebuild =
113
113
  options && options.liveClientBuildPaths && options.liveClientBuildPaths.length > 0 ? true : false;
114
114
 
115
+ // common ssr components
116
+ let jsSsrCommonComponents = '';
117
+ {
118
+ const files = await fs.readdir(`./src/client/ssr/common`);
119
+ for (const relativePath of files)
120
+ jsSsrCommonComponents += await srcFormatted(
121
+ fs.readFileSync(`./src/client/ssr/common/${relativePath}`, 'utf8').split('export')[0],
122
+ );
123
+ }
124
+
115
125
  let currentPort = parseInt(process.env.PORT) + 1;
116
126
  for (const host of Object.keys(confServer)) {
117
127
  const paths = orderArrayFromAttrInt(Object.keys(confServer[host]), 'length', 'asc');
@@ -178,7 +188,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
178
188
  iconsBuild,
179
189
  metadata,
180
190
  });
181
- if (apis)
191
+ if (apis && false)
182
192
  for (const apiBuildScript of apis) {
183
193
  const scriptPath = `src/api/${apiBuildScript}/${apiBuildScript}.build.js`;
184
194
  if (fs.existsSync(`./${scriptPath}`)) {
@@ -238,8 +248,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
238
248
  'const getBaseHost = () => location.host;',
239
249
  `const getBaseHost = () => '${apiBaseHost}';`,
240
250
  );
241
- if (apiBaseProxyPath)
251
+ if (apiBaseProxyPath) {
242
252
  jsSrc = jsSrc.replace('${getProxyPath()}api/', `${apiBaseProxyPath}${process.env.BASE_API}/`);
253
+ jsSrc = jsSrc.replace(
254
+ "const getWsBasePath = () => (getProxyPath() !== '/' ? `${getProxyPath()}socket.io/` : undefined);",
255
+ `const getWsBasePath = () => '${apiBaseProxyPath}socket.io/';`,
256
+ );
257
+ }
243
258
  }
244
259
  fs.writeFileSync(
245
260
  jsPublicPath,
@@ -274,26 +289,61 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
274
289
 
275
290
  const buildId = `${client}.index`;
276
291
  const siteMapLinks = [];
292
+ let Render = () => '';
293
+ eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/Render.js`, 'utf8')));
277
294
 
278
295
  if (views) {
279
- // build service worker
280
- if (path === '/') {
281
- const jsSrcPath = fs.existsSync(`./src/client/sw/${publicClientId}.sw.js`)
282
- ? `./src/client/sw/${publicClientId}.sw.js`
283
- : `./src/client/sw/default.sw.js`;
284
-
285
- const jsPublicPath = `${rootClientPath}/sw.js`;
286
-
296
+ const buildJsSrcPage = async (jsSrcPath, jsPublicPath, filter) => {
287
297
  if (!(enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath))) {
288
- const jsSrc = viewFormatted(await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')), dists, path, baseHost);
289
-
298
+ let jsSrc = viewFormatted(await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')), dists, path, baseHost);
299
+ if (jsSrc.split('/*imports*/')[1]) jsSrc = jsSrc.split('/*imports*/')[1];
300
+ if (filter) jsSrc = await filter(jsSrc);
290
301
  fs.writeFileSync(
291
302
  jsPublicPath,
292
303
  minifyBuild || process.env.NODE_ENV === 'production' ? UglifyJS.minify(jsSrc).code : jsSrc,
293
304
  'utf8',
294
305
  );
295
306
  }
307
+ };
308
+
309
+ // service woker
310
+ await buildJsSrcPage(
311
+ fs.existsSync(`./src/client/sw/${publicClientId}.sw.js`)
312
+ ? `./src/client/sw/${publicClientId}.sw.js`
313
+ : `./src/client/sw/default.sw.js`,
314
+ `${rootClientPath}/sw.js`,
315
+ path !== '/'
316
+ ? (jsSrc) => jsSrc.replaceAll(`const PROXY_PATH = '/';`, `const PROXY_PATH = '${path}/';`)
317
+ : undefined,
318
+ );
319
+
320
+ // ssr pages
321
+ for (const page of await fs.readdir('./src/client/ssr/pages')) {
322
+ await buildJsSrcPage(`./src/client/ssr/pages/${page}`, `${rootClientPath}/${page}`);
323
+
324
+ const htmlSrc = Render({
325
+ title: metadata?.title ? metadata.title : cap(client),
326
+ ssrPath: '/',
327
+ ssrHeadComponents: '',
328
+ ssrBodyComponents: '',
329
+ baseSsrLib: jsSsrCommonComponents + fs.readFileSync(`${rootClientPath}/${page}`, 'utf8'),
330
+ });
331
+
332
+ fs.writeFileSync(
333
+ `${rootClientPath}/${page.slice(0, -3)}.html`,
334
+ minifyBuild || process.env.NODE_ENV === 'production'
335
+ ? await minify(htmlSrc, {
336
+ minifyCSS: true,
337
+ minifyJS: true,
338
+ collapseBooleanAttributes: true,
339
+ collapseInlineTagWhitespace: true,
340
+ collapseWhitespace: true,
341
+ })
342
+ : htmlSrc,
343
+ 'utf8',
344
+ );
296
345
  }
346
+
297
347
  if (
298
348
  !(
299
349
  enableLiveRebuild &&
@@ -345,11 +395,9 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
345
395
  confSSR[view.ssr].head.unshift('Production');
346
396
 
347
397
  for (const ssrHeadComponent of confSSR[view.ssr].head) {
348
- let SrrComponent;
349
- eval(
350
- await srcFormatted(
351
- fs.readFileSync(`./src/client/ssr/head-components/${ssrHeadComponent}.js`, 'utf8'),
352
- ),
398
+ const SrrComponent = await ssrFactory(
399
+ `./src/client/ssr/components/head/${ssrHeadComponent}.js`,
400
+ jsSsrCommonComponents,
353
401
  );
354
402
 
355
403
  switch (ssrHeadComponent) {
@@ -359,7 +407,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
359
407
  fs.existsSync(`./src/client/public/${publicClientId}/browserconfig.xml`) &&
360
408
  fs.existsSync(`./src/client/public/${publicClientId}/site.webmanifest`);
361
409
 
362
- if (view.path === '/' && validPwaBuild) {
410
+ if (validPwaBuild) {
363
411
  // build webmanifest
364
412
  const webmanifestJson = JSON.parse(
365
413
  fs.readFileSync(`./src/client/public/${publicClientId}/site.webmanifest`, 'utf8'),
@@ -431,11 +479,9 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
431
479
  }
432
480
 
433
481
  for (const ssrBodyComponent of confSSR[view.ssr].body) {
434
- let SrrComponent;
435
- eval(
436
- await srcFormatted(
437
- fs.readFileSync(`./src/client/ssr/body-components/${ssrBodyComponent}.js`, 'utf8'),
438
- ),
482
+ const SrrComponent = await ssrFactory(
483
+ `./src/client/ssr/components/body/${ssrBodyComponent}.js`,
484
+ jsSsrCommonComponents,
439
485
  );
440
486
  switch (ssrBodyComponent) {
441
487
  case 'UnderpostDefaultSplashScreen':
@@ -448,7 +494,10 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
448
494
  .readFileSync(backgroundImage)
449
495
  .toString('base64')}`,
450
496
  });
497
+ break;
451
498
  } else {
499
+ ssrHeadComponents += SrrComponent({ metadata });
500
+ break;
452
501
  const bufferBackgroundImage = await getBufferPngText({
453
502
  text: ' ',
454
503
  textColor: metadata?.themeColor ? metadata.themeColor : '#ececec',
@@ -459,7 +508,6 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
459
508
  base64BackgroundImage: `data:image/png;base64,${bufferBackgroundImage.toString('base64')}`,
460
509
  });
461
510
  }
462
- break;
463
511
 
464
512
  case 'CyberiaSplashScreenLore': {
465
513
  ssrBodyComponents += SrrComponent({
@@ -467,48 +515,6 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
467
515
  host,
468
516
  path,
469
517
  ttiLoadTimeLimit,
470
- storage: {
471
- // 'space-background': fs.readFileSync('./src/client/public/cyberia/space-background', 'utf8'),
472
- lore0: `data:image/jpeg;base64,${fs
473
- .readFileSync('./src/client/public/cyberia/assets/lore/lore0.jpeg')
474
- .toString('base64')}`,
475
- lore1: `data:image/jpeg;base64,${fs
476
- .readFileSync('./src/client/public/cyberia/assets/lore/lore1.jpeg')
477
- .toString('base64')}`,
478
- lore2: `data:image/jpeg;base64,${fs
479
- .readFileSync('./src/client/public/cyberia/assets/lore/lore2.jpeg')
480
- .toString('base64')}`,
481
- lore3: `data:image/jpeg;base64,${fs
482
- .readFileSync('./src/client/public/cyberia/assets/lore/lore3.jpeg')
483
- .toString('base64')}`,
484
- lore4: `data:image/jpeg;base64,${fs
485
- .readFileSync('./src/client/public/cyberia/assets/lore/lore4.jpeg')
486
- .toString('base64')}`,
487
- lore5: `data:image/jpeg;base64,${fs
488
- .readFileSync('./src/client/public/cyberia/assets/lore/lore5.jpeg')
489
- .toString('base64')}`,
490
- lore6: `data:image/jpeg;base64,${fs
491
- .readFileSync('./src/client/public/cyberia/assets/lore/lore6.jpeg')
492
- .toString('base64')}`,
493
- lore7: `data:image/jpeg;base64,${fs
494
- .readFileSync('./src/client/public/cyberia/assets/lore/lore7.jpeg')
495
- .toString('base64')}`,
496
- lore8: `data:image/jpeg;base64,${fs
497
- .readFileSync('./src/client/public/cyberia/assets/lore/lore8.jpeg')
498
- .toString('base64')}`,
499
- ['arrow-left']: `data:image/png;base64,${fs
500
- .readFileSync('./src/client/public/cyberia/assets/ui-icons/arrow-left.png')
501
- .toString('base64')}`,
502
- ['arrow-right']: `data:image/png;base64,${fs
503
- .readFileSync('./src/client/public/cyberia/assets/ui-icons/arrow-right.png')
504
- .toString('base64')}`,
505
- ['fullscreen']: `data:image/png;base64,${fs
506
- .readFileSync('./src/client/public/cyberia/assets/ui-icons/fullscreen.png')
507
- .toString('base64')}`,
508
- ['cyberia-logo']: `data:image/png;base64,${fs
509
- .readFileSync('./src/client/public/cyberia/assets/util/cyberia-retro-banner.png')
510
- .toString('base64')}`,
511
- },
512
518
  });
513
519
  break;
514
520
  }
@@ -519,16 +525,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
519
525
  }
520
526
  }
521
527
  }
522
-
523
- let Render = () => '';
524
- eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/Render.js`, 'utf8')));
525
-
526
528
  const htmlSrc = Render({
527
529
  title,
528
530
  buildId,
529
531
  ssrPath,
530
532
  ssrHeadComponents,
531
533
  ssrBodyComponents,
534
+ baseSsrLib: jsSsrCommonComponents,
532
535
  });
533
536
 
534
537
  /** @type {import('sitemap').SitemapItem} */
@@ -616,7 +619,7 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
616
619
  fs.copySync(`./coverage`, coverageBuildPath);
617
620
 
618
621
  // uml
619
- shellExec(`node bin/deploy uml ${host} ${path}`);
622
+ // shellExec(`node bin/deploy uml ${host} ${path}`);
620
623
 
621
624
  // https://swagger-autogen.github.io/docs/
622
625
 
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ import fs from 'fs-extra';
4
+
3
5
  const srcFormatted = (src) =>
4
6
  src
5
7
  .replaceAll(' html`', '`')
@@ -45,4 +47,12 @@ const viewFormatted = (src, dists, proxyPath, baseHost = '') => {
45
47
  return src.replaceAll(`from './`, componentFromFormatted).replaceAll(`from '../`, componentFromFormatted);
46
48
  };
47
49
 
48
- export { srcFormatted, JSONweb, componentFormatted, viewFormatted };
50
+ const ssrFactory = async (componentPath = '', jsSsrCommonComponents) => {
51
+ let SrrComponent = () => {};
52
+ let render = await srcFormatted(fs.readFileSync(componentPath, 'utf8'));
53
+ if (render.split('/*imports*/')[1]) render = render.split('/*imports*/')[1];
54
+ eval(jsSsrCommonComponents + render);
55
+ return SrrComponent;
56
+ };
57
+
58
+ export { srcFormatted, JSONweb, componentFormatted, viewFormatted, ssrFactory };
@@ -140,7 +140,7 @@ const buildIcons = async ({
140
140
  for (const file of response.files)
141
141
  fs.writeFileSync(`./src/client/public/${publicClientId}/${file.name}`, file.contents, 'utf8');
142
142
 
143
- const ssrPath = `./src/client/ssr/head-components/Pwa${getCapVariableName(publicClientId)}.js`;
143
+ const ssrPath = `./src/client/ssr/components/head/Pwa${getCapVariableName(publicClientId)}.js`;
144
144
  if (!fs.existsSync(ssrPath))
145
145
  fs.writeFileSync(ssrPath, 'SrrComponent = () => html`' + response.html.join(`\n`) + '`;', 'utf8');
146
146
  } catch (error) {