cyberia 3.0.3 → 3.1.3
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/{.env.production → .env.example} +20 -2
- package/.github/workflows/engine-cyberia.cd.yml +41 -10
- package/.github/workflows/engine-cyberia.ci.yml +53 -14
- package/.github/workflows/ghpkg.ci.yml +1 -1
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/hardhat.ci.yml +82 -0
- package/.github/workflows/npmpkg.ci.yml +37 -8
- package/.github/workflows/publish.ci.yml +5 -5
- package/.github/workflows/publish.cyberia.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +3 -2
- package/.vscode/extensions.json +9 -8
- package/.vscode/settings.json +3 -2
- package/CHANGELOG.md +211 -1
- package/CLI-HELP.md +78 -53
- package/WHITE-PAPER.md +1540 -0
- package/bin/build.js +16 -10
- package/bin/cyberia.js +861 -4
- package/bin/deploy.js +103 -270
- package/bin/file.js +2 -1
- package/bin/index.js +861 -4
- package/bin/vs.js +3 -3
- package/conf.js +105 -97
- package/deployment.yaml +148 -4
- package/hardhat/.env.example +31 -0
- package/hardhat/README.md +531 -0
- package/hardhat/WHITE-PAPER.md +1540 -0
- package/hardhat/contracts/ObjectLayerToken.sol +391 -0
- package/hardhat/deployments/.gitkeep +0 -0
- package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
- package/hardhat/hardhat.config.js +136 -0
- package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
- package/hardhat/networks/besu-object-layer.network.json +138 -0
- package/hardhat/package-lock.json +7628 -0
- package/hardhat/package.json +45 -0
- package/hardhat/scripts/deployObjectLayerToken.js +98 -0
- package/hardhat/test/ObjectLayerToken.js +590 -0
- package/jsdoc.dd-cyberia.json +59 -0
- package/jsdoc.json +20 -13
- 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 +490 -0
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +261 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/manifests/pv-pvc-dd.yaml +1 -1
- package/package.json +50 -44
- package/proxy.yaml +79 -7
- package/pv-pvc.yaml +132 -0
- package/scripts/k3s-node-setup.sh +1 -1
- package/scripts/ports-ls.sh +2 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +3 -1
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +1 -2
- package/src/api/document/document.service.js +1 -1
- package/src/api/file/file.controller.js +3 -1
- package/src/api/file/file.service.js +28 -5
- package/src/api/ipfs/ipfs.service.js +2 -2
- package/src/api/object-layer/object-layer.controller.js +6 -2
- package/src/api/object-layer/object-layer.model.js +12 -8
- package/src/api/object-layer/object-layer.router.js +668 -42
- package/src/api/object-layer/object-layer.service.js +6 -7
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
- package/src/api/user/user.router.js +10 -5
- package/src/api/user/user.service.js +7 -7
- package/src/cli/baremetal.js +6 -10
- package/src/cli/cloud-init.js +0 -3
- package/src/cli/db.js +54 -71
- package/src/cli/deploy.js +64 -12
- package/src/cli/env.js +5 -5
- package/src/cli/fs.js +0 -2
- package/src/cli/image.js +0 -3
- package/src/cli/index.js +35 -13
- package/src/cli/monitor.js +5 -6
- package/src/cli/repository.js +329 -46
- package/src/cli/run.js +180 -120
- package/src/cli/secrets.js +1 -3
- package/src/cli/ssh.js +1 -1
- package/src/client/Itemledger.index.js +1 -959
- package/src/client/components/core/AgGrid.js +20 -5
- package/src/client/components/core/Alert.js +2 -2
- package/src/client/components/core/Content.js +22 -3
- package/src/client/components/core/Docs.js +30 -6
- package/src/client/components/core/FileExplorer.js +71 -4
- package/src/client/components/core/Input.js +1 -1
- package/src/client/components/core/Modal.js +20 -6
- package/src/client/components/core/RichText.js +1 -2
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +1 -0
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +0 -1
- package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +64 -2
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +1 -0
- package/src/client/components/underpost/CssUnderpost.js +59 -0
- package/src/client/components/underpost/LogInUnderpost.js +3 -0
- package/src/client/components/underpost/LogOutUnderpost.js +2 -0
- package/src/client/components/underpost/MenuUnderpost.js +99 -13
- package/src/client/components/underpost/RoutesUnderpost.js +2 -0
- package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
- package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
- package/src/client/public/cryptokoyn/microdata.json +85 -0
- package/src/client/public/cryptokoyn/site.webmanifest +57 -0
- package/src/client/public/cryptokoyn/sitemap +3 -3
- package/src/client/public/default/sitemap +3 -3
- package/src/client/public/itemledger/browserconfig.xml +2 -2
- package/src/client/public/itemledger/manifest.webmanifest +4 -4
- package/src/client/public/itemledger/microdata.json +71 -0
- package/src/client/public/itemledger/sitemap +3 -3
- package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
- package/src/client/public/test/sitemap +3 -3
- package/src/client/ssr/body/404.js +15 -11
- package/src/client/ssr/body/500.js +15 -11
- package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
- package/src/client/ssr/head/PwaItemledger.js +60 -0
- package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
- package/src/client/ssr/pages/Test.js +11 -10
- package/src/client.build.js +0 -3
- package/src/client.dev.js +0 -3
- package/src/db/DataBaseProvider.js +17 -2
- package/src/db/mariadb/MariaDB.js +14 -9
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/index.js +1 -1
- package/src/proxy.js +0 -3
- package/src/runtime/express/Express.js +15 -9
- package/src/runtime/lampp/Lampp.js +6 -13
- package/src/server/auth.js +12 -14
- package/src/server/backup.js +2 -3
- package/src/server/besu-genesis-generator.js +1630 -0
- package/src/server/client-build-docs.js +126 -17
- package/src/server/client-build-live.js +9 -18
- package/src/server/client-build.js +203 -75
- package/src/server/client-dev-server.js +14 -13
- package/src/server/conf.js +376 -164
- package/src/server/cron.js +2 -1
- package/src/server/dns.js +28 -12
- package/src/server/downloader.js +0 -2
- package/src/server/logger.js +27 -9
- package/src/server/object-layer.js +79 -6
- package/src/server/peer.js +0 -2
- package/src/server/process.js +1 -50
- package/src/server/proxy.js +4 -8
- package/src/server/runtime.js +5 -8
- package/src/server/ssr.js +0 -3
- package/src/server/start.js +19 -12
- package/src/server/tls.js +0 -2
- package/src/server.js +0 -4
- package/.env.development +0 -43
- package/.env.test +0 -43
- package/hardhat/contracts/CryptoKoyn.sol +0 -59
- package/hardhat/contracts/ItemLedger.sol +0 -73
- package/hardhat/contracts/Lock.sol +0 -34
- package/hardhat/hardhat.config.cjs +0 -45
- package/hardhat/ignition/modules/Lock.js +0 -18
- package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
- package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
- package/hardhat/scripts/deployItemledger.cjs +0 -25
- package/hardhat/test/Lock.js +0 -126
- package/hardhat/white-paper.md +0 -581
- package/white-paper.md +0 -581
package/src/cli/repository.js
CHANGED
|
@@ -4,18 +4,27 @@
|
|
|
4
4
|
* @namespace UnderpostRepository
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { commitData } from '../client/components/core/CommonJs.js';
|
|
8
7
|
import dotenv from 'dotenv';
|
|
8
|
+
import { commitData } from '../client/components/core/CommonJs.js';
|
|
9
9
|
import { pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
10
10
|
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
11
11
|
import fs from 'fs-extra';
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
getNpmRootPath,
|
|
14
|
+
Config,
|
|
15
|
+
loadConf,
|
|
16
|
+
readConfJson,
|
|
17
|
+
getConfFilePath,
|
|
18
|
+
loadReplicas,
|
|
19
|
+
loadConfServerJson,
|
|
20
|
+
getDataDeploy,
|
|
21
|
+
buildReplicaId,
|
|
22
|
+
writeEnv,
|
|
23
|
+
} from '../server/conf.js';
|
|
24
|
+
import { buildClient } from '../server/client-build.js';
|
|
14
25
|
import { DefaultConf } from '../../conf.js';
|
|
15
26
|
import Underpost from '../index.js';
|
|
16
27
|
|
|
17
|
-
dotenv.config();
|
|
18
|
-
|
|
19
28
|
const logger = loggerFactory(import.meta);
|
|
20
29
|
|
|
21
30
|
const diffCmd = `--no-pager show -U0 -w --word-diff=color --word-diff-regex='[^[:space:]]' --color=always`;
|
|
@@ -37,8 +46,8 @@ class UnderpostRepository {
|
|
|
37
46
|
* @param {boolean} [options.g8=false] - If true, uses the .g8 extension.
|
|
38
47
|
* @memberof UnderpostRepository
|
|
39
48
|
*/
|
|
40
|
-
clone(gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`, options = { bare: false,
|
|
41
|
-
const gExtension = options.
|
|
49
|
+
clone(gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`, options = { bare: false, g8: false }) {
|
|
50
|
+
const gExtension = options.g8 === true ? '.g8' : '.git';
|
|
42
51
|
const repoName = gitUri.split('/').pop();
|
|
43
52
|
if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
|
|
44
53
|
shellExec(
|
|
@@ -54,16 +63,16 @@ class UnderpostRepository {
|
|
|
54
63
|
* Pulls updates from a GitHub repository.
|
|
55
64
|
* @param {string} [repoPath='./'] - The local path to the repository.
|
|
56
65
|
* @param {string} [gitUri=`${process.env.GITHUB_USERNAME}/pwa-microservices-template`] - The URI of the GitHub repository.
|
|
57
|
-
* @param {object} [options={
|
|
66
|
+
* @param {object} [options={ g8: false }] - Pulling options.
|
|
58
67
|
* @param {boolean} [options.g8=false] - If true, uses the .g8 extension.
|
|
59
68
|
* @memberof UnderpostRepository
|
|
60
69
|
*/
|
|
61
70
|
pull(
|
|
62
71
|
repoPath = './',
|
|
63
72
|
gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`,
|
|
64
|
-
options = {
|
|
73
|
+
options = { g8: false },
|
|
65
74
|
) {
|
|
66
|
-
const gExtension = options.
|
|
75
|
+
const gExtension = options.g8 === true ? '.g8' : '.git';
|
|
67
76
|
shellExec(
|
|
68
77
|
`cd ${repoPath} && git pull https://${
|
|
69
78
|
process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
|
|
@@ -118,15 +127,24 @@ class UnderpostRepository {
|
|
|
118
127
|
changelogBuild: false,
|
|
119
128
|
changelogMinVersion: '',
|
|
120
129
|
changelogNoHash: false,
|
|
130
|
+
b: false,
|
|
121
131
|
},
|
|
122
132
|
) {
|
|
123
133
|
if (!repoPath) repoPath = '.';
|
|
124
134
|
|
|
135
|
+
if (options.b) {
|
|
136
|
+
const currentBranch = shellExec(`cd ${repoPath} && git branch --show-current`, {
|
|
137
|
+
stdout: true,
|
|
138
|
+
silent: true,
|
|
139
|
+
disableLog: true,
|
|
140
|
+
}).trim();
|
|
141
|
+
if (options.copy) pbcopy(currentBranch);
|
|
142
|
+
else console.log(currentBranch);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
125
146
|
if (options.changelog !== undefined || options.changelogBuild) {
|
|
126
|
-
const ciIntegrationPrefix = 'ci(package-pwa-microservices-';
|
|
127
|
-
const ciIntegrationVersionPrefix = 'New release v:';
|
|
128
147
|
const releaseMatch = 'New release v:';
|
|
129
|
-
|
|
130
148
|
// Helper: parse [<tag>] commits into grouped sections
|
|
131
149
|
const buildSectionChangelog = (commits) => {
|
|
132
150
|
const groups = {};
|
|
@@ -253,24 +271,13 @@ class UnderpostRepository {
|
|
|
253
271
|
fs.writeFileSync(changelogPath, `# Changelog\n\n${changelog}`);
|
|
254
272
|
logger.info('CHANGELOG.md built at', changelogPath);
|
|
255
273
|
} else {
|
|
256
|
-
// --changelog [latest-n]: print changelog of last N commits
|
|
274
|
+
// --changelog [latest-n]: print changelog of last N commits (default: 1)
|
|
257
275
|
const hasExplicitCount =
|
|
258
276
|
options.changelog !== undefined && options.changelog !== true && !isNaN(parseInt(options.changelog));
|
|
259
|
-
const scanLimit = hasExplicitCount ? parseInt(options.changelog) :
|
|
277
|
+
const scanLimit = hasExplicitCount ? parseInt(options.changelog) : 1;
|
|
260
278
|
const allCommits = fetchHistory(scanLimit);
|
|
261
279
|
|
|
262
|
-
|
|
263
|
-
if (!hasExplicitCount) {
|
|
264
|
-
// No explicit count: find commits up to the last CI integration boundary
|
|
265
|
-
const ciIndex = allCommits.findIndex(
|
|
266
|
-
(c) => c.message.startsWith(ciIntegrationPrefix) && !c.message.match(ciIntegrationVersionPrefix),
|
|
267
|
-
);
|
|
268
|
-
commits = ciIndex >= 0 ? allCommits.slice(0, ciIndex) : allCommits;
|
|
269
|
-
} else {
|
|
270
|
-
commits = allCommits;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const sections = buildVersionSections(commits);
|
|
280
|
+
const sections = buildVersionSections(allCommits);
|
|
274
281
|
let changelog = renderSections(sections);
|
|
275
282
|
console.log(changelog || `No changelog entries found.\n`);
|
|
276
283
|
}
|
|
@@ -360,7 +367,7 @@ class UnderpostRepository {
|
|
|
360
367
|
* Pushes commits to a remote GitHub repository.
|
|
361
368
|
* @param {string} [repoPath='./'] - The local path to the repository.
|
|
362
369
|
* @param {string} [gitUri=`${process.env.GITHUB_USERNAME}/pwa-microservices-template`] - The URI of the GitHub repository.
|
|
363
|
-
* @param {object} [options={ f: false,
|
|
370
|
+
* @param {object} [options={ f: false, g8: false }] - Push options.
|
|
364
371
|
* @param {boolean} [options.f=false] - If true, forces the push.
|
|
365
372
|
* @param {boolean} [options.g8=false] - If true, uses the .g8 extension.
|
|
366
373
|
* @memberof UnderpostRepository
|
|
@@ -368,9 +375,9 @@ class UnderpostRepository {
|
|
|
368
375
|
push(
|
|
369
376
|
repoPath = './',
|
|
370
377
|
gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`,
|
|
371
|
-
options = { f: false,
|
|
378
|
+
options = { f: false, g8: false },
|
|
372
379
|
) {
|
|
373
|
-
const gExtension = options.
|
|
380
|
+
const gExtension = options.g8 === true ? '.g8' : '.git';
|
|
374
381
|
shellExec(
|
|
375
382
|
`cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}${gExtension}${
|
|
376
383
|
options?.f === true ? ' --force' : ''
|
|
@@ -403,6 +410,7 @@ class UnderpostRepository {
|
|
|
403
410
|
* @param {boolean} [options.cleanTemplate=false] - If true, cleans the pwa-microservices-template build directory.
|
|
404
411
|
* @param {boolean} [options.build=false] - If true, builds the deployment to pwa-microservices-template (requires deployId).
|
|
405
412
|
* @param {boolean} [options.syncConf=false] - If true, syncs configuration to private repositories (requires deployId).
|
|
413
|
+
* @param {boolean} [options.syncStart=false] - If true, syncs start scripts in deploy ID package.json with root package.json.
|
|
406
414
|
* @param {boolean} [options.defaultConf=false] - If true, updates the default configuration file (requires deployId).
|
|
407
415
|
* @param {string} [options.confWorkflowId=''] - If provided, uses this configuration workflow ID.
|
|
408
416
|
* @returns {Promise<boolean>} A promise that resolves when the initialization is complete.
|
|
@@ -420,6 +428,7 @@ class UnderpostRepository {
|
|
|
420
428
|
cleanTemplate: false,
|
|
421
429
|
build: false,
|
|
422
430
|
syncConf: false,
|
|
431
|
+
syncStart: false,
|
|
423
432
|
defaultConf: false,
|
|
424
433
|
confWorkflowId: '',
|
|
425
434
|
},
|
|
@@ -448,6 +457,13 @@ class UnderpostRepository {
|
|
|
448
457
|
|
|
449
458
|
if (options.deployId) {
|
|
450
459
|
let deployId = options.deployId;
|
|
460
|
+
|
|
461
|
+
// Handle sync-start operation (before dd- prefix normalization to support 'dd' special case)
|
|
462
|
+
if (options.syncStart) {
|
|
463
|
+
shellExec(`node bin/deploy sync-start ${deployId}`);
|
|
464
|
+
return resolve(true);
|
|
465
|
+
}
|
|
466
|
+
|
|
451
467
|
if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
|
|
452
468
|
// Handle purge operation
|
|
453
469
|
if (options.purge) {
|
|
@@ -547,7 +563,6 @@ class UnderpostRepository {
|
|
|
547
563
|
const npmRoot = getNpmRootPath();
|
|
548
564
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
549
565
|
const destFolder = `./${projectName}`;
|
|
550
|
-
logger.info('Note: This process may take several minutes to complete');
|
|
551
566
|
logger.info('build app', { destFolder });
|
|
552
567
|
if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
|
|
553
568
|
fs.mkdirSync(destFolder, { recursive: true });
|
|
@@ -572,6 +587,209 @@ class UnderpostRepository {
|
|
|
572
587
|
});
|
|
573
588
|
},
|
|
574
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Builds client assets, single replicas, and/or syncs environment ports.
|
|
592
|
+
* @param {string} [deployId='dd-default'] - The deployment ID.
|
|
593
|
+
* @param {string} [subConf=''] - The sub-configuration for the build.
|
|
594
|
+
* @param {string} [host=''] - Comma-separated hosts to filter the build.
|
|
595
|
+
* @param {string} [path=''] - Comma-separated paths to filter the build.
|
|
596
|
+
* @param {object} [options] - Build options.
|
|
597
|
+
* @param {boolean} [options.syncEnvPort=false] - If true, syncs environment port assignments across all deploy IDs.
|
|
598
|
+
* @param {boolean} [options.singleReplica=false] - If true, builds single replica folders instead of full client.
|
|
599
|
+
* @param {boolean} [options.buildZip=false] - If true, creates zip files of the builds.
|
|
600
|
+
* @param {boolean} [options.liteBuild=false] - If true, skips full build (default is full build).
|
|
601
|
+
* @param {boolean} [options.iconsBuild=false] - If true, builds icons.
|
|
602
|
+
* @returns {Promise<boolean>} A promise that resolves when the build is complete.
|
|
603
|
+
* @memberof UnderpostRepository
|
|
604
|
+
*/
|
|
605
|
+
client(
|
|
606
|
+
deployId = 'dd-default',
|
|
607
|
+
subConf = '',
|
|
608
|
+
host = '',
|
|
609
|
+
path = '',
|
|
610
|
+
options = {
|
|
611
|
+
syncEnvPort: false,
|
|
612
|
+
singleReplica: false,
|
|
613
|
+
buildZip: false,
|
|
614
|
+
liteBuild: false,
|
|
615
|
+
iconsBuild: false,
|
|
616
|
+
},
|
|
617
|
+
) {
|
|
618
|
+
return new Promise(async (resolve, reject) => {
|
|
619
|
+
try {
|
|
620
|
+
// Handle syncEnvPort operation
|
|
621
|
+
if (options.syncEnvPort) {
|
|
622
|
+
const dataDeploy = await getDataDeploy({ disableSyncEnvPort: true });
|
|
623
|
+
const dataEnv = [
|
|
624
|
+
{ env: 'production', port: 3000 },
|
|
625
|
+
{ env: 'development', port: 4000 },
|
|
626
|
+
{ env: 'test', port: 5000 },
|
|
627
|
+
];
|
|
628
|
+
let portOffset = 0;
|
|
629
|
+
const singleReplicaPortOffsets = {};
|
|
630
|
+
for (const deployIdObj of dataDeploy) {
|
|
631
|
+
const { deployId } = deployIdObj;
|
|
632
|
+
const baseConfPath = fs.existsSync(`./engine-private/replica/${deployId}`)
|
|
633
|
+
? `./engine-private/replica`
|
|
634
|
+
: `./engine-private/conf`;
|
|
635
|
+
|
|
636
|
+
const effectivePortOffset =
|
|
637
|
+
singleReplicaPortOffsets[deployId] !== undefined ? singleReplicaPortOffsets[deployId] : portOffset;
|
|
638
|
+
|
|
639
|
+
for (const envInstanceObj of dataEnv) {
|
|
640
|
+
const envPath = `${baseConfPath}/${deployId}/.env.${envInstanceObj.env}`;
|
|
641
|
+
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
642
|
+
envObj.PORT = `${envInstanceObj.port + effectivePortOffset}`;
|
|
643
|
+
writeEnv(envPath, envObj);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (singleReplicaPortOffsets[deployId] !== undefined) continue;
|
|
647
|
+
|
|
648
|
+
const serverConf = loadReplicas(
|
|
649
|
+
deployId,
|
|
650
|
+
loadConfServerJson(`${baseConfPath}/${deployId}/conf.server.json`),
|
|
651
|
+
);
|
|
652
|
+
for (const host of Object.keys(serverConf)) {
|
|
653
|
+
let deferredSingleReplicaSlots = [];
|
|
654
|
+
for (const path of Object.keys(serverConf[host])) {
|
|
655
|
+
if (serverConf[host][path].singleReplica && serverConf[host][path].replicas) {
|
|
656
|
+
deferredSingleReplicaSlots.push({
|
|
657
|
+
replicas: serverConf[host][path].replicas,
|
|
658
|
+
peer: !!serverConf[host][path].peer,
|
|
659
|
+
});
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
portOffset++;
|
|
663
|
+
if (serverConf[host][path].peer) portOffset++;
|
|
664
|
+
}
|
|
665
|
+
for (const slot of deferredSingleReplicaSlots) {
|
|
666
|
+
for (const replica of slot.replicas) {
|
|
667
|
+
const replicaDeployId = buildReplicaId({ deployId, replica });
|
|
668
|
+
singleReplicaPortOffsets[replicaDeployId] = portOffset;
|
|
669
|
+
portOffset++;
|
|
670
|
+
if (slot.peer) portOffset++;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return resolve(true);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Handle singleReplica operation
|
|
679
|
+
if (options.singleReplica) {
|
|
680
|
+
const replicaPath = path;
|
|
681
|
+
if (!deployId || !host || !replicaPath) {
|
|
682
|
+
logger.error('client --single-replica requires deploy-id, host, and path arguments');
|
|
683
|
+
return reject(false);
|
|
684
|
+
}
|
|
685
|
+
const serverConf = loadReplicas(
|
|
686
|
+
deployId,
|
|
687
|
+
loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`),
|
|
688
|
+
);
|
|
689
|
+
|
|
690
|
+
if (serverConf[host][replicaPath].replicas) {
|
|
691
|
+
{
|
|
692
|
+
let replicaIndex = -1;
|
|
693
|
+
for (const replica of serverConf[host][replicaPath].replicas) {
|
|
694
|
+
replicaIndex++;
|
|
695
|
+
const replicaDeployId = `${deployId}-${serverConf[host][replicaPath].replicas[replicaIndex].slice(1)}`;
|
|
696
|
+
await fs.copy(`./engine-private/conf/${deployId}`, `./engine-private/replica/${replicaDeployId}`);
|
|
697
|
+
fs.writeFileSync(
|
|
698
|
+
`./engine-private/replica/${replicaDeployId}/package.json`,
|
|
699
|
+
fs
|
|
700
|
+
.readFileSync(`./engine-private/replica/${replicaDeployId}/package.json`, 'utf8')
|
|
701
|
+
.replaceAll(`${deployId}`, `${replicaDeployId}`),
|
|
702
|
+
'utf8',
|
|
703
|
+
);
|
|
704
|
+
const replicaFolder = `./engine-private/replica/${replicaDeployId}`;
|
|
705
|
+
for (const envFile of ['.env.production', '.env.development', '.env.test']) {
|
|
706
|
+
const envFilePath = `${replicaFolder}/${envFile}`;
|
|
707
|
+
if (fs.existsSync(envFilePath)) {
|
|
708
|
+
fs.writeFileSync(
|
|
709
|
+
envFilePath,
|
|
710
|
+
fs
|
|
711
|
+
.readFileSync(envFilePath, 'utf8')
|
|
712
|
+
.replaceAll(`DEPLOY_ID=${deployId}`, `DEPLOY_ID=${replicaDeployId}`),
|
|
713
|
+
'utf8',
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
{
|
|
720
|
+
let replicaIndex = -1;
|
|
721
|
+
for (const replica of serverConf[host][replicaPath].replicas) {
|
|
722
|
+
replicaIndex++;
|
|
723
|
+
const replicaDeployId = `${deployId}-${serverConf[host][replicaPath].replicas[replicaIndex].slice(1)}`;
|
|
724
|
+
let replicaServerConf = JSON.parse(
|
|
725
|
+
fs.readFileSync(`./engine-private/replica/${replicaDeployId}/conf.server.json`, 'utf8'),
|
|
726
|
+
);
|
|
727
|
+
|
|
728
|
+
const singleReplicaConf = replicaServerConf[host][replicaPath];
|
|
729
|
+
singleReplicaConf.replicas = undefined;
|
|
730
|
+
singleReplicaConf.singleReplica = undefined;
|
|
731
|
+
|
|
732
|
+
replicaServerConf = {};
|
|
733
|
+
replicaServerConf[host] = {};
|
|
734
|
+
replicaServerConf[host][replica] = singleReplicaConf;
|
|
735
|
+
|
|
736
|
+
fs.writeFileSync(
|
|
737
|
+
`./engine-private/replica/${replicaDeployId}/conf.server.json`,
|
|
738
|
+
JSON.stringify(replicaServerConf, null, 4),
|
|
739
|
+
'utf8',
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return resolve(true);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Handle buildFullClient operation (default)
|
|
748
|
+
{
|
|
749
|
+
const { deployId: resolvedDeployId } = loadConf(deployId, subConf ?? '');
|
|
750
|
+
|
|
751
|
+
let argHost = host ? host.split(',') : [];
|
|
752
|
+
let argPath = path ? path.split(',') : [];
|
|
753
|
+
let deployIdSingleReplicas = [];
|
|
754
|
+
let singleReplicaHosts = [];
|
|
755
|
+
const serverConf = resolvedDeployId
|
|
756
|
+
? readConfJson(resolvedDeployId, 'server', { loadReplicas: true })
|
|
757
|
+
: Config.default.server;
|
|
758
|
+
const confFilePath = resolvedDeployId ? getConfFilePath(resolvedDeployId, 'server') : null;
|
|
759
|
+
const originalConfBackup = confFilePath ? fs.readFileSync(confFilePath, 'utf8') : null;
|
|
760
|
+
for (const host of Object.keys(serverConf)) {
|
|
761
|
+
for (const path of Object.keys(serverConf[host])) {
|
|
762
|
+
if (argHost.length && argPath.length && (!argHost.includes(host) || !argPath.includes(path))) {
|
|
763
|
+
delete serverConf[host][path];
|
|
764
|
+
} else {
|
|
765
|
+
if (serverConf[host][path].singleReplica && serverConf[host][path].replicas) {
|
|
766
|
+
singleReplicaHosts.push({ host, path });
|
|
767
|
+
deployIdSingleReplicas = deployIdSingleReplicas.concat(
|
|
768
|
+
serverConf[host][path].replicas.map((replica) =>
|
|
769
|
+
buildReplicaId({ deployId: resolvedDeployId, replica }),
|
|
770
|
+
),
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
await buildClient({
|
|
777
|
+
buildZip: options.buildZip || false,
|
|
778
|
+
fullBuild: options.liteBuild ? false : true,
|
|
779
|
+
iconsBuild: options.iconsBuild || false,
|
|
780
|
+
});
|
|
781
|
+
for (const replicaDeployId of deployIdSingleReplicas) await Underpost.repo.client(replicaDeployId);
|
|
782
|
+
|
|
783
|
+
return resolve(true);
|
|
784
|
+
}
|
|
785
|
+
} catch (error) {
|
|
786
|
+
console.log(error);
|
|
787
|
+
logger.error(error, error.stack);
|
|
788
|
+
return reject(false);
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
},
|
|
792
|
+
|
|
575
793
|
/**
|
|
576
794
|
* Gets a list of deleted files from a Git repository.
|
|
577
795
|
* @param {string} [path='.'] - The path to the repository.
|
|
@@ -720,25 +938,14 @@ Prevent build private config repo.`,
|
|
|
720
938
|
DefaultConf.client = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
|
|
721
939
|
DefaultConf.server = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
722
940
|
DefaultConf.ssr = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
|
|
723
|
-
// DefaultConf.cron = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.cron.json`, 'utf8'));
|
|
724
|
-
|
|
725
|
-
for (const host of Object.keys(DefaultConf.server)) {
|
|
726
|
-
for (const path of Object.keys(DefaultConf.server[host])) {
|
|
727
|
-
DefaultConf.server[host][path].db = defaultServer.db;
|
|
728
|
-
DefaultConf.server[host][path].mailer = defaultServer.mailer;
|
|
729
|
-
|
|
730
|
-
delete DefaultConf.server[host][path]._wp_client;
|
|
731
|
-
delete DefaultConf.server[host][path]._wp_git;
|
|
732
|
-
delete DefaultConf.server[host][path]._wp_directory;
|
|
733
|
-
delete DefaultConf.server[host][path].wp;
|
|
734
|
-
delete DefaultConf.server[host][path].git;
|
|
735
|
-
delete DefaultConf.server[host][path].directory;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
941
|
} else
|
|
739
942
|
logger.warn(
|
|
740
943
|
`Deploy ID configuration not found: ./engine-private/conf/${deployId}, using default configuration.`,
|
|
741
944
|
);
|
|
945
|
+
|
|
946
|
+
// Serialize the configuration into the conf.*.js manifest file.
|
|
947
|
+
// env: references from JSON configs are preserved as 'env:KEY' strings.
|
|
948
|
+
// At runtime, resolveConfSecrets() in conf.js resolves them via process.env.
|
|
742
949
|
const sepRender = '/**/';
|
|
743
950
|
const confRawPaths = fs.readFileSync('./conf.js', 'utf8').split(sepRender);
|
|
744
951
|
confRawPaths[1] = `${JSON.stringify(DefaultConf)};`;
|
|
@@ -924,6 +1131,82 @@ Prevent build private config repo.`,
|
|
|
924
1131
|
|
|
925
1132
|
return copiedFiles;
|
|
926
1133
|
},
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* Dispatches a GitHub Actions workflow using gh CLI or curl fallback.
|
|
1137
|
+
* @param {object} options - Dispatch options.
|
|
1138
|
+
* @param {string} options.repo - The GitHub repository (e.g., "owner/repo").
|
|
1139
|
+
* @param {string} options.workflowFile - The workflow file name (e.g., "engine-core.cd.yml").
|
|
1140
|
+
* @param {string} [options.ref='master'] - The git ref to dispatch against.
|
|
1141
|
+
* @param {object} [options.inputs={}] - Key-value inputs for the workflow_dispatch event.
|
|
1142
|
+
* @memberof UnderpostRepository
|
|
1143
|
+
*/
|
|
1144
|
+
dispatchWorkflow(options = { repo: '', workflowFile: '', ref: 'master', inputs: {} }) {
|
|
1145
|
+
const { repo, workflowFile, ref, inputs } = options;
|
|
1146
|
+
const ghAvailable = shellExec('command -v gh 2>/dev/null', {
|
|
1147
|
+
stdout: true,
|
|
1148
|
+
silent: true,
|
|
1149
|
+
disableLog: true,
|
|
1150
|
+
}).trim();
|
|
1151
|
+
|
|
1152
|
+
if (ghAvailable) {
|
|
1153
|
+
let cmd = `gh workflow run ${workflowFile} --repo ${repo} --ref ${ref}`;
|
|
1154
|
+
for (const [key, value] of Object.entries(inputs)) {
|
|
1155
|
+
if (value !== undefined && value !== '') {
|
|
1156
|
+
const escaped = String(value).replace(/'/g, "'\\''");
|
|
1157
|
+
cmd += ` -f ${key}='${escaped}'`;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
shellExec(cmd);
|
|
1161
|
+
} else {
|
|
1162
|
+
let token = process.env.GITHUB_TOKEN;
|
|
1163
|
+
if (!token) {
|
|
1164
|
+
const envPath = `${getNpmRootPath()}/underpost/.env`;
|
|
1165
|
+
if (fs.existsSync(envPath) && fs.statSync(envPath).isFile()) {
|
|
1166
|
+
const envVars = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
1167
|
+
token = envVars.GITHUB_TOKEN;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
if (!token) {
|
|
1171
|
+
logger.error('GITHUB_TOKEN is required for workflow dispatch (gh CLI not available)');
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const payload = { ref };
|
|
1175
|
+
if (Object.keys(inputs).length > 0) payload.inputs = inputs;
|
|
1176
|
+
const payloadJson = JSON.stringify(payload).replace(/'/g, "'\\''");
|
|
1177
|
+
shellExec(
|
|
1178
|
+
`curl -s -f -X POST ` +
|
|
1179
|
+
`-H "Accept: application/vnd.github.v3+json" ` +
|
|
1180
|
+
`-H "Authorization: token ${token}" ` +
|
|
1181
|
+
`"https://api.github.com/repos/${repo}/actions/workflows/${workflowFile}/dispatches" ` +
|
|
1182
|
+
`-d '${payloadJson}'`,
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
logger.info('Dispatched workflow', `${repo} -> ${workflowFile}`, inputs.job ? `(job: ${inputs.job})` : '');
|
|
1186
|
+
},
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Sanitizes a markdown changelog string into a compact message format.
|
|
1190
|
+
* Strips date headers, converts section tags to `[tag]` prefixes, removes bullet markers and special characters.
|
|
1191
|
+
* @param {string} message - The raw markdown changelog output.
|
|
1192
|
+
* @returns {string} The sanitized single-line or multi-line compact message.
|
|
1193
|
+
* @memberof UnderpostRepository
|
|
1194
|
+
*/
|
|
1195
|
+
sanitizeChangelogMessage(message) {
|
|
1196
|
+
if (!message) return '';
|
|
1197
|
+
return message
|
|
1198
|
+
.replace(/^##\s+\d{4}-\d{2}-\d{2}\s*/gm, '')
|
|
1199
|
+
.replace(/^###\s+(\S+)\s*/gm, '[$1] ')
|
|
1200
|
+
.replace(/^- /gm, '')
|
|
1201
|
+
.replaceAll('"', '')
|
|
1202
|
+
.replaceAll('`', '')
|
|
1203
|
+
.split('\n')
|
|
1204
|
+
.map((l) => l.trim())
|
|
1205
|
+
.filter(Boolean)
|
|
1206
|
+
.join('\n')
|
|
1207
|
+
.trim()
|
|
1208
|
+
.replaceAll('] - ', '] ');
|
|
1209
|
+
},
|
|
927
1210
|
};
|
|
928
1211
|
}
|
|
929
1212
|
|