underpost 2.7.6 → 2.7.8

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 (47) hide show
  1. package/.github/workflows/ghpkg.yml +75 -0
  2. package/.github/workflows/publish.yml +33 -1
  3. package/.github/workflows/pwa-microservices-template.test.yml +30 -0
  4. package/CHANGELOG.md +16 -32
  5. package/bin/deploy.js +15 -8
  6. package/bin/index.js +1 -1
  7. package/docker-compose.yml +1 -1
  8. package/package.json +1 -1
  9. package/src/client/components/core/Css.js +5 -223
  10. package/src/client/components/core/Docs.js +1 -1
  11. package/src/client/components/core/LoadingAnimation.js +6 -7
  12. package/src/client/components/core/Translate.js +11 -2
  13. package/src/client/components/core/VanillaJs.js +3 -0
  14. package/src/client/components/core/Worker.js +14 -4
  15. package/src/client/services/default/default.management.js +118 -120
  16. package/src/client/ssr/Render.js +224 -3
  17. package/src/client/ssr/common/Alert.js +75 -0
  18. package/src/client/ssr/common/SsrCore.js +91 -0
  19. package/src/client/ssr/common/Translate.js +26 -0
  20. package/src/client/ssr/common/Worker.js +28 -0
  21. package/src/client/ssr/{body-components → components/body}/CacheControl.js +1 -1
  22. package/src/client/ssr/{body-components → components/body}/DefaultSplashScreen.js +15 -4
  23. package/src/client/ssr/offline/default.index.js +31 -0
  24. package/src/client/ssr/pages/404.js +12 -0
  25. package/src/client/ssr/pages/500.js +12 -0
  26. package/src/client/sw/default.sw.js +11 -9
  27. package/src/cron.js +7 -2
  28. package/src/db/mongo/MongooseDB.js +0 -12
  29. package/src/mailer/EmailRender.js +1 -1
  30. package/src/server/backup.js +29 -22
  31. package/src/server/client-build-live.js +28 -2
  32. package/src/server/client-build.js +146 -24
  33. package/src/server/client-formatted.js +11 -1
  34. package/src/server/client-icons.js +1 -1
  35. package/src/server/conf.js +11 -17
  36. package/src/server/cron.js +35 -0
  37. package/src/server/dns.js +3 -12
  38. package/src/server/runtime.js +24 -7
  39. package/.github/workflows/test.yml +0 -80
  40. package/src/client/ssr/head-components/Microdata.js +0 -11
  41. package/src/client/ssr/head-components/Production.js +0 -1
  42. package/src/client/ssr/head-components/Seo.js +0 -14
  43. /package/src/client/ssr/{email-components → components/email}/DefaultRecoverEmail.js +0 -0
  44. /package/src/client/ssr/{email-components → components/email}/DefaultVerifyEmail.js +0 -0
  45. /package/src/client/ssr/{head-components → components/head}/Css.js +0 -0
  46. /package/src/client/ssr/{head-components → components/head}/DefaultScripts.js +0 -0
  47. /package/src/client/ssr/{head-components → components/head}/PwaDefault.js +0 -0
@@ -0,0 +1,91 @@
1
+ const s = (el) => document.querySelector(el);
2
+
3
+ const append = (el, html) => s(el).insertAdjacentHTML('beforeend', html);
4
+
5
+ const htmls = (el, html) => (s(el).innerHTML = html);
6
+
7
+ const s4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
8
+
9
+ const range = (start, end) => {
10
+ return end < start
11
+ ? range(end, start).reverse()
12
+ : Array.apply(0, Array(end - start + 1)).map((element, index) => index + start);
13
+ };
14
+
15
+ const timer = (ms) => new Promise((res) => setTimeout(res, ms));
16
+
17
+ const newInstance = (obj) => {
18
+ // structuredClone() 2022 ES6 feature
19
+ try {
20
+ return JSON.parse(JSON.stringify(obj));
21
+ } catch (error) {
22
+ return { error: error.message };
23
+ }
24
+ };
25
+
26
+ const fullScreenIn = () => {
27
+ const elem = document.documentElement;
28
+ if (elem.requestFullscreen) {
29
+ elem.requestFullscreen();
30
+ } else if (elem.mozRequestFullScreen) {
31
+ /* Firefox */
32
+ elem.mozRequestFullScreen();
33
+ } else if (elem.webkitRequestFullscreen) {
34
+ /* Chrome, Safari & Opera */
35
+ elem.webkitRequestFullscreen();
36
+ } else if (elem.msRequestFullscreen) {
37
+ /* IE/Edge */
38
+ elem = window.top.document.body; //To break out of frame in IE
39
+ elem.msRequestFullscreen();
40
+ }
41
+ };
42
+
43
+ const borderChar = (px, color, selectors) => {
44
+ if (selectors) {
45
+ return selectors
46
+ .map(
47
+ (selector) => html`
48
+ <style>
49
+ ${selector} {
50
+ text-shadow: ${px}px -${px}px ${px}px ${color}, -${px}px ${px}px ${px}px ${color},
51
+ -${px}px -${px}px ${px}px ${color}, ${px}px ${px}px ${px}px ${color};
52
+ }
53
+ </style>
54
+ `,
55
+ )
56
+ .join('');
57
+ }
58
+ return html`
59
+ text-shadow: ${px}px -${px}px ${px}px ${color}, -${px}px ${px}px ${px}px ${color}, -${px}px -${px}px ${px}px
60
+ ${color}, ${px}px ${px}px ${px}px ${color};
61
+ `;
62
+ };
63
+ const getLang = () =>
64
+ localStorage.getItem('lang') ? localStorage.getItem('lang') : navigator.language || navigator.userLanguage;
65
+
66
+ const loggerFactory = (meta) => {
67
+ meta = meta.url.split('/').pop();
68
+ const types = ['error', 'warn', 'info', 'debug'];
69
+ const logger = {
70
+ log: function (type, args) {
71
+ if (location.hostname !== 'localhost' && console.log() !== null) {
72
+ console.log = () => null;
73
+ console.error = () => null;
74
+ console.info = () => null;
75
+ console.warn = () => null;
76
+ }
77
+ return location.hostname === 'localhost'
78
+ ? console[type](`[${meta}] ${new Date().toISOString()} ${type}:`, ...args)
79
+ : null;
80
+ },
81
+ };
82
+ types.map(
83
+ (type) =>
84
+ (logger[type] = function (...args) {
85
+ return this.log(type, args);
86
+ }),
87
+ );
88
+ return logger;
89
+ };
90
+
91
+ export { getLang, s, append, s4, range, timer, htmls, newInstance, fullScreenIn, borderChar, loggerFactory };
@@ -0,0 +1,26 @@
1
+ const TranslateCore = {
2
+ ['server-maintenance']: {
3
+ en: "The server is under maintenance <br> we'll be back soon.",
4
+ es: 'El servidor está en mantenimiento <br> volveremos pronto.',
5
+ },
6
+ ['no-internet-connection']: {
7
+ en: 'No internet connection <br> verify your network',
8
+ es: 'Sin conexión a internet <br> verifica tu red',
9
+ },
10
+ ['page-not-found']: {
11
+ en: 'Page not found',
12
+ es: 'Página no encontrada',
13
+ },
14
+ ['page-broken']: {
15
+ es: 'Algo salio mal',
16
+ en: 'Something went wrong',
17
+ },
18
+ ['back']: {
19
+ en: 'Back to <br> homepage',
20
+ es: 'Volver a <br> la pagina principal',
21
+ },
22
+ };
23
+
24
+ const Translate = (key) => TranslateCore[key][getLang().match('es') ? 'es' : 'en'];
25
+
26
+ export { Translate };
@@ -0,0 +1,28 @@
1
+ const Worker = {
2
+ instance: async function (options = { render: async () => {} }) {
3
+ window.serviceWorkerReady = true;
4
+ append(
5
+ 'body',
6
+ html`
7
+ <style>
8
+ body {
9
+ background-color: #dcdcdc;
10
+ color: #303030;
11
+ font-family: arial;
12
+ font-size: 16px;
13
+ }
14
+ .page-render {
15
+ min-height: 100vh;
16
+ }
17
+ a {
18
+ color: #000000;
19
+ }
20
+ </style>
21
+ <div class="in page-render"></div>
22
+ `,
23
+ );
24
+ await options.render();
25
+ },
26
+ };
27
+
28
+ export { Worker };
@@ -109,6 +109,6 @@ SrrComponent = ({ ttiLoadTimeLimit }) => {
109
109
  const CacheControl = ${CacheControl};
110
110
  CacheControl({ ttiLoadTimeLimit: ${ttiLoadTimeLimit ? ttiLoadTimeLimit : 1000 * 70 * 1} });
111
111
  </script>
112
- <div class="clean-cache-container">v2.7.6</div>
112
+ <div class="clean-cache-container">v2.7.8</div>
113
113
  `;
114
114
  };
@@ -1,8 +1,19 @@
1
- SrrComponent = ({ base64BackgroundImage }) => html`
1
+ SrrComponent = ({ base64BackgroundImage, metadata }) => html`
2
+ ${base64BackgroundImage
3
+ ? html`<style>
4
+ .ssr-background-image {
5
+ background-image: url('${base64BackgroundImage}');
6
+ }
7
+ </style>`
8
+ : metadata?.themeColor
9
+ ? html`<style>
10
+ .ssr-background-image {
11
+ background: ${metadata.themeColor};
12
+ }
13
+ </style>`
14
+ : ''}
15
+
2
16
  <style>
3
- .ssr-background-image {
4
- background-image: url('${base64BackgroundImage}');
5
- }
6
17
  .ssr-top-bar {
7
18
  background: #ffffff;
8
19
  height: 100px;
@@ -0,0 +1,31 @@
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: '/offline.js' });
8
+
9
+ window.onload = () =>
10
+ Worker.instance({
11
+ render: async () => {
12
+ window.ononline = async () => {
13
+ location.href = '/';
14
+ };
15
+ window.onoffline = async () => {
16
+ htmls(`.page-render`, html`${await Alert.noInternet({ Translate })}`);
17
+ };
18
+ try {
19
+ if (navigator.onLine) {
20
+ const maintenance = await fetch(location.origin + '/favicon.ico');
21
+ if (maintenance.status !== 200) {
22
+ htmls(`.page-render`, html`${await Alert.maintenance({ Translate })}`);
23
+ } else window.ononline();
24
+ }
25
+ throw new Error(`no internet connection`);
26
+ } catch (error) {
27
+ logger.error(error);
28
+ window.onoffline();
29
+ }
30
+ },
31
+ });
@@ -0,0 +1,12 @@
1
+ import { e404 } from '../common/Alert.js';
2
+ import { append } from '../common/SsrCore.js';
3
+ import { Translate } from '../common/Translate.js';
4
+ import { Worker } from '../common/Worker.js';
5
+ /*imports*/
6
+
7
+ window.onload = () =>
8
+ Worker.instance({
9
+ render: async () => {
10
+ append('.page-render', await e404({ Translate }));
11
+ },
12
+ });
@@ -0,0 +1,12 @@
1
+ import { e500 } from '../common/Alert.js';
2
+ import { append } from '../common/SsrCore.js';
3
+ import { Translate } from '../common/Translate.js';
4
+ import { Worker } from '../common/Worker.js';
5
+ /*imports*/
6
+
7
+ window.onload = () =>
8
+ Worker.instance({
9
+ render: async () => {
10
+ append('.page-render', await e500({ Translate }));
11
+ },
12
+ });
@@ -179,15 +179,17 @@ self.addEventListener('fetch', (event) => {
179
179
  }
180
180
 
181
181
  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;
182
+ try {
183
+ const cache = await caches.open('/offline.html');
184
+ const cachedResponse = await cache.match('/offline.html');
185
+ return cachedResponse;
186
+ } catch (error) {
187
+ logger.error('Error opening cache for offline page', { error, path });
188
+ const response = new Response(JSON.stringify({ status: 'error', message: 'offline test response' }));
189
+ // response.status = 200;
190
+ response.headers.set('Content-Type', 'application/json');
191
+ return response;
192
+ }
191
193
  }
192
194
  })(),
193
195
  );
package/src/cron.js CHANGED
@@ -9,6 +9,7 @@ import { Dns } from './server/dns.js';
9
9
  import { ProcessController } from './server/process.js';
10
10
  import { Config } from './server/conf.js';
11
11
  import { BackUpManagement } from './server/backup.js';
12
+ import { CronManagement } from './server/cron.js';
12
13
 
13
14
  dotenv.config();
14
15
 
@@ -18,8 +19,12 @@ const logger = loggerFactory(import.meta);
18
19
 
19
20
  await logger.setUpInfo();
20
21
 
21
- await Dns.InitIpDaemon();
22
+ // every minutes
23
+ CronManagement.add('ip', '* * * * *', await Dns.InitIpDaemon());
22
24
 
23
- await BackUpManagement.Init();
25
+ // every day at 1 am
26
+ CronManagement.add('backup', '0 1 * * *', await BackUpManagement.Init());
27
+
28
+ await CronManagement.init();
24
29
 
25
30
  ProcessController.init(logger);
@@ -114,18 +114,6 @@ const MongooseDB = {
114
114
  };
115
115
 
116
116
  checkStatus();
117
- break;
118
- // every 30 minute
119
- cron.schedule(
120
- '0 */30 * * * *',
121
- async () => {
122
- checkStatus();
123
- },
124
- {
125
- scheduled: true,
126
- timezone: process.env.TIME_ZONE || 'America/New_York',
127
- },
128
- );
129
117
  }
130
118
  break;
131
119
  default:
@@ -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;
@@ -2,25 +2,17 @@ import fs from 'fs-extra';
2
2
  import { loggerFactory } from './logger.js';
3
3
  import { shellCd, shellExec } from './process.js';
4
4
  import { getCronBackUpFolder, getDataDeploy } from './conf.js';
5
- import cron from 'node-cron';
5
+ import dotenv from 'dotenv';
6
+
7
+ dotenv.config();
6
8
 
7
9
  const logger = loggerFactory(import.meta);
8
10
 
9
11
  const BackUpManagement = {
12
+ repoUrl: `https://${process.env.GITHUB_BACKUP_TOKEN}@github.com/${process.env.GITHUB_BACKUP_USERNAME}/${process.env.GITHUB_BACKUP_REPO}.git`,
10
13
  Init: async function () {
11
- await BackUpManagement.Callback();
12
-
13
- // Schedule the sending process to run every day at 1 am
14
- cron.schedule(
15
- '0 1 * * *',
16
- async () => {
17
- await BackUpManagement.Callback();
18
- },
19
- {
20
- scheduled: true,
21
- timezone: process.env.TIME_ZONE || 'America/New_York',
22
- },
23
- );
14
+ await this.Callback();
15
+ return this.Callback;
24
16
  },
25
17
  Callback: async function () {
26
18
  const privateCronConfPath = `./engine-private/conf/${process.argv[2]}/conf.cron.json`;
@@ -54,7 +46,7 @@ const BackUpManagement = {
54
46
  for (const host of Object.keys(confServer))
55
47
  for (const path of Object.keys(confServer[host])) {
56
48
  // retention policy
57
- let { db, backupFrequency, maxBackupRetention, singleReplica } = confServer[host][path];
49
+ let { db, backupFrequency, maxBackupRetention, singleReplica, wp, git, directory } = confServer[host][path];
58
50
 
59
51
  if (!db || singleReplica) continue;
60
52
 
@@ -75,26 +67,41 @@ const BackUpManagement = {
75
67
  case 'daily':
76
68
 
77
69
  default:
78
- if (currentBackupsDirs[0] && currentDate - currentBackupsDirs[0] <= 1000 * 60 * 60 * 24) continue;
70
+ // if (currentBackupsDirs[0] && currentDate - currentBackupsDirs[0] < 1000 * 60 * 60 * 24) continue;
79
71
  break;
80
72
  }
81
73
 
82
- for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention + 1)) {
74
+ for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
83
75
  const removePathRetention = `${backUpPath}/${retentionPath}`;
76
+ logger.info('Remove backup folder', removePathRetention);
84
77
  fs.removeSync(removePathRetention);
85
78
  }
86
79
 
87
80
  fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
88
81
 
89
82
  shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
83
+
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`;
88
+
89
+ shellExec(
90
+ `cd ${directory}` +
91
+ ` && git pull ${repoUrl}` +
92
+ ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
93
+ ` && git push ${repoUrl}`,
94
+ );
95
+ }
90
96
  }
91
97
  }
92
98
  }
93
- shellCd(`./engine-private`);
94
- shellExec(`git pull origin master`);
95
- shellExec(`git add . && git commit -m "backup ${new Date().toLocaleDateString()}"`);
96
- shellExec(`git push origin master`);
97
- shellCd(`..`);
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
+ );
98
105
  },
99
106
  };
100
107
 
@@ -20,8 +20,26 @@ const clientLiveBuild = async () => {
20
20
  (fs.existsSync(`./engine-private/conf/${deployId}`) || fs.existsSync(`./engine-private/replica/${deployId}`))
21
21
  ) {
22
22
  loadConf(deployId);
23
- const confClient = JSON.parse(fs.readFileSync(`./conf/conf.client.json`, 'utf8'));
24
- const confServer = JSON.parse(fs.readFileSync(`./conf/conf.server.json`, 'utf8'));
23
+ const confClient = JSON.parse(
24
+ fs.readFileSync(
25
+ fs.existsSync(`./engine-private/replica/${deployId}`)
26
+ ? `./engine-private/replica/${deployId}/conf.client.json`
27
+ : fs.existsSync(`./engine-private/conf/${deployId}/conf.client.json`)
28
+ ? `./engine-private/conf/${deployId}/conf.client.json`
29
+ : `./conf/conf.client.json`,
30
+ 'utf8',
31
+ ),
32
+ );
33
+ const confServer = JSON.parse(
34
+ fs.readFileSync(
35
+ fs.existsSync(`./engine-private/replica/${deployId}`)
36
+ ? `./engine-private/replica/${deployId}/conf.server.json`
37
+ : fs.existsSync(`./engine-private/conf/${deployId}/conf.server.json`)
38
+ ? `./engine-private/conf/${deployId}/conf.server.json`
39
+ : `./conf/conf.server.json`,
40
+ 'utf8',
41
+ ),
42
+ );
25
43
  host = process.argv[3];
26
44
  path = process.argv[4];
27
45
  clientId = confServer[host][path].client;
@@ -41,6 +59,8 @@ const clientLiveBuild = async () => {
41
59
  const updates = JSON.parse(fs.readFileSync(`./tmp/client.build.json`, 'utf8'));
42
60
  const liveClientBuildPaths = [];
43
61
  for (let srcPath of updates) {
62
+ srcPath = srcPath.replaceAll('/', `\\`); // linux case
63
+
44
64
  const srcBuildPath = `./src${srcPath.split('src')[1].replace(/\\/g, '/')}`;
45
65
  if (
46
66
  srcPath.split('src')[1].startsWith(`\\client\\components`) ||
@@ -51,6 +71,12 @@ const clientLiveBuild = async () => {
51
71
  } else if (srcPath.split('src')[1].startsWith(`\\client\\sw`)) {
52
72
  const publicBuildPath = `./public/${baseHost}/sw.js`;
53
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 });
54
80
  } else if (srcPath.split('src')[1].startsWith(`\\client`) && srcPath.slice(-9) === '.index.js') {
55
81
  for (const view of views) {
56
82
  const publicBuildPath = `./public/${baseHost}${view.path === '/' ? '' : view.path}/${clientId}.index.js`;