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
@@ -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';
@@ -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');
@@ -274,18 +284,14 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
274
284
 
275
285
  const buildId = `${client}.index`;
276
286
  const siteMapLinks = [];
287
+ let Render = () => '';
288
+ eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/Render.js`, 'utf8')));
277
289
 
278
290
  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
-
291
+ const buildJsSrcPage = async (jsSrcPath, jsPublicPath) => {
287
292
  if (!(enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath))) {
288
- const jsSrc = viewFormatted(await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')), dists, path, baseHost);
293
+ let jsSrc = viewFormatted(await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')), dists, path, baseHost);
294
+ if (jsSrc.split('/*imports*/')[1]) jsSrc = jsSrc.split('/*imports*/')[1];
289
295
 
290
296
  fs.writeFileSync(
291
297
  jsPublicPath,
@@ -293,7 +299,76 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
293
299
  'utf8',
294
300
  );
295
301
  }
302
+ };
303
+
304
+ if (path === '/') {
305
+ // service woker
306
+ await buildJsSrcPage(
307
+ fs.existsSync(`./src/client/sw/${publicClientId}.sw.js`)
308
+ ? `./src/client/sw/${publicClientId}.sw.js`
309
+ : `./src/client/sw/default.sw.js`,
310
+ `${rootClientPath}/sw.js`,
311
+ );
312
+ }
313
+
314
+ // offline html
315
+ {
316
+ await buildJsSrcPage(
317
+ fs.existsSync(`./src/client/ssr/offline/${publicClientId}.index.js`)
318
+ ? `./src/client/ssr/offline/${publicClientId}.index.js`
319
+ : `./src/client/ssr/offline/default.index.js`,
320
+ `${rootClientPath}/offline.js`,
321
+ );
322
+
323
+ const htmlSrc = Render({
324
+ title: metadata?.title ? metadata.title : cap(client),
325
+ ssrPath: '/',
326
+ ssrHeadComponents: '',
327
+ ssrBodyComponents: '',
328
+ baseSsrLib: jsSsrCommonComponents + fs.readFileSync(`${rootClientPath}/offline.js`, 'utf8'),
329
+ });
330
+
331
+ fs.writeFileSync(
332
+ `${rootClientPath}offline.html`,
333
+ minifyBuild || process.env.NODE_ENV === 'production'
334
+ ? await minify(htmlSrc, {
335
+ minifyCSS: true,
336
+ minifyJS: true,
337
+ collapseBooleanAttributes: true,
338
+ collapseInlineTagWhitespace: true,
339
+ collapseWhitespace: true,
340
+ })
341
+ : htmlSrc,
342
+ 'utf8',
343
+ );
296
344
  }
345
+ // ssr pages
346
+ for (const page of await fs.readdir('./src/client/ssr/pages')) {
347
+ await buildJsSrcPage(`./src/client/ssr/pages/${page}`, `${rootClientPath}/${page}`);
348
+
349
+ const htmlSrc = Render({
350
+ title: metadata?.title ? metadata.title : cap(client),
351
+ ssrPath: '/',
352
+ ssrHeadComponents: '',
353
+ ssrBodyComponents: '',
354
+ baseSsrLib: jsSsrCommonComponents + fs.readFileSync(`${rootClientPath}/${page}`, 'utf8'),
355
+ });
356
+
357
+ fs.writeFileSync(
358
+ `${rootClientPath}${page.slice(0, -3)}.html`,
359
+ minifyBuild || process.env.NODE_ENV === 'production'
360
+ ? await minify(htmlSrc, {
361
+ minifyCSS: true,
362
+ minifyJS: true,
363
+ collapseBooleanAttributes: true,
364
+ collapseInlineTagWhitespace: true,
365
+ collapseWhitespace: true,
366
+ })
367
+ : htmlSrc,
368
+ 'utf8',
369
+ );
370
+ }
371
+
297
372
  if (
298
373
  !(
299
374
  enableLiveRebuild &&
@@ -345,11 +420,9 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
345
420
  confSSR[view.ssr].head.unshift('Production');
346
421
 
347
422
  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
- ),
423
+ const SrrComponent = await ssrFactory(
424
+ `./src/client/ssr/components/head/${ssrHeadComponent}.js`,
425
+ jsSsrCommonComponents,
353
426
  );
354
427
 
355
428
  switch (ssrHeadComponent) {
@@ -431,11 +504,9 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
431
504
  }
432
505
 
433
506
  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
- ),
507
+ const SrrComponent = await ssrFactory(
508
+ `./src/client/ssr/components/body/${ssrBodyComponent}.js`,
509
+ jsSsrCommonComponents,
439
510
  );
440
511
  switch (ssrBodyComponent) {
441
512
  case 'UnderpostDefaultSplashScreen':
@@ -448,7 +519,10 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
448
519
  .readFileSync(backgroundImage)
449
520
  .toString('base64')}`,
450
521
  });
522
+ break;
451
523
  } else {
524
+ ssrHeadComponents += SrrComponent({ metadata });
525
+ break;
452
526
  const bufferBackgroundImage = await getBufferPngText({
453
527
  text: ' ',
454
528
  textColor: metadata?.themeColor ? metadata.themeColor : '#ececec',
@@ -459,7 +533,58 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
459
533
  base64BackgroundImage: `data:image/png;base64,${bufferBackgroundImage.toString('base64')}`,
460
534
  });
461
535
  }
536
+
537
+ case 'CyberiaSplashScreenLore': {
538
+ ssrBodyComponents += SrrComponent({
539
+ ssrPath,
540
+ host,
541
+ path,
542
+ ttiLoadTimeLimit,
543
+ storage: {
544
+ // 'space-background': fs.readFileSync('./src/client/public/cyberia/space-background', 'utf8'),
545
+ lore0: `data:image/jpeg;base64,${fs
546
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore0.jpeg')
547
+ .toString('base64')}`,
548
+ lore1: `data:image/jpeg;base64,${fs
549
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore1.jpeg')
550
+ .toString('base64')}`,
551
+ lore2: `data:image/jpeg;base64,${fs
552
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore2.jpeg')
553
+ .toString('base64')}`,
554
+ lore3: `data:image/jpeg;base64,${fs
555
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore3.jpeg')
556
+ .toString('base64')}`,
557
+ lore4: `data:image/jpeg;base64,${fs
558
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore4.jpeg')
559
+ .toString('base64')}`,
560
+ lore5: `data:image/jpeg;base64,${fs
561
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore5.jpeg')
562
+ .toString('base64')}`,
563
+ lore6: `data:image/jpeg;base64,${fs
564
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore6.jpeg')
565
+ .toString('base64')}`,
566
+ lore7: `data:image/jpeg;base64,${fs
567
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore7.jpeg')
568
+ .toString('base64')}`,
569
+ lore8: `data:image/jpeg;base64,${fs
570
+ .readFileSync('./src/client/public/cyberia/assets/lore/lore8.jpeg')
571
+ .toString('base64')}`,
572
+ ['arrow-left']: `data:image/png;base64,${fs
573
+ .readFileSync('./src/client/public/cyberia/assets/ui-icons/arrow-left.png')
574
+ .toString('base64')}`,
575
+ ['arrow-right']: `data:image/png;base64,${fs
576
+ .readFileSync('./src/client/public/cyberia/assets/ui-icons/arrow-right.png')
577
+ .toString('base64')}`,
578
+ ['fullscreen']: `data:image/png;base64,${fs
579
+ .readFileSync('./src/client/public/cyberia/assets/ui-icons/fullscreen.png')
580
+ .toString('base64')}`,
581
+ ['cyberia-logo']: `data:image/png;base64,${fs
582
+ .readFileSync('./src/client/public/cyberia/assets/util/cyberia-retro-banner.png')
583
+ .toString('base64')}`,
584
+ },
585
+ });
462
586
  break;
587
+ }
463
588
 
464
589
  default:
465
590
  ssrBodyComponents += SrrComponent({ ssrPath, host, path, ttiLoadTimeLimit });
@@ -467,16 +592,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
467
592
  }
468
593
  }
469
594
  }
470
-
471
- let Render = () => '';
472
- eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/Render.js`, 'utf8')));
473
-
474
595
  const htmlSrc = Render({
475
596
  title,
476
597
  buildId,
477
598
  ssrPath,
478
599
  ssrHeadComponents,
479
600
  ssrBodyComponents,
601
+ baseSsrLib: jsSsrCommonComponents,
480
602
  });
481
603
 
482
604
  /** @type {import('sitemap').SitemapItem} */
@@ -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) {
@@ -240,8 +240,8 @@ const buildClientSrc = async (
240
240
  }
241
241
 
242
242
  fs.writeFileSync(
243
- `./src/client/ssr/head-components/${toClientVariableName}Scripts.js`,
244
- formattedSrc(fs.readFileSync(`./src/client/ssr/head-components/${fromClientVariableName}Scripts.js`, 'utf8')),
243
+ `./src/client/ssr/components/head/${toClientVariableName}Scripts.js`,
244
+ formattedSrc(fs.readFileSync(`./src/client/ssr/components/head/${fromClientVariableName}Scripts.js`, 'utf8')),
245
245
  'utf8',
246
246
  );
247
247
 
@@ -560,7 +560,7 @@ const validateTemplatePath = (absolutePath = '') => {
560
560
  const confServer = DefaultConf.server[host][path];
561
561
  const confClient = DefaultConf.client[client];
562
562
  const confSsr = DefaultConf.ssr[ssr];
563
- const clients = Object.keys(confClient).concat(['core', 'test']);
563
+ const clients = Object.keys(confClient).concat(['core', 'test', 'default']);
564
564
 
565
565
  if (absolutePath.match('src/api') && !confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))) {
566
566
  return false;
@@ -584,14 +584,14 @@ const validateTemplatePath = (absolutePath = '') => {
584
584
  return false;
585
585
  }
586
586
  if (
587
- absolutePath.match('src/client/ssr/body-components') &&
588
- !confSsr.body.find((p) => absolutePath.match(`src/client/ssr/body-components/${p}.js`))
587
+ absolutePath.match('src/client/ssr/components/body') &&
588
+ !confSsr.body.find((p) => absolutePath.match(`src/client/ssr/components/body/${p}.js`))
589
589
  ) {
590
590
  return false;
591
591
  }
592
592
  if (
593
- absolutePath.match('src/client/ssr/head-components') &&
594
- !confSsr.head.find((p) => absolutePath.match(`src/client/ssr/head-components/${p}.js`))
593
+ absolutePath.match('src/client/ssr/components/head') &&
594
+ !confSsr.head.find((p) => absolutePath.match(`src/client/ssr/components/head/${p}.js`))
595
595
  ) {
596
596
  return false;
597
597
  }
@@ -599,6 +599,7 @@ const validateTemplatePath = (absolutePath = '') => {
599
599
  if (
600
600
  absolutePath.match('/client') &&
601
601
  absolutePath.match('.index.js') &&
602
+ !absolutePath.match('/offline') &&
602
603
  !clients.find((p) => absolutePath.match(`src/client/${capFirst(p)}.index.js`))
603
604
  ) {
604
605
  return false;
@@ -619,6 +620,8 @@ const deployTest = async (dataDeploy) => {
619
620
  let fail = false;
620
621
  for (const host of Object.keys(serverConf))
621
622
  for (const path of Object.keys(serverConf[host])) {
623
+ const { singleReplica } = serverConf[host][path];
624
+ if (singleReplica) continue;
622
625
  const urlTest = `https://${host}${path}`;
623
626
  try {
624
627
  const result = await axios.get(urlTest);
@@ -693,6 +696,7 @@ const execDeploy = async (options = { deployId: 'default' }) => {
693
696
  const deployRun = async (dataDeploy, reset) => {
694
697
  if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
695
698
  if (reset) fs.writeFileSync(`./tmp/runtime-router.json`, '{}', 'utf8');
699
+ await fixDependencies();
696
700
  for (const deploy of dataDeploy) await execDeploy(deploy);
697
701
  const { failed } = await deployTest(dataDeploy);
698
702
  if (failed.length > 0) {
@@ -702,15 +706,6 @@ const deployRun = async (dataDeploy, reset) => {
702
706
  } else logger.info(`Deploy process successfully`);
703
707
  };
704
708
 
705
- const updateSrc = () => {
706
- const silent = true;
707
- shellExec(`git pull origin master`, { silent });
708
- shellCd(`engine-private`);
709
- shellExec(`git pull origin master`, { silent });
710
- shellCd(`..`);
711
- // shellExec(`npm install && npm install --only=dev`);
712
- };
713
-
714
709
  const restoreMacroDb = async (deployGroupId = '') => {
715
710
  const dataDeploy = await getDataDeploy({ deployGroupId, buildSingleReplica: false });
716
711
  for (const deployGroup of dataDeploy) {
@@ -881,7 +876,6 @@ export {
881
876
  getDeployGroupId,
882
877
  execDeploy,
883
878
  deployRun,
884
- updateSrc,
885
879
  getCronBackUpFolder,
886
880
  getRestoreCronCmd,
887
881
  mergeBackUp,
@@ -0,0 +1,35 @@
1
+ import cron from 'node-cron';
2
+ import { loggerFactory } from './logger.js';
3
+
4
+ const logger = loggerFactory(import.meta);
5
+
6
+ const CronManagement = {
7
+ data: {},
8
+ init: function () {
9
+ // verify tokens
10
+ // https://github.com/settings/tokens
11
+ for (const cronKey of Object.keys(this.data)) {
12
+ if (this.data[cronKey].valid) {
13
+ this.data[cronKey].task.start();
14
+ logger.info(`Cron task "${this.data[cronKey].name}" started`);
15
+ } else {
16
+ logger.error(
17
+ `Invalid cron expression "${this.data[cronKey].expression}" for task "${this.data[cronKey].name}"`,
18
+ );
19
+ }
20
+ }
21
+ },
22
+ add: function (name = 'task', expression = '* * * * *', callback = async () => null) {
23
+ const args = { name, expression, valid: cron.validate(expression) };
24
+ this.data[name] = {
25
+ ...args,
26
+ task: cron.schedule(expression, callback, {
27
+ scheduled: false,
28
+ timezone: process.env.TIME_ZONE || 'America/New_York',
29
+ name,
30
+ }),
31
+ };
32
+ },
33
+ };
34
+
35
+ export { CronManagement };
package/src/server/dns.js CHANGED
@@ -14,6 +14,7 @@ const logger = loggerFactory(import.meta);
14
14
  const Dns = {
15
15
  ip: null,
16
16
  ipDaemon: null,
17
+ callback: () => null,
17
18
  InitIpDaemon: async function () {
18
19
  // WAN | NAT-VPS | LAN
19
20
  // enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
@@ -58,18 +59,8 @@ const Dns = {
58
59
  }
59
60
  }
60
61
  };
61
- await callback();
62
- // every minute
63
- cron.schedule(
64
- '* * * * *',
65
- async () => {
66
- await callback();
67
- },
68
- {
69
- scheduled: true,
70
- timezone: process.env.TIME_ZONE || 'America/New_York',
71
- },
72
- );
62
+ this.callback = callback;
63
+ return callback;
73
64
  },
74
65
  services: {
75
66
  updateIp: {
@@ -1,4 +1,4 @@
1
- import fs from 'fs';
1
+ import fs from 'fs-extra';
2
2
  import express from 'express';
3
3
  import cors from 'cors';
4
4
  import dotenv from 'dotenv';
@@ -114,10 +114,10 @@ export PATH=$PATH:/opt/lampp/bin`,
114
114
  Listen ${port}
115
115
 
116
116
  <VirtualHost *:${port}>
117
- DocumentRoot "${directory ? directory.replace(path, '/') : `${getRootDirectory()}${rootHostPath}`}"
117
+ DocumentRoot "${directory ? directory : `${getRootDirectory()}${rootHostPath}`}"
118
118
  ServerName ${host}:${port}
119
119
 
120
- <Directory "${directory ? directory.replace(path, '/') : `${getRootDirectory()}${rootHostPath}`}">
120
+ <Directory "${directory ? directory : `${getRootDirectory()}${rootHostPath}`}">
121
121
  Options Indexes FollowSymLinks MultiViews
122
122
  AllowOverride All
123
123
  Require all granted
@@ -134,6 +134,13 @@ export PATH=$PATH:/opt/lampp/bin`,
134
134
  : ''
135
135
  }
136
136
 
137
+ ErrorDocument 400 ${path === '/' ? '' : path}/400.html
138
+ ErrorDocument 404 ${path === '/' ? '' : path}/400.html
139
+ ErrorDocument 500 ${path === '/' ? '' : path}/500.html
140
+ ErrorDocument 502 ${path === '/' ? '' : path}/500.html
141
+ ErrorDocument 503 ${path === '/' ? '' : path}/500.html
142
+ ErrorDocument 504 ${path === '/' ? '' : path}/500.html
143
+
137
144
  </VirtualHost>
138
145
 
139
146
  `);
@@ -196,10 +203,10 @@ export PATH=$PATH:/opt/lampp/bin`,
196
203
  Listen ${port}
197
204
 
198
205
  <VirtualHost *:${port}>
199
- DocumentRoot "${directory ? directory.replace(path, '/') : `${getRootDirectory()}${rootHostPath}`}"
206
+ DocumentRoot "${directory ? directory : `${getRootDirectory()}${rootHostPath}`}"
200
207
  ServerName ${host}:${port}
201
208
 
202
- <Directory "${directory ? directory.replace(path, '/') : `${getRootDirectory()}${rootHostPath}`}">
209
+ <Directory "${directory ? directory : `${getRootDirectory()}${rootHostPath}`}">
203
210
  Options Indexes FollowSymLinks MultiViews
204
211
  AllowOverride All
205
212
  Require all granted
@@ -216,6 +223,13 @@ export PATH=$PATH:/opt/lampp/bin`,
216
223
  : ''
217
224
  }
218
225
 
226
+ ErrorDocument 400 ${path === '/' ? '' : path}/400.html
227
+ ErrorDocument 404 ${path === '/' ? '' : path}/400.html
228
+ ErrorDocument 500 ${path === '/' ? '' : path}/500.html
229
+ ErrorDocument 502 ${path === '/' ? '' : path}/500.html
230
+ ErrorDocument 503 ${path === '/' ? '' : path}/500.html
231
+ ErrorDocument 504 ${path === '/' ? '' : path}/500.html
232
+
219
233
  </VirtualHost>
220
234
 
221
235
  `);
@@ -369,13 +383,16 @@ export PATH=$PATH:/opt/lampp/bin`,
369
383
  app.use(`${apiPath}/${api}`, router);
370
384
  })();
371
385
  }
372
-
373
386
  app.use(function (req, res, next) {
374
- res.status(404).send('Sorry cant find that!');
387
+ const path404 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/404.html`;
388
+ if (fs.existsSync(path404)) return res.status(404).sendFile(path404);
389
+ else res.status(404).send('Sorry cant find that!');
375
390
  });
376
391
 
377
392
  app.use(function (err, req, res, next) {
378
393
  logger.error(err, err.stack);
394
+ const path500 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/500.html`;
395
+ if (fs.existsSync(path500)) return res.status(500).sendFile(path500);
379
396
  res.status(500).send('Something broke!');
380
397
  });
381
398
 
@@ -1,80 +0,0 @@
1
- name: Test
2
- on:
3
- push:
4
- branches: ['master']
5
- pull_request:
6
- branches: ['master']
7
- jobs:
8
- test:
9
- name: Node ${{ matrix.node }} on ${{ matrix.os }}
10
- runs-on: ${{ matrix.os }}
11
- strategy:
12
- matrix:
13
- node-version: [21.x]
14
- os: [ubuntu-latest]
15
- # os: [ubuntu-latest, windows-latest]
16
-
17
- steps:
18
- - name: Clone repository
19
- uses: actions/checkout@v3
20
-
21
- - name: Set Node.js version
22
- uses: actions/setup-node@v3
23
- with:
24
- node-version: ${{ matrix.node }}
25
-
26
- - name: Get npm root
27
- run: sudo npm root -g
28
-
29
- - name: Install underpost cli
30
- run: sudo npm install -g underpost
31
-
32
- - name: Run test
33
- run: sudo underpost test
34
-
35
- # for travis
36
- # - name: Run coveralls
37
- # run: npm run coveralls # nyc npm run test --reporter=text-lcov | coveralls -v
38
-
39
- # - name: Test token
40
- # run: echo "${{ secrets.COVERALLS_REPO_TOKEN }}"
41
-
42
- # - name: Coveralls
43
- # uses: coverallsapp/github-action@master
44
- # with:
45
- # github-token: ${{ secrets.GITHUB_TOKEN }}
46
- # flag-name: ${{matrix.os}}-node-${{ matrix.node }}
47
- # parallel: true
48
-
49
- # - name: Coveralls
50
- # uses: coverallsapp/github-action@master
51
- # with:
52
- # github-token: ${{ secrets.GITHUB_TOKEN }}
53
- # path-to-lcov: '/usr/local/lib/node_modules/underpost/coverage/lcov.info'
54
- # env:
55
- # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
56
- # COVERALLS_GIT_BRANCH: "${{ github.ref }}"
57
-
58
- # - name: Coveralls
59
- # run: node ./node_modules/coveralls-next/bin/coveralls.js # cat ./coverage/lcov.info |
60
- # env:
61
- # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
62
- # COVERALLS_SERVICE_NAME: CI-pipeline
63
- # COVERALLS_SERVICE_JOB_ID: ${{github.run_id}}
64
- # COVERALLS_SERVICE_JOB_NUMBER: ${{github.run_number}}
65
- # COVERALLS_FLAG_NAME: ${{matrix.os}}-node-${{ matrix.node }}
66
- # COVERALLS_PARALLEL: true
67
- # NODE_COVERALLS_DEBUG: 1
68
- # finish:
69
- # needs: test
70
- # runs-on: ubuntu-latest
71
- # steps:
72
- # - name: Clone repository
73
- # uses: actions/checkout@v2
74
-
75
- # - name: Coveralls Finished
76
- # run: |
77
- # curl -kv -d 'payload[build_num]=${{github.run_id}}&payload[status]=done' https://coveralls.io/webhook?repo_token=${COVERALLS_REPO_TOKEN}
78
- # env:
79
- # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
80
- # COVERALLS_GIT_BRANCH: '${{ github.ref }}'
@@ -1,11 +0,0 @@
1
- SrrComponent = ({ microdata }) => html`
2
- ${microdata
3
- .map(
4
- (jsonld) => html`
5
- <script type="application/ld+json">
6
- ${JSON.stringify(jsonld, null, 4)}
7
- </script>
8
- `,
9
- )
10
- .join(` `)}
11
- `;
@@ -1 +0,0 @@
1
- SrrComponent = () => html``;
@@ -1,14 +0,0 @@
1
- SrrComponent = ({ title, author, keywords, description, themeColor, ssrPath, canonicalURL, thumbnail }) => html`
2
- <link rel="canonical" href="${canonicalURL}" />
3
-
4
- <meta name="author" content="${author}" />
5
- <meta name="keywords" content="${keywords.join(',')}" />
6
- <meta name="description" content="${description}" />
7
- <meta name="theme-color" content="${themeColor}" />
8
-
9
- <meta property="og:title" content="${title}" />
10
- <meta property="og:description" content="${description}" />
11
- <meta property="og:image" content="${thumbnail}" />
12
- <meta property="og:url" content="${canonicalURL}" />
13
- <meta name="twitter:card" content="summary_large_image" />
14
- `;