cyberia 3.2.9 → 3.2.12
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.
- package/.github/workflows/engine-cyberia.cd.yml +6 -0
- package/.github/workflows/npmpkg.ci.yml +1 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -0
- package/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +20 -4
- package/CHANGELOG.md +213 -1
- package/CLI-HELP.md +92 -23
- package/README.md +190 -348
- package/bin/build.js +24 -8
- package/bin/build.template.js +187 -0
- package/bin/cyberia.js +229 -52
- package/bin/deploy.js +12 -2
- package/bin/index.js +229 -52
- package/bump.config.js +26 -0
- package/conf.js +130 -24
- package/deployment.yaml +4 -2
- package/hardhat/package-lock.json +113 -144
- package/hardhat/package.json +4 -3
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +4 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +4 -2
- package/manifests/kind-config-dev.yaml +8 -0
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb/pv-pvc.yaml +44 -8
- package/manifests/mongodb/statefulset.yaml +55 -68
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +27 -15
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +81 -46
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +38 -33
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +16 -16
- package/src/api/core/core.router.js +19 -14
- package/src/api/core/core.service.js +5 -5
- package/src/api/crypto/crypto.router.js +18 -12
- package/src/api/crypto/crypto.service.js +3 -3
- package/src/api/cyberia-action/cyberia-action.model.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +22 -18
- package/src/api/cyberia-action/cyberia-action.service.js +5 -5
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +74 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +99 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +98 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +25 -20
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +6 -6
- package/src/api/cyberia-entity/cyberia-entity.router.js +22 -18
- package/src/api/cyberia-entity/cyberia-entity.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-fallback-world.js +79 -4
- package/src/api/cyberia-instance/cyberia-instance.router.js +57 -52
- package/src/api/cyberia-instance/cyberia-instance.service.js +10 -10
- package/src/api/cyberia-instance/cyberia-world-generator.js +3 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +14 -48
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +22 -18
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +5 -5
- package/src/api/cyberia-map/cyberia-map.router.js +35 -30
- package/src/api/cyberia-map/cyberia-map.service.js +7 -7
- package/src/api/cyberia-quest/cyberia-quest.model.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +22 -18
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +22 -18
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +5 -5
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +451 -0
- package/src/api/default/default.router.js +22 -18
- package/src/api/default/default.service.js +5 -5
- package/src/api/document/document.router.js +28 -23
- package/src/api/document/document.service.js +100 -23
- package/src/api/file/file.router.js +19 -13
- package/src/api/file/file.service.js +9 -7
- package/src/api/instance/instance.router.js +29 -24
- package/src/api/instance/instance.service.js +6 -6
- package/src/api/ipfs/ipfs.router.js +21 -16
- package/src/api/ipfs/ipfs.service.js +8 -8
- package/src/api/object-layer/object-layer.router.js +512 -507
- package/src/api/object-layer/object-layer.service.js +17 -14
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +22 -18
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +5 -5
- package/src/api/test/test.router.js +17 -12
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +5 -4
- package/src/api/user/user.router.js +297 -288
- package/src/api/user/user.service.js +100 -35
- package/src/cli/baremetal.js +132 -101
- package/src/cli/cluster.js +700 -232
- package/src/cli/db.js +59 -60
- package/src/cli/deploy.js +216 -137
- package/src/cli/fs.js +13 -3
- package/src/cli/index.js +80 -15
- package/src/cli/ipfs.js +4 -6
- package/src/cli/kubectl.js +4 -1
- package/src/cli/lxd.js +1099 -223
- package/src/cli/monitor.js +9 -3
- package/src/cli/release.js +334 -140
- package/src/cli/repository.js +68 -23
- package/src/cli/run.js +193 -49
- package/src/cli/secrets.js +11 -2
- package/src/cli/test.js +9 -3
- package/src/client/Default.index.js +9 -3
- package/src/client/components/core/Auth.js +5 -0
- package/src/client/components/core/ClientEvents.js +76 -0
- package/src/client/components/core/EventBus.js +4 -0
- package/src/client/components/core/Modal.js +82 -41
- package/src/client/components/core/PanelForm.js +56 -52
- package/src/client/components/core/Worker.js +162 -363
- package/src/client/components/cyberia/MapEngineCyberia.js +1 -1
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +330 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +50 -410
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +114 -327
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +200 -222
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +203 -185
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +2 -2
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
- package/src/client/ssr/views/CyberiaServerMetrics.js +982 -0
- package/src/client/sw/core.sw.js +174 -112
- package/src/db/DataBaseProvider.js +115 -15
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +129 -21
- package/src/grpc/cyberia/grpc-server.js +25 -57
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +24 -3
- package/src/runtime/cyberia-client/Dockerfile.dev +82 -0
- package/src/runtime/cyberia-server/Dockerfile +29 -4
- package/src/runtime/cyberia-server/Dockerfile.dev +71 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/auth.js +2 -2
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build.js +94 -129
- package/src/server/conf.js +86 -83
- package/src/server/process.js +180 -19
- package/src/server/proxy.js +9 -2
- package/src/server/runtime.js +1 -1
- package/src/server/start.js +17 -5
- package/src/server/valkey.js +2 -0
- package/src/ws/IoInterface.js +16 -16
- package/src/ws/core/channels/core.ws.chat.js +11 -11
- package/src/ws/core/channels/core.ws.mailer.js +29 -29
- package/src/ws/core/channels/core.ws.stream.js +19 -19
- package/src/ws/core/core.ws.connection.js +8 -8
- package/src/ws/core/core.ws.server.js +6 -5
- package/src/ws/default/channels/default.ws.main.js +10 -10
- package/src/ws/default/default.ws.connection.js +4 -4
- package/src/ws/default/default.ws.server.js +4 -3
- package/bin/file.js +0 -202
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +0 -574
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +0 -467
- package/src/client/ssr/email/DefaultRecoverEmail.js +0 -21
- package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
- package/src/client/ssr/pages/CyberiaServerMetrics.js +0 -461
- /package/src/client/ssr/{offline → views}/Maintenance.js +0 -0
- /package/src/client/ssr/{offline → views}/NoNetworkConnection.js +0 -0
- /package/src/client/ssr/{pages → views}/Test.js +0 -0
package/src/runtime/wp/Wp.js
CHANGED
|
@@ -56,10 +56,11 @@ class WpService {
|
|
|
56
56
|
* to `/usr/local/bin/wp` if it is not already present.
|
|
57
57
|
*/
|
|
58
58
|
static ensureWpCli() {
|
|
59
|
-
const existing = shellExec(`PATH="${LAMPP_BIN}:$PATH" which wp
|
|
59
|
+
const existing = shellExec(`PATH="${LAMPP_BIN}:$PATH" which wp`, {
|
|
60
60
|
stdout: true,
|
|
61
61
|
silent: true,
|
|
62
62
|
disableLog: true,
|
|
63
|
+
silentOnError: true,
|
|
63
64
|
});
|
|
64
65
|
if (existing && existing.trim()) return;
|
|
65
66
|
logger.info('WP-CLI not found — installing to /usr/local/bin/wp');
|
|
@@ -76,10 +77,11 @@ class WpService {
|
|
|
76
77
|
*/
|
|
77
78
|
static ensureSendmail() {
|
|
78
79
|
const sendmailPath = '/usr/sbin/sendmail';
|
|
79
|
-
const existing = shellExec(`test -x "${sendmailPath}" && echo ok
|
|
80
|
+
const existing = shellExec(`test -x "${sendmailPath}" && echo ok`, {
|
|
80
81
|
stdout: true,
|
|
81
82
|
silent: true,
|
|
82
83
|
disableLog: true,
|
|
84
|
+
silentOnError: true,
|
|
83
85
|
});
|
|
84
86
|
if (existing && existing.trim() === 'ok') return;
|
|
85
87
|
logger.info('sendmail stub missing — creating no-op at /usr/sbin/sendmail');
|
|
@@ -494,7 +496,7 @@ Thumbs.db
|
|
|
494
496
|
* `git clone` yields a fully working site without needing a fresh install.
|
|
495
497
|
*
|
|
496
498
|
* Safe to call repeatedly — `git commit` is a no-op when the working tree
|
|
497
|
-
* is clean (
|
|
499
|
+
* is clean (`silentOnError: true` swallows the non-zero exit gracefully).
|
|
498
500
|
*
|
|
499
501
|
* @param {object} opts
|
|
500
502
|
* @param {string} opts.siteRoot - Absolute path to the WordPress root.
|
|
@@ -514,7 +516,8 @@ Thumbs.db
|
|
|
514
516
|
|
|
515
517
|
logger.info(`${host}: persisting site to repository`);
|
|
516
518
|
shellExec(
|
|
517
|
-
`cd "${siteRoot}" && git add -A && git commit -m "wp provision ${host} $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
519
|
+
`cd "${siteRoot}" && git add -A && git commit -m "wp provision ${host} $(date -u +%Y-%m-%dT%H:%M:%SZ)"`,
|
|
520
|
+
{ silentOnError: true },
|
|
518
521
|
);
|
|
519
522
|
shellExec(`cd "${siteRoot}" && underpost push . ${githubOrg}/${repoName} -f`);
|
|
520
523
|
logger.info(`${host}: initial commit pushed to ${githubOrg}/${repoName}`);
|
|
@@ -627,7 +630,7 @@ if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROT
|
|
|
627
630
|
|
|
628
631
|
// MariaDB export is handled by the shared db.js backup flow — no duplicate dump here.
|
|
629
632
|
if (fs.existsSync(path.join(siteRoot, '.git'))) {
|
|
630
|
-
shellExec(`cd "${siteRoot}" && git add -A && git commit -m "wp backup $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
633
|
+
shellExec(`cd "${siteRoot}" && git add -A && git commit -m "wp backup $(date -u +%Y-%m-%dT%H:%M:%SZ)"`, { silentOnError: true });
|
|
631
634
|
shellExec(`cd "${siteRoot}" && underpost push . ${githubOrg}/${repository.split('/').pop().split('.')[0]}`);
|
|
632
635
|
logger.info(`backup: git push done for ${siteRoot}`);
|
|
633
636
|
} else {
|
package/src/server/auth.js
CHANGED
|
@@ -20,7 +20,7 @@ import rateLimit from 'express-rate-limit';
|
|
|
20
20
|
import slowDown from 'express-slow-down';
|
|
21
21
|
import cors from 'cors';
|
|
22
22
|
import cookieParser from 'cookie-parser';
|
|
23
|
-
import {
|
|
23
|
+
import { DataBaseProviderService } from '../db/DataBaseProvider.js';
|
|
24
24
|
import { isDevProxyContext } from './conf.js';
|
|
25
25
|
|
|
26
26
|
const logger = loggerFactory(import.meta);
|
|
@@ -229,7 +229,7 @@ const authMiddlewareFactory = (options = { host: '', path: '' }) => {
|
|
|
229
229
|
|
|
230
230
|
// Non-guest verify session exists
|
|
231
231
|
if (payload.jwtid && payload.role !== 'guest') {
|
|
232
|
-
const User =
|
|
232
|
+
const User = DataBaseProviderService.getModel('user', { host: payload.host, path: payload.path });
|
|
233
233
|
const user = await User.findOne({ _id: payload._id, 'activeSessions._id': payload.jwtid }).lean();
|
|
234
234
|
|
|
235
235
|
if (!user) {
|
|
@@ -399,7 +399,7 @@ const buildCoverage = async ({ docs, docsDestination }) => {
|
|
|
399
399
|
shellExec(`cd ${coveragePath} && npm run coverage`, { silent: true });
|
|
400
400
|
} else if (pkg.scripts && pkg.scripts.test) {
|
|
401
401
|
logger.info('generating coverage via test', coveragePath);
|
|
402
|
-
shellExec(`cd ${coveragePath} && npm test`, { silent: true });
|
|
402
|
+
shellExec(`cd ${coveragePath} && npm test`, { silent: true, silentOnError: true });
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
405
|
}
|
|
@@ -724,23 +724,24 @@ const buildClient = async (
|
|
|
724
724
|
const ssrPath = path === '/' ? path : `${path}/`;
|
|
725
725
|
const Render = await ssrFactory();
|
|
726
726
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
727
|
+
const swSrcPath = `./src/client/sw/core.sw.js`;
|
|
728
|
+
const swPublicPath = `${rootClientPath}/sw.js`;
|
|
729
|
+
const swShouldRebuild =
|
|
730
|
+
views && !(enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === swSrcPath));
|
|
731
|
+
// Transformed SW JS is held in memory; it gets prepended with renderPayload
|
|
732
|
+
// and written once below, after PRE_CACHED_RESOURCES are known.
|
|
733
|
+
let swTransformedJs = '';
|
|
734
|
+
if (swShouldRebuild) {
|
|
735
|
+
swTransformedJs = await transformClientJs(swSrcPath, {
|
|
736
|
+
dists,
|
|
737
|
+
proxyPath: path,
|
|
738
|
+
baseHost,
|
|
739
|
+
minify: minifyBuild,
|
|
740
|
+
externalizeBareImports: false,
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
743
|
|
|
744
|
+
if (views) {
|
|
744
745
|
if (
|
|
745
746
|
!(
|
|
746
747
|
enableLiveRebuild &&
|
|
@@ -750,9 +751,8 @@ const buildClient = async (
|
|
|
750
751
|
)
|
|
751
752
|
)
|
|
752
753
|
for (const view of views) {
|
|
753
|
-
const buildPath = `${
|
|
754
|
-
|
|
755
|
-
}${view.path === '/' ? view.path : `${view.path}/`}`;
|
|
754
|
+
const buildPath = `${rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
|
|
755
|
+
}${view.path === '/' ? view.path : `${view.path}/`}`;
|
|
756
756
|
|
|
757
757
|
if (!fs.existsSync(buildPath)) fs.mkdirSync(buildPath, { recursive: true });
|
|
758
758
|
|
|
@@ -768,9 +768,8 @@ const buildClient = async (
|
|
|
768
768
|
fs.writeFileSync(`${buildPath}${buildId}.js`, jsSrc, 'utf8');
|
|
769
769
|
const title = metadata.title ? metadata.title : title;
|
|
770
770
|
|
|
771
|
-
const canonicalURL = `https://${host}${path}${
|
|
772
|
-
|
|
773
|
-
}`;
|
|
771
|
+
const canonicalURL = `https://${host}${path}${view.path === '/' ? (path === '/' ? '' : '/') : path === '/' ? `${view.path.slice(1)}/` : `${view.path}/`
|
|
772
|
+
}`;
|
|
774
773
|
|
|
775
774
|
let ssrHeadComponents = ``;
|
|
776
775
|
let ssrBodyComponents = ``;
|
|
@@ -904,12 +903,12 @@ const buildClient = async (
|
|
|
904
903
|
`${buildPath}index.html`,
|
|
905
904
|
minifyBuild
|
|
906
905
|
? await minify(htmlSrc, {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
906
|
+
minifyCSS: true,
|
|
907
|
+
minifyJS: true,
|
|
908
|
+
collapseBooleanAttributes: true,
|
|
909
|
+
collapseInlineTagWhitespace: true,
|
|
910
|
+
collapseWhitespace: true,
|
|
911
|
+
})
|
|
913
912
|
: htmlSrc,
|
|
914
913
|
'utf8',
|
|
915
914
|
);
|
|
@@ -967,119 +966,85 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
|
|
|
967
966
|
}
|
|
968
967
|
|
|
969
968
|
if (client) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
...(isDevelopment ? { dev: true } : undefined),
|
|
1001
|
-
},
|
|
1002
|
-
renderApi: {
|
|
1003
|
-
JSONweb,
|
|
1004
|
-
},
|
|
1005
|
-
});
|
|
1006
|
-
|
|
1007
|
-
const buildPath = `${
|
|
1008
|
-
rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
|
|
1009
|
-
}${page.path === '/' ? page.path : `${page.path}/`}`;
|
|
1010
|
-
|
|
1011
|
-
// Install-time precache is intentionally restricted to SSR offline pages.
|
|
1012
|
-
// All other routes/assets are loaded lazily at runtime.
|
|
1013
|
-
if (pageType === 'offline') {
|
|
1014
|
-
PRE_CACHED_RESOURCES.push(toPrecacheIndexUrl(page.path));
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
if (!fs.existsSync(buildPath)) fs.mkdirSync(buildPath, { recursive: true });
|
|
1018
|
-
|
|
1019
|
-
const buildHtmlPath = `${buildPath}index.html`;
|
|
1020
|
-
|
|
1021
|
-
logger.info('ssr page build', buildHtmlPath);
|
|
1022
|
-
|
|
1023
|
-
fs.writeFileSync(
|
|
1024
|
-
buildHtmlPath,
|
|
1025
|
-
minifyBuild
|
|
1026
|
-
? await minify(htmlSrc, {
|
|
1027
|
-
minifyCSS: true,
|
|
1028
|
-
minifyJS: true,
|
|
1029
|
-
collapseBooleanAttributes: true,
|
|
1030
|
-
collapseInlineTagWhitespace: true,
|
|
1031
|
-
collapseWhitespace: true,
|
|
1032
|
-
})
|
|
1033
|
-
: htmlSrc,
|
|
1034
|
-
'utf8',
|
|
1035
|
-
);
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
969
|
+
const proxyPrefix = path === '/' ? '' : path;
|
|
970
|
+
const buildIndexUrl = (routePath) => `${proxyPrefix}${routePath === '/' ? '' : routePath}/index.html`;
|
|
971
|
+
|
|
972
|
+
// SSR views: a single declarative array. The role of each view (regular
|
|
973
|
+
// page vs. offline/maintenance fallback) is expressed by per-entry flags;
|
|
974
|
+
// fallback-flagged views are also precached so the SW can serve them
|
|
975
|
+
// when the network is unreachable.
|
|
976
|
+
const ssrClientConf = confSSR[getCapVariableName(client)] || {};
|
|
977
|
+
const ssrViews = Array.isArray(ssrClientConf.views) ? ssrClientConf.views : [];
|
|
978
|
+
const PRE_CACHED_RESOURCES = [];
|
|
979
|
+
let offlineFallbackUrl = null;
|
|
980
|
+
let maintenanceFallbackUrl = null;
|
|
981
|
+
|
|
982
|
+
for (const view of ssrViews) {
|
|
983
|
+
const SsrComponent = await ssrFactory(`./src/client/ssr/views/${view.client}.js`);
|
|
984
|
+
|
|
985
|
+
const htmlSrc = Render({
|
|
986
|
+
title: view.title,
|
|
987
|
+
ssrPath,
|
|
988
|
+
ssrHeadComponents: '<base target="_top">',
|
|
989
|
+
ssrBodyComponents: SsrComponent(),
|
|
990
|
+
renderPayload: {
|
|
991
|
+
apiBaseProxyPath,
|
|
992
|
+
apiBaseHost,
|
|
993
|
+
apiBasePath: process.env.BASE_API,
|
|
994
|
+
version: Underpost.version,
|
|
995
|
+
...(isDevelopment ? { dev: true } : undefined),
|
|
996
|
+
},
|
|
997
|
+
renderApi: { JSONweb },
|
|
998
|
+
});
|
|
1039
999
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
const ssrClientConf = confSSR[getCapVariableName(client)] || {};
|
|
1043
|
-
const ssrOfflinePages = Array.isArray(ssrClientConf.offline) ? ssrClientConf.offline : [];
|
|
1044
|
-
const normalizeSsrRoutePath = (candidatePath, fallbackPath) => {
|
|
1045
|
-
const value =
|
|
1046
|
-
typeof candidatePath === 'string' && candidatePath.trim().length > 0
|
|
1047
|
-
? candidatePath.trim()
|
|
1048
|
-
: fallbackPath;
|
|
1049
|
-
const withLeadingSlash = value.startsWith('/') ? value : `/${value}`;
|
|
1050
|
-
const withoutTrailingSlash = withLeadingSlash.replace(/\/+$/, '');
|
|
1051
|
-
return withoutTrailingSlash.length > 0 ? withoutTrailingSlash : '/';
|
|
1052
|
-
};
|
|
1000
|
+
const buildPath = `${rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
|
|
1001
|
+
}${view.path === '/' ? view.path : `${view.path}/`}`;
|
|
1053
1002
|
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1003
|
+
const indexUrl = buildIndexUrl(view.path);
|
|
1004
|
+
if (view.offlineDefault) {
|
|
1005
|
+
offlineFallbackUrl = indexUrl;
|
|
1006
|
+
PRE_CACHED_RESOURCES.push(indexUrl);
|
|
1007
|
+
}
|
|
1008
|
+
if (view.maintenanceDefault) {
|
|
1009
|
+
maintenanceFallbackUrl = indexUrl;
|
|
1010
|
+
PRE_CACHED_RESOURCES.push(indexUrl);
|
|
1011
|
+
}
|
|
1060
1012
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
page?.client === 'Maintenance' ||
|
|
1065
|
-
/maintenance/i.test(`${page?.title || ''} ${page?.client || ''} ${page?.path || ''}`),
|
|
1066
|
-
) || ssrOfflinePages[1];
|
|
1013
|
+
if (!fs.existsSync(buildPath)) fs.mkdirSync(buildPath, { recursive: true });
|
|
1014
|
+
const buildHtmlPath = `${buildPath}index.html`;
|
|
1015
|
+
logger.info('ssr view build', buildHtmlPath);
|
|
1067
1016
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1017
|
+
fs.writeFileSync(
|
|
1018
|
+
buildHtmlPath,
|
|
1019
|
+
minifyBuild
|
|
1020
|
+
? await minify(htmlSrc, {
|
|
1021
|
+
minifyCSS: true,
|
|
1022
|
+
minifyJS: true,
|
|
1023
|
+
collapseBooleanAttributes: true,
|
|
1024
|
+
collapseInlineTagWhitespace: true,
|
|
1025
|
+
collapseWhitespace: true,
|
|
1026
|
+
})
|
|
1027
|
+
: htmlSrc,
|
|
1028
|
+
'utf8',
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1070
1031
|
|
|
1032
|
+
if (swShouldRebuild) {
|
|
1033
|
+
const cacheScope = path === '/' ? 'root' : path.replaceAll('/', '_');
|
|
1071
1034
|
const renderPayload = {
|
|
1072
1035
|
PRE_CACHED_RESOURCES: uniqueArray(PRE_CACHED_RESOURCES),
|
|
1073
1036
|
PROXY_PATH: path,
|
|
1074
|
-
CACHE_PREFIX: `engine-core
|
|
1075
|
-
|
|
1076
|
-
|
|
1037
|
+
CACHE_PREFIX: `engine-core-${cacheScope}`,
|
|
1038
|
+
OFFLINE_URL: offlineFallbackUrl || buildIndexUrl('/offline'),
|
|
1039
|
+
MAINTENANCE_URL: maintenanceFallbackUrl || buildIndexUrl('/maintenance'),
|
|
1077
1040
|
};
|
|
1041
|
+
|
|
1042
|
+
// Single write: prepend the payload prelude to the transformed SW JS.
|
|
1078
1043
|
fs.writeFileSync(
|
|
1079
|
-
|
|
1044
|
+
swPublicPath,
|
|
1080
1045
|
`self.renderPayload = ${JSONweb(renderPayload)};
|
|
1081
1046
|
self.__WB_DISABLE_DEV_LOGS = true;
|
|
1082
|
-
${
|
|
1047
|
+
${swTransformedJs}`,
|
|
1083
1048
|
'utf8',
|
|
1084
1049
|
);
|
|
1085
1050
|
}
|
package/src/server/conf.js
CHANGED
|
@@ -41,6 +41,20 @@ const logger = loggerFactory(import.meta);
|
|
|
41
41
|
*/
|
|
42
42
|
const ENV_REF_PREFIX = 'env:';
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Resolves a standardized context key from host/path descriptors.
|
|
46
|
+
* The key is used across DB, WS, mailer, and cache registries.
|
|
47
|
+
*
|
|
48
|
+
* @method resolveHostKeyContext
|
|
49
|
+
* @param {{host?: string, path?: string}|string} [context={ host: '', path: '' }] - Context object or prebuilt key.
|
|
50
|
+
* @returns {string} Host key context string.
|
|
51
|
+
* @memberof ServerConfBuilder
|
|
52
|
+
*/
|
|
53
|
+
const resolveHostKeyContext = (context = { host: '', path: '' }) => {
|
|
54
|
+
if (typeof context === 'string') return context;
|
|
55
|
+
return `${context.host || ''}${context.path || ''}`;
|
|
56
|
+
};
|
|
57
|
+
|
|
44
58
|
/**
|
|
45
59
|
* Recursively walks a configuration object and replaces every string value that
|
|
46
60
|
* starts with {@link ENV_REF_PREFIX} (`"env:"`) with the corresponding
|
|
@@ -320,25 +334,29 @@ const Config = {
|
|
|
320
334
|
|
|
321
335
|
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
322
336
|
|
|
323
|
-
const
|
|
337
|
+
const sharedEnvTemplate = fs.existsSync('./.env.example')
|
|
324
338
|
? fs.readFileSync('./.env.example', 'utf8')
|
|
325
339
|
: fs.existsSync('./.env.production')
|
|
326
340
|
? fs.readFileSync('./.env.production', 'utf8')
|
|
327
341
|
: '';
|
|
328
342
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
fs.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
343
|
+
const envTemplates = {
|
|
344
|
+
production: fs.existsSync('./.env.production') ? fs.readFileSync('./.env.production', 'utf8') : sharedEnvTemplate,
|
|
345
|
+
development: fs.existsSync('./.env.development')
|
|
346
|
+
? fs.readFileSync('./.env.development', 'utf8')
|
|
347
|
+
: sharedEnvTemplate
|
|
348
|
+
? sharedEnvTemplate.replace('NODE_ENV=production', 'NODE_ENV=development').replace('PORT=3000', 'PORT=4000')
|
|
349
|
+
: '',
|
|
350
|
+
test: fs.existsSync('./.env.test')
|
|
351
|
+
? fs.readFileSync('./.env.test', 'utf8')
|
|
352
|
+
: sharedEnvTemplate
|
|
353
|
+
? sharedEnvTemplate.replace('NODE_ENV=production', 'NODE_ENV=test').replace('PORT=3000', 'PORT=5000')
|
|
354
|
+
: '',
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
for (const [envName, envTemplate] of Object.entries(envTemplates)) {
|
|
358
|
+
if (!envTemplate) continue;
|
|
359
|
+
fs.writeFileSync(`${folder}/.env.${envName}`, envTemplate.replaceAll('dd-default', deployId), 'utf8');
|
|
342
360
|
}
|
|
343
361
|
|
|
344
362
|
fs.writeFileSync(
|
|
@@ -1208,7 +1226,11 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
1208
1226
|
const confSsr = DefaultConf.ssr[ssr];
|
|
1209
1227
|
const clients = DefaultConf.client.default.services;
|
|
1210
1228
|
|
|
1211
|
-
if (
|
|
1229
|
+
if (
|
|
1230
|
+
absolutePath.match('src/api') &&
|
|
1231
|
+
!absolutePath.match('src/api/types.js') &&
|
|
1232
|
+
!confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))
|
|
1233
|
+
) {
|
|
1212
1234
|
return false;
|
|
1213
1235
|
}
|
|
1214
1236
|
if (absolutePath.match('conf.dd-') && absolutePath.match('.js')) return false;
|
|
@@ -1250,14 +1272,8 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
1250
1272
|
return false;
|
|
1251
1273
|
}
|
|
1252
1274
|
if (
|
|
1253
|
-
absolutePath.match('src/client/ssr/
|
|
1254
|
-
!confSsr.
|
|
1255
|
-
) {
|
|
1256
|
-
return false;
|
|
1257
|
-
}
|
|
1258
|
-
if (
|
|
1259
|
-
absolutePath.match('src/client/ssr/pages') &&
|
|
1260
|
-
!confSsr.pages.find((p) => absolutePath.match(`src/client/ssr/pages/${p.client}.js`))
|
|
1275
|
+
absolutePath.match('src/client/ssr/views') &&
|
|
1276
|
+
!(confSsr.views || []).find((p) => absolutePath.match(`src/client/ssr/views/${p.client}.js`))
|
|
1261
1277
|
) {
|
|
1262
1278
|
return false;
|
|
1263
1279
|
}
|
|
@@ -1279,15 +1295,17 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
1279
1295
|
/**
|
|
1280
1296
|
* @method awaitDeployMonitor
|
|
1281
1297
|
* @description Waits for the deploy monitor.
|
|
1282
|
-
* @param {boolean} [
|
|
1298
|
+
* @param {boolean} [isFinal=false] - If true, logs when the final (non-replica) deployment completes.
|
|
1283
1299
|
* @param {number} [deltaMs=1000] - The delta ms.
|
|
1284
1300
|
* @returns {Promise<void>} - The await deploy monitor.
|
|
1285
1301
|
* @memberof ServerConfBuilder
|
|
1286
1302
|
*/
|
|
1287
|
-
const awaitDeployMonitor = async (
|
|
1288
|
-
|
|
1303
|
+
const awaitDeployMonitor = async (isFinal = false, deltaMs = 1000) => {
|
|
1304
|
+
Underpost.env.set('await-deploy', new Date().toISOString());
|
|
1305
|
+
if (isFinal) logger.info('Final deployment running (no replica)');
|
|
1289
1306
|
await timer(deltaMs);
|
|
1290
|
-
if (Underpost.env.get('
|
|
1307
|
+
if (Underpost.env.get('container-status') === 'error') throw new Error('Container status error');
|
|
1308
|
+
if (Underpost.env.get('await-deploy')) return await awaitDeployMonitor(isFinal, deltaMs);
|
|
1291
1309
|
};
|
|
1292
1310
|
|
|
1293
1311
|
/**
|
|
@@ -1312,59 +1330,6 @@ const mergeFile = async (parts = [], outputFilePath) => {
|
|
|
1312
1330
|
});
|
|
1313
1331
|
};
|
|
1314
1332
|
|
|
1315
|
-
/**
|
|
1316
|
-
* @method rebuildConfFactory
|
|
1317
|
-
* @description Rebuilds the conf factory.
|
|
1318
|
-
* @param {object} options - The options.
|
|
1319
|
-
* @param {string} options.deployId - The deploy ID.
|
|
1320
|
-
* @param {string} options.valkey - The valkey.
|
|
1321
|
-
* @param {boolean} [options.mongo=false] - The mongo.
|
|
1322
|
-
* @returns {object} - The rebuild conf factory.
|
|
1323
|
-
* @memberof ServerConfBuilder
|
|
1324
|
-
*/
|
|
1325
|
-
const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
1326
|
-
const confServer = loadReplicas(deployId, loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`));
|
|
1327
|
-
const hosts = {};
|
|
1328
|
-
for (const host of Object.keys(confServer)) {
|
|
1329
|
-
hosts[host] = {};
|
|
1330
|
-
for (const path of Object.keys(confServer[host])) {
|
|
1331
|
-
if (!confServer[host][path].db) continue;
|
|
1332
|
-
const { singleReplica, replicas, db } = confServer[host][path];
|
|
1333
|
-
const { provider } = db;
|
|
1334
|
-
if (singleReplica) {
|
|
1335
|
-
for (const replica of replicas) {
|
|
1336
|
-
const deployIdReplica = buildReplicaId({ replica, deployId });
|
|
1337
|
-
const confServerReplica = loadConfServerJson(`./engine-private/replica/${deployIdReplica}/conf.server.json`);
|
|
1338
|
-
for (const _host of Object.keys(confServerReplica)) {
|
|
1339
|
-
for (const _path of Object.keys(confServerReplica[_host])) {
|
|
1340
|
-
hosts[host][_path] = { replica: { host, path } };
|
|
1341
|
-
confServerReplica[_host][_path].valkey = valkey;
|
|
1342
|
-
switch (provider) {
|
|
1343
|
-
case 'mongoose':
|
|
1344
|
-
confServerReplica[_host][_path].db.host = mongo.host;
|
|
1345
|
-
break;
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
fs.writeFileSync(
|
|
1350
|
-
`./engine-private/replica/${deployIdReplica}/conf.server.json`,
|
|
1351
|
-
JSON.stringify(confServerReplica, null, 4),
|
|
1352
|
-
'utf8',
|
|
1353
|
-
);
|
|
1354
|
-
}
|
|
1355
|
-
} else hosts[host][path] = {};
|
|
1356
|
-
confServer[host][path].valkey = valkey;
|
|
1357
|
-
switch (provider) {
|
|
1358
|
-
case 'mongoose':
|
|
1359
|
-
confServer[host][path].db.host = mongo.host;
|
|
1360
|
-
break;
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
1365
|
-
return { hosts };
|
|
1366
|
-
};
|
|
1367
|
-
|
|
1368
1333
|
/**
|
|
1369
1334
|
* @method getPathsSSR
|
|
1370
1335
|
* @description Gets the paths SSR.
|
|
@@ -1377,8 +1342,7 @@ const getPathsSSR = (conf) => {
|
|
|
1377
1342
|
for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
|
|
1378
1343
|
for (const o of conf.body) paths.push(`src/client/ssr/body/${o}.js`);
|
|
1379
1344
|
for (const o of Object.keys(conf.mailer)) paths.push(`src/client/ssr/mailer/${conf.mailer[o]}.js`);
|
|
1380
|
-
for (const o of conf.
|
|
1381
|
-
for (const o of conf.pages) paths.push(`src/client/ssr/pages/${o.client}.js`);
|
|
1345
|
+
for (const o of conf.views || []) paths.push(`src/client/ssr/views/${o.client}.js`);
|
|
1382
1346
|
return paths;
|
|
1383
1347
|
};
|
|
1384
1348
|
|
|
@@ -1746,6 +1710,44 @@ const loadConfServerJson = (jsonPath, options) => {
|
|
|
1746
1710
|
return options && options.resolve === true ? resolveConfSecrets(raw) : raw;
|
|
1747
1711
|
};
|
|
1748
1712
|
|
|
1713
|
+
/**
|
|
1714
|
+
* Creates and writes the /etc/hosts file for a deployment.
|
|
1715
|
+
* @method etcHostFactory
|
|
1716
|
+
* @param {Array<string>} hosts - List of hosts to be added to the hosts file.
|
|
1717
|
+
* @param {object} options - Options for the hosts file creation.
|
|
1718
|
+
* @param {boolean} options.append - Whether to append to the existing hosts file.
|
|
1719
|
+
* @returns {object} - Object containing the rendered hosts file.
|
|
1720
|
+
* @memberof ServerConfBuilder
|
|
1721
|
+
*/
|
|
1722
|
+
const etcHostFactory = (hosts = [], options = { append: false }) => {
|
|
1723
|
+
hosts = hosts.map((host) => {
|
|
1724
|
+
try {
|
|
1725
|
+
if (!host.startsWith('http')) host = `http://${host}`;
|
|
1726
|
+
const hostname = new URL(host).hostname;
|
|
1727
|
+
logger.info('Hostname extract valid', { host, hostname });
|
|
1728
|
+
return hostname;
|
|
1729
|
+
} catch (e) {
|
|
1730
|
+
logger.warn('No hostname extract valid', host);
|
|
1731
|
+
return host;
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
const renderHosts = `127.0.0.1 ${hosts.join(
|
|
1735
|
+
' ',
|
|
1736
|
+
)} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
1737
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
1738
|
+
|
|
1739
|
+
if (options && options.append && fs.existsSync(`/etc/hosts`)) {
|
|
1740
|
+
fs.writeFileSync(
|
|
1741
|
+
`/etc/hosts`,
|
|
1742
|
+
fs.readFileSync(`/etc/hosts`, 'utf8') +
|
|
1743
|
+
`
|
|
1744
|
+
${renderHosts}`,
|
|
1745
|
+
'utf8',
|
|
1746
|
+
);
|
|
1747
|
+
} else fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
1748
|
+
return { renderHosts };
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1749
1751
|
export {
|
|
1750
1752
|
Config,
|
|
1751
1753
|
loadConf,
|
|
@@ -1774,7 +1776,6 @@ export {
|
|
|
1774
1776
|
pathPortAssignmentFactory,
|
|
1775
1777
|
deployRangePortFactory,
|
|
1776
1778
|
awaitDeployMonitor,
|
|
1777
|
-
rebuildConfFactory,
|
|
1778
1779
|
buildCliDoc,
|
|
1779
1780
|
getInstanceContext,
|
|
1780
1781
|
buildApiConf,
|
|
@@ -1784,6 +1785,7 @@ export {
|
|
|
1784
1785
|
devProxyHostFactory,
|
|
1785
1786
|
isTlsDevProxy,
|
|
1786
1787
|
getTlsHosts,
|
|
1788
|
+
resolveHostKeyContext,
|
|
1787
1789
|
resolveConfSecrets,
|
|
1788
1790
|
loadConfServerJson,
|
|
1789
1791
|
getConfFolder,
|
|
@@ -1792,4 +1794,5 @@ export {
|
|
|
1792
1794
|
DEFAULT_DEPLOY_ID,
|
|
1793
1795
|
loadCronDeployEnv,
|
|
1794
1796
|
cronDeployIdResolve,
|
|
1797
|
+
etcHostFactory,
|
|
1795
1798
|
};
|