underpost 3.1.2 → 3.2.0

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 (98) hide show
  1. package/.env.example +0 -2
  2. package/.github/workflows/ghpkg.ci.yml +4 -4
  3. package/.github/workflows/npmpkg.ci.yml +38 -7
  4. package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -4
  5. package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
  6. package/.github/workflows/release.cd.yml +4 -4
  7. package/CHANGELOG.md +365 -1
  8. package/CLI-HELP.md +55 -3
  9. package/README.md +7 -3
  10. package/bin/build.js +18 -12
  11. package/bin/deploy.js +205 -225
  12. package/bin/file.js +3 -0
  13. package/conf.js +4 -10
  14. package/jsdoc.json +1 -1
  15. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  16. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  17. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  18. package/manifests/deployment/dd-test-development/deployment.yaml +72 -50
  19. package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
  20. package/manifests/deployment/playwright/deployment.yaml +1 -1
  21. package/nodemon.json +1 -1
  22. package/package.json +21 -14
  23. package/scripts/ports-ls.sh +2 -0
  24. package/scripts/rhel-grpc-setup.sh +56 -0
  25. package/src/api/file/file.ref.json +18 -0
  26. package/src/api/user/user.service.js +8 -7
  27. package/src/cli/cluster.js +7 -7
  28. package/src/cli/db.js +76 -242
  29. package/src/cli/deploy.js +104 -65
  30. package/src/cli/env.js +1 -0
  31. package/src/cli/fs.js +2 -1
  32. package/src/cli/index.js +50 -1
  33. package/src/cli/kubectl.js +211 -0
  34. package/src/cli/release.js +284 -0
  35. package/src/cli/repository.js +328 -112
  36. package/src/cli/run.js +283 -69
  37. package/src/cli/test.js +3 -3
  38. package/src/client/Default.index.js +3 -4
  39. package/src/client/components/core/Alert.js +2 -2
  40. package/src/client/components/core/AppStore.js +69 -0
  41. package/src/client/components/core/CalendarCore.js +2 -2
  42. package/src/client/components/core/Docs.js +9 -2
  43. package/src/client/components/core/DropDown.js +129 -17
  44. package/src/client/components/core/Keyboard.js +2 -2
  45. package/src/client/components/core/LogIn.js +2 -2
  46. package/src/client/components/core/LogOut.js +2 -2
  47. package/src/client/components/core/Modal.js +0 -1
  48. package/src/client/components/core/Panel.js +0 -1
  49. package/src/client/components/core/PanelForm.js +19 -19
  50. package/src/client/components/core/RichText.js +1 -2
  51. package/src/client/components/core/SocketIo.js +82 -29
  52. package/src/client/components/core/SocketIoHandler.js +75 -0
  53. package/src/client/components/core/Stream.js +143 -95
  54. package/src/client/components/core/Webhook.js +40 -7
  55. package/src/client/components/default/AppStoreDefault.js +5 -0
  56. package/src/client/components/default/LogInDefault.js +3 -3
  57. package/src/client/components/default/LogOutDefault.js +2 -2
  58. package/src/client/components/default/MenuDefault.js +5 -5
  59. package/src/client/components/default/SocketIoDefault.js +3 -51
  60. package/src/client/services/core/core.service.js +20 -8
  61. package/src/client/services/user/user.management.js +2 -2
  62. package/src/client/ssr/body/404.js +15 -11
  63. package/src/client/ssr/body/500.js +15 -11
  64. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  65. package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
  66. package/src/client/ssr/pages/Test.js +11 -10
  67. package/src/index.js +24 -1
  68. package/src/runtime/express/Express.js +26 -9
  69. package/src/runtime/lampp/Dockerfile +9 -2
  70. package/src/runtime/lampp/Lampp.js +4 -3
  71. package/src/runtime/wp/Dockerfile +64 -0
  72. package/src/runtime/wp/Wp.js +497 -0
  73. package/src/server/auth.js +30 -6
  74. package/src/server/backup.js +19 -1
  75. package/src/server/client-build-docs.js +51 -110
  76. package/src/server/client-build.js +55 -64
  77. package/src/server/client-formatted.js +109 -57
  78. package/src/server/conf.js +19 -15
  79. package/src/server/ipfs-client.js +24 -1
  80. package/src/server/peer.js +8 -0
  81. package/src/server/runtime.js +25 -1
  82. package/src/server/start.js +21 -8
  83. package/src/ws/IoInterface.js +1 -10
  84. package/src/ws/IoServer.js +14 -33
  85. package/src/ws/core/channels/core.ws.chat.js +65 -20
  86. package/src/ws/core/channels/core.ws.mailer.js +113 -32
  87. package/src/ws/core/channels/core.ws.stream.js +90 -31
  88. package/src/ws/core/core.ws.connection.js +12 -33
  89. package/src/ws/core/core.ws.emit.js +10 -26
  90. package/src/ws/core/core.ws.server.js +25 -58
  91. package/src/ws/default/channels/default.ws.main.js +53 -12
  92. package/src/ws/default/default.ws.connection.js +26 -13
  93. package/src/ws/default/default.ws.server.js +30 -12
  94. package/src/client/components/default/ElementsDefault.js +0 -38
  95. package/src/ws/core/management/core.ws.chat.js +0 -8
  96. package/src/ws/core/management/core.ws.mailer.js +0 -16
  97. package/src/ws/core/management/core.ws.stream.js +0 -8
  98. package/src/ws/default/management/default.ws.main.js +0 -8
package/bin/deploy.js CHANGED
@@ -3,7 +3,7 @@ import axios from 'axios';
3
3
 
4
4
  import dotenv from 'dotenv';
5
5
 
6
- import { pbcopy, shellCd, shellExec } from '../src/server/process.js';
6
+ import { pbcopy, shellExec } from '../src/server/process.js';
7
7
  import { loggerFactory } from '../src/server/logger.js';
8
8
  import {
9
9
  addApiConf,
@@ -187,6 +187,7 @@ try {
187
187
  const deployPackage = JSON.parse(fs.readFileSync(filePah, 'utf8'));
188
188
  deployPackage.dependencies = originPackage.dependencies;
189
189
  deployPackage.devDependencies = originPackage.devDependencies;
190
+ deployPackage.overrides = originPackage.overrides;
190
191
  fs.writeFileSync(filePah, JSON.stringify(deployPackage, null, 4), 'utf8');
191
192
  }
192
193
  }
@@ -217,115 +218,6 @@ try {
217
218
  break;
218
219
  }
219
220
 
220
- case 'version-build': {
221
- dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
222
- shellCd(`/home/dd/engine`);
223
- Underpost.repo.clean({ paths: ['/home/dd/engine', '/home/dd/engine/engine-private '] });
224
- shellExec(`node bin pull . ${process.env.GITHUB_USERNAME}/engine`);
225
- shellExec(`node bin run kill 4001`);
226
- shellExec(`node bin run kill 4002`);
227
- shellExec(`node bin run kill 4003`);
228
- shellExec(`npm run update:template`);
229
- shellExec(`cd ../pwa-microservices-template && npm install && npm run build`);
230
- console.log(fs.existsSync(`../pwa-microservices-template/engine-private/conf/dd-default`));
231
- shellExec(`cd ../pwa-microservices-template && ENABLE_FILE_LOGS=true timeout 5s npm run dev`, {
232
- async: true,
233
- });
234
- await timer(5500);
235
- const templateRunnerResult = fs.readFileSync(`../pwa-microservices-template/logs/start.js/all.log`, 'utf8');
236
- logger.info('Test template runner result');
237
- console.log(templateRunnerResult);
238
- if (!templateRunnerResult || templateRunnerResult.toLowerCase().match('error')) {
239
- logger.error('Test template runner result failed');
240
- break;
241
- }
242
- shellCd(`/home/dd/engine`);
243
- Underpost.repo.clean({ paths: ['/home/dd/engine', '/home/dd/engine/engine-private '] });
244
- const originPackageJson = JSON.parse(fs.readFileSync(`package.json`, 'utf8'));
245
- const newVersion = process.argv[3] ?? originPackageJson.version;
246
- const { version } = originPackageJson;
247
- originPackageJson.version = newVersion;
248
- fs.writeFileSync(`package.json`, JSON.stringify(originPackageJson, null, 4), 'utf8');
249
-
250
- const originPackageLockJson = JSON.parse(fs.readFileSync(`package-lock.json`, 'utf8'));
251
- originPackageLockJson.version = newVersion;
252
- originPackageLockJson.packages[''].version = newVersion;
253
- fs.writeFileSync(`package-lock.json`, JSON.stringify(originPackageLockJson, null, 4), 'utf8');
254
-
255
- if (fs.existsSync(`./engine-private/conf`)) {
256
- const files = await fs.readdir(`./engine-private/conf`, { recursive: true });
257
- for (const relativePath of files) {
258
- const filePah = `./engine-private/conf/${relativePath.replaceAll(`\\`, '/')}`;
259
- if (filePah.split('/').pop() === 'package.json') {
260
- const originPackage = JSON.parse(fs.readFileSync(filePah, 'utf8'));
261
- originPackage.version = newVersion;
262
- fs.writeFileSync(filePah, JSON.stringify(originPackage, null, 4), 'utf8');
263
- }
264
- if (filePah.split('/').pop() === 'deployment.yaml') {
265
- fs.writeFileSync(
266
- filePah,
267
- fs
268
- .readFileSync(filePah, 'utf8')
269
- .replaceAll(`v${version}`, `v${newVersion}`)
270
- .replaceAll(`engine.version: ${version}`, `engine.version: ${newVersion}`),
271
- 'utf8',
272
- );
273
- }
274
- }
275
- }
276
-
277
- fs.writeFileSync(
278
- `./manifests/deployment/dd-default-development/deployment.yaml`,
279
- fs
280
- .readFileSync(`./manifests/deployment/dd-default-development/deployment.yaml`, 'utf8')
281
- .replaceAll(`underpost:v${version}`, `underpost:v${newVersion}`),
282
- 'utf8',
283
- );
284
-
285
- if (fs.existsSync(`./.github/workflows/docker-image.ci.yml`))
286
- fs.writeFileSync(
287
- `./.github/workflows/docker-image.ci.yml`,
288
- fs
289
- .readFileSync(`./.github/workflows/docker-image.ci.yml`, 'utf8')
290
- .replaceAll(`underpost-engine:v${version}`, `underpost-engine:v${newVersion}`),
291
- 'utf8',
292
- );
293
-
294
- fs.writeFileSync(
295
- `./src/index.js`,
296
- fs.readFileSync(`./src/index.js`, 'utf8').replaceAll(`${version}`, `${newVersion}`),
297
- 'utf8',
298
- );
299
- shellExec(`node bin/deploy cli-docs ${version} ${newVersion}`);
300
- shellExec(`node bin/deploy update-dependencies`);
301
- shellExec(`node bin/build dd`);
302
- shellExec(`node bin deploy --build-manifest --sync --info-router --replicas 1 dd production`);
303
- shellExec(`node bin deploy --build-manifest --sync --info-router --replicas 1 dd development`);
304
- shellExec(`node bin/deploy build-default-confs`);
305
- shellExec(`sudo rm -rf ./engine-private/conf/dd-default`);
306
- shellExec(`node bin new --deploy-id dd-default`);
307
- console.log(fs.existsSync(`./engine-private/conf/dd-default`));
308
- shellExec(`sudo rm -rf ./engine-private/conf/dd-default`);
309
- shellExec(`node bin cron --dev --setup-start`);
310
- shellExec(`node bin cmt --changelog-build`);
311
- process.exit(0);
312
- break;
313
- }
314
-
315
- case 'version-deploy': {
316
- dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
317
- shellExec(
318
- `underpost secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
319
- );
320
- shellExec(`node bin/build dd conf`);
321
- shellExec(`git add . && cd ./engine-private && git add .`);
322
- shellExec(`node bin cmt . ci package-pwa-microservices-template 'New release v:${process.argv[3]}'`);
323
- shellExec(`node bin cmt ./engine-private ci package-pwa-microservices-template`);
324
- shellExec(`node bin push . ${process.env.GITHUB_USERNAME}/engine`);
325
- shellExec(`cd ./engine-private && node ../bin push . ${process.env.GITHUB_USERNAME}/engine-private`);
326
- break;
327
- }
328
-
329
221
  case 'build-default-confs': {
330
222
  for (const deployId of fs
331
223
  .readFileSync(`./engine-private/deploy/dd.router`, 'utf8')
@@ -474,7 +366,10 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
474
366
  `${path}/.env`,
475
367
  fs
476
368
  .readFileSync(`${path}/.env`, 'utf8')
477
- .replace(`FIRST_SUPERUSER=admin@example.com`, `FIRST_SUPERUSER=development@underpost.net`)
369
+ .replace(
370
+ `FIRST_SUPERUSER=admin@example.com`,
371
+ `FIRST_SUPERUSER=${process.env.GITHUB_EMAIL || 'development@underpost.net'}`,
372
+ )
478
373
  .replace(`FIRST_SUPERUSER_PASSWORD=changethis`, `FIRST_SUPERUSER_PASSWORD=${password}`)
479
374
  .replace(`SECRET_KEY=changethis`, `SECRET_KEY=${password}`)
480
375
  .replace(`POSTGRES_DB=app`, `POSTGRES_DB=postgresdb`)
@@ -560,7 +455,7 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
560
455
  shellExec(
561
456
  `sudo kubectl create secret generic ${secretSelector}` +
562
457
  ` --from-file=SECRET_KEY=/home/dd/engine/engine-private/postgresql-password` +
563
- ` --from-literal=FIRST_SUPERUSER=development@underpost.net` +
458
+ ` --from-literal=FIRST_SUPERUSER=${process.env.GITHUB_EMAIL || 'development@underpost.net'}` +
564
459
  ` --from-file=FIRST_SUPERUSER_PASSWORD=/home/dd/engine/engine-private/postgresql-password` +
565
460
  ` --dry-run=client -o yaml | kubectl apply -f - -n ${namespace}`,
566
461
  );
@@ -708,71 +603,6 @@ nvidia/gpu-operator \
708
603
  break;
709
604
  }
710
605
 
711
- case 'udpate-version-files': {
712
- const oldNpmVersion = process.argv[3];
713
- const oldNodeVersion = process.argv[4];
714
- const oldNodeMajorVersion = oldNodeVersion.split('.')[0];
715
- const nodeVersion = shellExec(`node --version`, { stdout: true }).trim().replace('v', '');
716
- const newNodeMajorVersion = nodeVersion.split('.')[0];
717
- const npmVersion = shellExec(`npm --version`, { stdout: true }).trim();
718
-
719
- fs.writeFileSync(
720
- `README.md`,
721
- fs
722
- .readFileSync(`README.md`, 'utf8')
723
- .replaceAll(oldNodeVersion, nodeVersion)
724
- .replaceAll(oldNpmVersion, npmVersion),
725
- );
726
- fs.writeFileSync(
727
- `src/client/public/nexodev/docs/references/Getting started.md`,
728
- fs
729
- .readFileSync(`src/client/public/nexodev/docs/references/Getting started.md`, 'utf8')
730
- .replaceAll(oldNodeVersion, nodeVersion)
731
- .replaceAll(oldNpmVersion, npmVersion),
732
- );
733
-
734
- const workflowFiles = [
735
- `./.github/workflows/coverall.ci.yml`,
736
-
737
- `./.github/workflows/engine-core.ci.yml`,
738
-
739
- `./.github/workflows/engine-cyberia.ci.yml`,
740
-
741
- `./.github/workflows/engine-lampp.ci.yml`,
742
-
743
- `./.github/workflows/engine-test.ci.yml`,
744
-
745
- `./.github/workflows/ghpkg.ci.yml`,
746
-
747
- `./.github/workflows/npmpkg.ci.yml`,
748
-
749
- `./.github/workflows/publish.ci.yml`,
750
-
751
- `./.github/workflows/pwa-microservices-template-page.cd.yml`,
752
-
753
- `./.github/workflows/pwa-microservices-template-test.ci.yml`,
754
-
755
- `./.github/workflows/test-api-rest.cd.yml`,
756
-
757
- `./src/runtime/lampp/Dockerfile`,
758
-
759
- `./Dockerfile`,
760
- ];
761
-
762
- workflowFiles.forEach((file) => {
763
- fs.writeFileSync(
764
- file,
765
- fs
766
- .readFileSync(file, 'utf8')
767
- .replaceAll(oldNodeMajorVersion + '.x', newNodeMajorVersion + '.x')
768
- .replaceAll(oldNodeVersion, nodeVersion)
769
- .replaceAll(oldNpmVersion, npmVersion),
770
- );
771
- });
772
- pbcopy(`nvm alias default v${nodeVersion}`);
773
- break;
774
- }
775
-
776
606
  case 'tls': {
777
607
  fs.mkdirSync(`./engine-private/ssl/localhost`, { recursive: true });
778
608
  const targetDir = `./engine-private/ssl/${process.argv[3] ? process.argv[3] : 'localhost'}`;
@@ -854,6 +684,35 @@ nvidia/gpu-operator \
854
684
  break;
855
685
  }
856
686
 
687
+ case 'sync-conf': {
688
+ const originPackageJson = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
689
+ for (const deployId of ['dd-cron'].concat(
690
+ fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(','),
691
+ )) {
692
+ for (const file of fs.readdirSync(`./engine-private/conf/${deployId}/`)) {
693
+ const deployPackage = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
694
+ deployPackage.overrides = originPackageJson.overrides;
695
+ deployPackage.dependencies = originPackageJson.dependencies;
696
+ fs.writeFileSync(
697
+ `./engine-private/conf/${deployId}/package.json`,
698
+ JSON.stringify(deployPackage, null, 4),
699
+ 'utf8',
700
+ );
701
+ if (file.startsWith('conf.server') && file.endsWith('.json')) {
702
+ const filePath = `./engine-private/conf/${deployId}/${file}`;
703
+ const confObj = JSON.parse(fs.readFileSync(filePath, 'utf8'));
704
+ for (const host of Object.keys(confObj)) {
705
+ for (const path of Object.keys(confObj[host])) {
706
+ }
707
+ }
708
+ // fs.writeFileSync(filePath, JSON.stringify(confObj, null, 4), 'utf8');
709
+ logger.info(`sync-conf`, { deployId, file });
710
+ }
711
+ }
712
+ }
713
+ break;
714
+ }
715
+
857
716
  case 'cyberia': {
858
717
  const { CyberiaDependencies } = await import(`../src/client/components/cyberia-portal/CommonCyberiaPortal.js`);
859
718
  for (const dep of Object.keys(CyberiaDependencies)) {
@@ -863,43 +722,6 @@ nvidia/gpu-operator \
863
722
  break;
864
723
  }
865
724
 
866
- case 'cyberia-hardhat': {
867
- shellExec(`cd ./hardhat && npm install --include=dev`);
868
- break;
869
- }
870
-
871
- case 'cyberia-docs': {
872
- // Copy custom cyberia jsdoc to project root for docs build
873
- const cyberiaJsDocPath = `./jsdoc.dd-cyberia.json`;
874
- if (fs.existsSync(cyberiaJsDocPath)) {
875
- logger.info('copying custom cyberia jsdoc.json to project root');
876
- fs.copySync(cyberiaJsDocPath, `./jsdoc.json`);
877
- }
878
-
879
- // Generate hardhat coverage report for docs inclusion
880
- if (fs.existsSync(`./hardhat/package.json`)) {
881
- logger.info('generating hardhat coverage report for cyberia docs');
882
- try {
883
- shellExec(`cd ./hardhat && NODE_ENV=development npx hardhat coverage`);
884
- } catch (e) {
885
- logger.warn('hardhat coverage generation failed, continuing', e.message);
886
- }
887
- }
888
-
889
- // Prepare cyberia docs references directory with hardhat README and WHITE-PAPER
890
- const cyberiaDocsRefsDir = `./src/client/public/cyberia/docs/references`;
891
- fs.mkdirSync(cyberiaDocsRefsDir, { recursive: true });
892
- if (fs.existsSync(`./hardhat/README.md`)) {
893
- fs.copySync(`./hardhat/README.md`, `${cyberiaDocsRefsDir}/Hardhat Module.md`);
894
- logger.info('copied hardhat README.md to cyberia docs references');
895
- }
896
- if (fs.existsSync(`./hardhat/WHITE-PAPER.md`)) {
897
- fs.copySync(`./hardhat/WHITE-PAPER.md`, `${cyberiaDocsRefsDir}/White Paper.md`);
898
- logger.info('copied hardhat WHITE-PAPER.md to cyberia docs references');
899
- }
900
- break;
901
- }
902
-
903
725
  case 'pw': {
904
726
  const help = `node bin/deploy pw <script-path> <from-path-in-pod> [to-path-on-local]`;
905
727
  const scriptPath = process.argv[3];
@@ -912,7 +734,7 @@ nvidia/gpu-operator \
912
734
  if (fs.existsSync(toPath)) fs.removeSync(toPath);
913
735
  shellExec(`node bin/deploy pw-conf ${scriptPath}`);
914
736
  shellExec(`kubectl delete deployment playwright-server --ignore-not-found`);
915
- while (Underpost.deploy.get('playwright-server').length > 0) {
737
+ while (Underpost.kubectl.get('playwright-server').length > 0) {
916
738
  logger.info(`Waiting for playwright-server deployment to be deleted...`);
917
739
  await timer(1000);
918
740
  }
@@ -920,13 +742,13 @@ nvidia/gpu-operator \
920
742
  const id = 'playwright-server';
921
743
  await Underpost.test.statusMonitor(id);
922
744
  const nameSpace = 'default';
923
- const [pod] = Underpost.deploy.get(id);
745
+ const [pod] = Underpost.kubectl.get(id);
924
746
  const podName = pod.NAME;
925
747
  shellExec(`kubectl logs -f ${podName} -n ${nameSpace}`, {
926
748
  async: true,
927
749
  });
928
750
  (async () => {
929
- while (!Underpost.deploy.existsContainerFile({ podName, path: fromPath })) {
751
+ while (!Underpost.kubectl.existsFile({ podName, path: fromPath })) {
930
752
  await timer(1000);
931
753
  logger.info(`Waiting for file ${fromPath} in pod ${podName}...`);
932
754
  }
@@ -947,7 +769,8 @@ nvidia/gpu-operator \
947
769
  }
948
770
 
949
771
  case 'dependabot': {
950
- shellExec(`git fetch origin`);
772
+ dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
773
+ shellExec(`git fetch origin --prune`);
951
774
 
952
775
  const { stdout: branchOutput } = shellExec(`git branch -r`, { silent: true });
953
776
  const dependabotBranches = branchOutput
@@ -963,20 +786,177 @@ nvidia/gpu-operator \
963
786
 
964
787
  logger.info('Found dependabot branches:', dependabotBranches);
965
788
 
966
- for (const branch of dependabotBranches) {
967
- logger.info(`Checking out branch: ${branch}`);
968
- shellExec(`git checkout -B ${branch} origin/${branch}`);
789
+ // Stash local changes to prevent checkout/merge conflicts
790
+ const stashResult = shellExec(`git stash --include-untracked`, { silent: true });
791
+ const hasStash = !stashResult.stdout.includes('No local changes to save');
792
+
793
+ // Checkout master
794
+ const checkoutResult = shellExec(`git checkout master`);
795
+ if (checkoutResult.code !== 0) {
796
+ logger.error('Failed to checkout master');
797
+ if (hasStash) shellExec(`git stash pop`);
798
+ break;
969
799
  }
970
800
 
971
- logger.info('Checking out master');
972
- shellExec(`git checkout master`);
801
+ // Pull latest master
802
+ shellExec(`git pull origin master`);
803
+
804
+ // Get repo URI from remote
805
+ const remoteUrl = shellExec(`git config --get remote.origin.url`, { stdout: true, silent: true }).trim();
806
+ const gitUri = remoteUrl.replace(/.*github\.com[:/]/, '').replace(/\.git$/, '');
807
+
808
+ const mergedBranches = [];
809
+ const failedBranches = [];
973
810
 
974
811
  for (const branch of dependabotBranches) {
975
812
  logger.info(`Merging branch: ${branch}`);
976
- shellExec(`git merge ${branch}`);
813
+ const mergeResult = shellExec(`git merge origin/${branch}`);
814
+ if (mergeResult.code === 0) {
815
+ const isAlreadyMerged = mergeResult.stdout && mergeResult.stdout.includes('Already up to date');
816
+ mergedBranches.push({ branch, isAlreadyMerged });
817
+ } else {
818
+ logger.error(`Failed to merge branch: ${branch}`);
819
+ shellExec(`git merge --abort`, { silent: true });
820
+ failedBranches.push(branch);
821
+ }
822
+ }
823
+
824
+ // Delete merged local and remote branches
825
+ for (const { branch, isAlreadyMerged } of mergedBranches) {
826
+ shellExec(`git branch -D ${branch}`, { silent: true });
827
+ // logger.info(`Deleting remote branch: ${branch}${isAlreadyMerged ? ' (already merged)' : ''}`);
828
+ // shellExec(`git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}.git --delete ${branch}`, {
829
+ // disableLog: true,
830
+ // });
831
+ }
832
+
833
+ // Restore stashed changes
834
+ if (hasStash) shellExec(`git stash pop`);
835
+
836
+ logger.info(
837
+ 'Merged branches:',
838
+ mergedBranches.map((m) => m.branch),
839
+ );
840
+ if (failedBranches.length > 0) logger.warn('Failed branches:', failedBranches);
841
+ logger.info('Dependabot merge completed');
842
+ break;
843
+ }
844
+
845
+ case 'add-api': {
846
+ // node bin/deploy add-api <apiId> <deployId> [clientId] [host]
847
+ // Example: node bin/deploy add-api cyberia-dialogue dd-cyberia cyberia-portal
848
+ // Example: node bin/deploy add-api cyberia-dialogue dd-cyberia cyberia-portal underpost.net
849
+ //
850
+ // Adds an API to server conf files (main + dev variants) and client conf.
851
+ // - conf.server.json: adds apiId to every host/path that has an `apis` array
852
+ // (or only to the specified host if [host] is provided)
853
+ // - conf.server.dev.*.json: same treatment for all dev variants
854
+ // - conf.client.json: adds apiId to the specified clientId's `services` array
855
+ // Idempotent: skips if the API is already present.
856
+
857
+ const apiId = process.argv[3];
858
+ const deployId = process.argv[4];
859
+ const clientId = process.argv[5];
860
+ const targetHost = process.argv[6];
861
+
862
+ if (!apiId || !deployId) {
863
+ logger.error('Usage: node bin/deploy add-api <apiId> <deployId> [clientId] [host]');
864
+ logger.error('Example: node bin/deploy add-api cyberia-dialogue dd-cyberia cyberia-portal');
865
+ logger.error('Example: node bin/deploy add-api cyberia-dialogue dd-cyberia cyberia-portal underpost.net');
866
+ process.exit(1);
867
+ }
868
+
869
+ const confFolder = `./engine-private/conf/${deployId}`;
870
+ if (!fs.existsSync(confFolder)) {
871
+ logger.error(`Config folder not found: ${confFolder}`);
872
+ process.exit(1);
873
+ }
874
+
875
+ // Helper: add apiId to apis[] arrays in a server conf file (idempotent)
876
+ // When targetHost is set, only entries under that host are modified.
877
+ const addApiToServerConf = (filePath) => {
878
+ if (!fs.existsSync(filePath)) return 0;
879
+ const conf = JSON.parse(fs.readFileSync(filePath, 'utf8'));
880
+ let count = 0;
881
+ const hosts = targetHost ? (conf[targetHost] ? [targetHost] : []) : Object.keys(conf);
882
+ for (const host of hosts) {
883
+ for (const path of Object.keys(conf[host])) {
884
+ const entry = conf[host][path];
885
+ if (Array.isArray(entry.apis) && entry.apis.length > 0 && !entry.apis.includes(apiId)) {
886
+ entry.apis.push(apiId);
887
+ count++;
888
+ }
889
+ }
890
+ }
891
+ if (count > 0) {
892
+ fs.writeFileSync(filePath, JSON.stringify(conf, null, 4), 'utf8');
893
+ }
894
+ return count;
895
+ };
896
+
897
+ // 1. Main conf.server.json
898
+ const mainPath = `${confFolder}/conf.server.json`;
899
+ const mainCount = addApiToServerConf(mainPath);
900
+ logger.info(`conf.server.json: added "${apiId}" to ${mainCount} path(s)`);
901
+
902
+ // 2. All dev variants: conf.server.dev.*.json
903
+ const devFiles = fs
904
+ .readdirSync(confFolder)
905
+ .filter((f) => f.startsWith('conf.server.dev.') && f.endsWith('.json'));
906
+ for (const devFile of devFiles) {
907
+ const devPath = `${confFolder}/${devFile}`;
908
+ const devCount = addApiToServerConf(devPath);
909
+ logger.info(`${devFile}: added "${apiId}" to ${devCount} path(s)`);
910
+ }
911
+
912
+ // Helper: add apiId to a client conf file's clientId services (idempotent)
913
+ const addApiToClientConf = (filePath, label) => {
914
+ if (!clientId || !fs.existsSync(filePath)) return;
915
+ const confClient = JSON.parse(fs.readFileSync(filePath, 'utf8'));
916
+ if (confClient[clientId] && Array.isArray(confClient[clientId].services)) {
917
+ if (!confClient[clientId].services.includes(apiId)) {
918
+ confClient[clientId].services.push(apiId);
919
+ fs.writeFileSync(filePath, JSON.stringify(confClient, null, 4), 'utf8');
920
+ logger.info(`${label}: added "${apiId}" to "${clientId}" services`);
921
+ } else {
922
+ logger.info(`${label}: "${apiId}" already in "${clientId}" services`);
923
+ }
924
+ } else {
925
+ logger.warn(`${label}: clientId "${clientId}" not found or has no services array`);
926
+ }
927
+ };
928
+
929
+ // 3. Client conf.client.json
930
+ addApiToClientConf(`${confFolder}/conf.client.json`, 'conf.client.json');
931
+
932
+ // 4. Replicas: engine-private/replica/<deployId>-*
933
+ const replicaBase = './engine-private/replica';
934
+ if (fs.existsSync(replicaBase)) {
935
+ const replicaDirs = fs
936
+ .readdirSync(replicaBase)
937
+ .filter((d) => d.startsWith(`${deployId}-`) && fs.statSync(`${replicaBase}/${d}`).isDirectory());
938
+ for (const replicaDir of replicaDirs) {
939
+ const replicaFolder = `${replicaBase}/${replicaDir}`;
940
+ // Server conf
941
+ const rMainCount = addApiToServerConf(`${replicaFolder}/conf.server.json`);
942
+ logger.info(`replica/${replicaDir}/conf.server.json: added "${apiId}" to ${rMainCount} path(s)`);
943
+ // Dev variants
944
+ const rDevFiles = fs
945
+ .readdirSync(replicaFolder)
946
+ .filter((f) => f.startsWith('conf.server.dev.') && f.endsWith('.json'));
947
+ for (const rDevFile of rDevFiles) {
948
+ const rDevCount = addApiToServerConf(`${replicaFolder}/${rDevFile}`);
949
+ logger.info(`replica/${replicaDir}/${rDevFile}: added "${apiId}" to ${rDevCount} path(s)`);
950
+ }
951
+ // Client conf
952
+ addApiToClientConf(`${replicaFolder}/conf.client.json`, `replica/${replicaDir}/conf.client.json`);
953
+ }
977
954
  }
978
955
 
979
- logger.info('All dependabot branches merged into master');
956
+ // 5. Rebuild default conf
957
+ shellExec(`node bin new --default-conf --deploy-id ${deployId}`);
958
+ logger.info(`Rebuilt default conf for ${deployId}`);
959
+
980
960
  break;
981
961
  }
982
962
  }
package/bin/file.js CHANGED
@@ -99,7 +99,10 @@ try {
99
99
  './src/server/atlas-sprite-sheet-generator.js',
100
100
  './src/server/shape-generator.js',
101
101
  './src/server/semantic-layer-generator.js',
102
+ './src/server/semantic-layer-generator-floor.js',
103
+ './src/server/semantic-layer-generator-skin.js',
102
104
  './src/server/besu-genesis-generator.js',
105
+ './src/grpc/cyberia',
103
106
  './test/shape-generator.test.js',
104
107
  'bin/cyberia.js',
105
108
  ]) {
package/conf.js CHANGED
@@ -63,12 +63,13 @@ const DefaultConf = /**/ {
63
63
  'Pagination',
64
64
  'windowGetDimensions',
65
65
  'SearchBox',
66
+ 'SocketIoHandler',
67
+ 'AppStore',
66
68
  ],
67
69
  default: [
68
70
  'MenuDefault',
69
71
  'RoutesDefault',
70
- 'ElementsDefault',
71
- 'CommonDefault',
72
+ 'AppStoreDefault',
72
73
  'CssDefault',
73
74
  'LogInDefault',
74
75
  'LogOutDefault',
@@ -156,7 +157,7 @@ const DefaultConf = /**/ {
156
157
  ssr: {
157
158
  Default: {
158
159
  head: ['Seo', 'Pwa', 'Css', 'DefaultScripts', 'Production'],
159
- body: ['CacheControl', 'DefaultSplashScreen'],
160
+ body: ['CacheControl', 'DefaultSplashScreen', '404', '500', 'SwaggerDarkMode'],
160
161
  mailer: { userVerifyEmail: 'DefaultVerifyEmail', userRecoverEmail: 'DefaultRecoverEmail' },
161
162
  offline: [
162
163
  { path: '/offline', title: 'No Network Connection', client: 'NoNetworkConnection', head: [], body: [] },
@@ -172,11 +173,6 @@ const DefaultConf = /**/ {
172
173
  runtime: 'nodejs',
173
174
  apis: ['default', 'core', 'user', 'test', 'file', 'document'],
174
175
  origins: [],
175
- minifyBuild: false,
176
- iconsBuild: false,
177
- liteBuild: true,
178
- docsBuild: false,
179
- offlineBuild: false,
180
176
  ws: 'core',
181
177
  peer: true,
182
178
  proxy: [80, 443],
@@ -214,8 +210,6 @@ const DefaultConf = /**/ {
214
210
  runtime: 'nodejs',
215
211
  apis: [],
216
212
  origins: [],
217
- minifyBuild: false,
218
- liteBuild: true,
219
213
  proxy: [80, 443],
220
214
  },
221
215
  },
package/jsdoc.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "search": true,
23
23
  "title": "Nexodev - ERP, CRM Development & Cloud DevOps Services",
24
24
  "homepageTitle": "Docs",
25
- "favicon": "./public/www.nexodev.org/",
25
+ "favicon": "./public/www.nexodev.org/favicon.ico",
26
26
  "displayModuleHeader": true,
27
27
  "includeFilesListInHomepage": true,
28
28
  "sections": ["Namespaces", "Tutorials"],
@@ -23,7 +23,7 @@ spec:
23
23
  spec:
24
24
  containers:
25
25
  - name: dd-cron-backup
26
- image: underpost/underpost-engine:v3.1.2
26
+ image: underpost/underpost-engine:v3.2.0
27
27
  command:
28
28
  - /bin/sh
29
29
  - -c
@@ -23,7 +23,7 @@ spec:
23
23
  spec:
24
24
  containers:
25
25
  - name: dd-cron-dns
26
- image: underpost/underpost-engine:v3.1.2
26
+ image: underpost/underpost-engine:v3.2.0
27
27
  command:
28
28
  - /bin/sh
29
29
  - -c
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-default-development-blue
20
- image: localhost/rockylinux9-underpost:v3.1.2
20
+ image: localhost/rockylinux9-underpost:v3.2.0
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "124Ki"
@@ -100,7 +100,7 @@ spec:
100
100
  spec:
101
101
  containers:
102
102
  - name: dd-default-development-green
103
- image: localhost/rockylinux9-underpost:v3.1.2
103
+ image: localhost/rockylinux9-underpost:v3.2.0
104
104
  # resources:
105
105
  # requests:
106
106
  # memory: "124Ki"