@underpostnet/cyberia 3.2.90 → 3.3.73

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 (490) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +16 -0
  3. package/.github/workflows/coverall.cyberia.ci.yml +107 -0
  4. package/.github/workflows/cyberia-client.cd.yml +6 -18
  5. package/.github/workflows/cyberia-server.cd.yml +6 -18
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +6 -78
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +42 -21
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +2 -9
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +47 -0
  22. package/CHANGELOG.md +581 -2417
  23. package/CLI-HELP.md +416 -127
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +4 -4
  27. package/README.md +21 -1
  28. package/bin/build.js +70 -43
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +372 -135
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +372 -135
  33. package/compose.env +16 -0
  34. package/conf.js +93 -4
  35. package/deploy/cyberia-client/deploy.sh +47 -0
  36. package/deploy/cyberia-client/package.sh +18 -0
  37. package/deploy/cyberia-client/state.sh +14 -0
  38. package/deploy/cyberia-server/deploy.sh +47 -0
  39. package/deploy/cyberia-server/package.sh +18 -0
  40. package/deploy/cyberia-server/state.sh +14 -0
  41. package/deploy/dd-cyberia/deploy.sh +22 -0
  42. package/deploy/dd-cyberia/init.sh +55 -0
  43. package/deploy/dd-cyberia/package.sh +17 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +116 -0
  46. package/deploy/lib/github-actions-logging.sh +594 -0
  47. package/deploy/lib/host.sh +185 -0
  48. package/deploy/lib/state.sh +62 -0
  49. package/deploy/pwa-microservices-template/deploy.sh +45 -0
  50. package/deploy/release/deploy.sh +32 -0
  51. package/deployment.yaml +7 -2
  52. package/docker-compose.yml +31 -37
  53. package/examples/static-page/README.md +19 -19
  54. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  55. package/hardhat/hardhat.config.js +1 -6
  56. package/hardhat/package-lock.json +104 -43
  57. package/hardhat/package.json +3 -3
  58. package/manifests/alertmanager/deployment.yaml +81 -0
  59. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  60. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
  61. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
  62. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  63. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  64. package/manifests/grafana/deployment.yaml +26 -7
  65. package/manifests/grafana/kustomization.yaml +1 -0
  66. package/manifests/grafana/service.yaml +6 -1
  67. package/manifests/mariadb/pv.yaml +1 -0
  68. package/manifests/mongodb/statefulset.yaml +9 -2
  69. package/manifests/mysql/pv-pvc.yaml +14 -1
  70. package/manifests/postgresql/pv.yaml +12 -1
  71. package/manifests/postgresql/pvc.yaml +1 -0
  72. package/manifests/prometheus/deployment.yaml +18 -22
  73. package/package.json +83 -10
  74. package/scripts/audit-selinux.sh +64 -0
  75. package/scripts/event-monitor.sh +56 -0
  76. package/scripts/gpu-diag.sh +0 -0
  77. package/scripts/ip-info.sh +0 -0
  78. package/scripts/k3s-node-setup.sh +30 -14
  79. package/scripts/kubeadm-node-setup.sh +40 -31
  80. package/scripts/lxd-vm-setup.sh +0 -0
  81. package/scripts/maas-nat-firewalld.sh +0 -0
  82. package/scripts/maas-setup.sh +8 -8
  83. package/scripts/nat-iptables.sh +2 -0
  84. package/scripts/rhel-grpc-setup.sh +0 -0
  85. package/scripts/rocky-kickstart.sh +25 -9
  86. package/scripts/selinux-normalize.sh +907 -0
  87. package/scripts/shutdown-machine.sh +843 -0
  88. package/scripts/test-monitor.sh +3 -3
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +1 -1
  99. package/src/api/cyberia-action/cyberia-action.service.js +2 -2
  100. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
  101. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
  102. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
  103. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  104. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  105. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  106. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  107. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  108. package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
  109. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
  110. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
  111. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
  112. package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
  113. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
  114. package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
  115. package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
  116. package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
  117. package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
  118. package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
  119. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  120. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
  121. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  122. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
  123. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  124. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  125. package/src/api/cyberia-map/cyberia-map.service.js +2 -2
  126. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  127. package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
  128. package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
  129. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  130. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  131. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  132. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  133. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  134. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  135. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -29
  136. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  137. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  138. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  139. package/src/api/default/default.controller.js +1 -1
  140. package/src/api/default/default.router.js +1 -1
  141. package/src/api/default/default.service.js +2 -2
  142. package/src/api/document/document.controller.js +1 -1
  143. package/src/api/document/document.router.js +1 -1
  144. package/src/api/document/document.service.js +2 -2
  145. package/src/api/file/file.controller.js +1 -1
  146. package/src/api/file/file.router.js +1 -1
  147. package/src/api/file/file.service.js +2 -2
  148. package/src/api/instance/instance.controller.js +1 -1
  149. package/src/api/instance/instance.router.js +1 -1
  150. package/src/api/instance/instance.service.js +2 -2
  151. package/src/api/ipfs/ipfs.controller.js +1 -1
  152. package/src/api/ipfs/ipfs.router.js +2 -2
  153. package/src/api/ipfs/ipfs.service.js +2 -2
  154. package/src/api/object-layer/object-layer.controller.js +1 -1
  155. package/src/api/object-layer/object-layer.model.js +204 -3
  156. package/src/api/object-layer/object-layer.router.js +2 -2
  157. package/src/api/object-layer/object-layer.service.js +4 -17
  158. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  159. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  160. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  161. package/src/api/test/test.controller.js +1 -1
  162. package/src/api/test/test.service.js +1 -1
  163. package/src/api/user/guest.service.js +3 -3
  164. package/src/api/user/user.controller.js +1 -1
  165. package/src/api/user/user.router.js +2 -2
  166. package/src/api/user/user.service.js +4 -4
  167. package/src/api.js +5 -9
  168. package/src/cli/app.js +391 -0
  169. package/src/cli/baremetal.js +30 -36
  170. package/src/cli/client.js +306 -0
  171. package/src/cli/cloud-init.js +3 -3
  172. package/src/cli/cluster.js +242 -135
  173. package/src/cli/db.js +126 -67
  174. package/src/cli/deploy.js +158 -60
  175. package/src/cli/docker-compose.js +5 -5
  176. package/src/cli/domains.js +184 -0
  177. package/src/cli/dotenv-store.js +143 -0
  178. package/src/cli/event.js +2281 -0
  179. package/src/cli/fs.js +3 -3
  180. package/src/cli/host.js +672 -0
  181. package/src/cli/image.js +4 -7
  182. package/src/cli/index.js +426 -134
  183. package/src/cli/ipfs.js +34 -30
  184. package/src/cli/kickstart.js +1 -1
  185. package/src/cli/kubectl.js +218 -41
  186. package/src/cli/lxd.js +3 -3
  187. package/src/cli/monitor.js +1359 -26
  188. package/src/cli/package.js +90 -0
  189. package/src/cli/release.js +73 -34
  190. package/src/cli/repository.js +564 -367
  191. package/src/cli/run.js +362 -654
  192. package/src/cli/secrets.js +2158 -964
  193. package/src/cli/ssh.js +651 -331
  194. package/src/cli/state.js +394 -0
  195. package/src/cli/static.js +2 -2
  196. package/src/cli/system.js +26 -13
  197. package/src/cli/test.js +199 -125
  198. package/src/cli/vultr.js +623 -0
  199. package/src/cli/wireguard.js +2930 -0
  200. package/src/client/components/core/CalendarCore.js +53 -96
  201. package/src/client/components/core/Docs.js +258 -211
  202. package/src/client/components/core/FileExplorer.js +0 -21
  203. package/src/client/components/core/PanelForm.js +4 -4
  204. package/src/client/components/core/Repository.js +56 -0
  205. package/src/client/components/core/Translate.js +7 -0
  206. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  207. package/src/client/components/core/Wallet.js +0 -11
  208. package/src/client/components/core/Worker.js +7 -1
  209. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  210. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
  211. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
  212. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
  213. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  214. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
  215. package/src/client/components/default/AppShellDefault.js +1 -1
  216. package/src/client/components/default/SettingsDefault.js +2 -2
  217. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  218. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  219. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  220. package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
  221. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
  222. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
  223. package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
  224. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  225. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  226. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  227. package/src/client/public/default/android-chrome-144x144.png +0 -0
  228. package/src/client/public/default/android-chrome-192x192.png +0 -0
  229. package/src/client/public/default/android-chrome-256x256.png +0 -0
  230. package/src/client/public/default/android-chrome-36x36.png +0 -0
  231. package/src/client/public/default/android-chrome-384x384.png +0 -0
  232. package/src/client/public/default/android-chrome-48x48.png +0 -0
  233. package/src/client/public/default/android-chrome-512x512.png +0 -0
  234. package/src/client/public/default/android-chrome-72x72.png +0 -0
  235. package/src/client/public/default/android-chrome-96x96.png +0 -0
  236. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  237. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  238. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  239. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  240. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  241. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  242. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  243. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  244. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  245. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  246. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  247. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  248. package/src/client/public/default/apple-touch-icon.png +0 -0
  249. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  250. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  251. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  252. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  253. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  254. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  255. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  256. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  257. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  258. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  259. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  260. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  261. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  262. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  263. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  264. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  265. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  266. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  267. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  268. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  269. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  270. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  271. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  272. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  273. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  274. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  275. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  276. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  277. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  278. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  279. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  280. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  281. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  282. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  283. package/src/client/public/default/assets/background/white.jpg +0 -0
  284. package/src/client/public/default/browserconfig.xml +1 -1
  285. package/src/client/public/default/favicon-16x16.png +0 -0
  286. package/src/client/public/default/favicon-32x32.png +0 -0
  287. package/src/client/public/default/favicon-48x48.png +0 -0
  288. package/src/client/public/default/favicon.ico +0 -0
  289. package/src/client/public/default/manifest.webmanifest +5 -5
  290. package/src/client/public/default/mstile-144x144.png +0 -0
  291. package/src/client/public/default/mstile-150x150.png +0 -0
  292. package/src/client/public/default/mstile-310x150.png +0 -0
  293. package/src/client/public/default/mstile-310x310.png +0 -0
  294. package/src/client/public/default/mstile-70x70.png +0 -0
  295. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  296. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  297. package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
  298. package/src/client/services/object-layer/object-layer.management.js +4 -4
  299. package/src/client/ssr/RootDocument.js +1 -1
  300. package/src/client/ssr/body/404.js +1 -1
  301. package/src/client/ssr/body/500.js +1 -1
  302. package/src/client/ssr/body/CacheControl.js +1 -1
  303. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  304. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  305. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  306. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  307. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  308. package/src/client/ssr/head/Css.js +1 -1
  309. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  310. package/src/client/ssr/head/DefaultScripts.js +1 -1
  311. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  312. package/src/client/ssr/head/Microdata.js +1 -1
  313. package/src/client/ssr/head/Production.js +1 -1
  314. package/src/client/ssr/head/Pwa.js +1 -1
  315. package/src/client/ssr/head/PwaItemledger.js +1 -1
  316. package/src/client/ssr/head/Seo.js +1 -1
  317. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  318. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  319. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  320. package/src/client/ssr/views/Cyberia404.js +7 -5
  321. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  322. package/src/client/ssr/views/Maintenance.js +1 -1
  323. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  324. package/src/client/ssr/views/Test.js +1 -1
  325. package/src/client/sw/core.sw.js +20 -14
  326. package/src/client-builder/client-build-docs.js +61 -46
  327. package/src/client-builder/client-build-live.js +2 -2
  328. package/src/client-builder/client-build.js +58 -44
  329. package/src/client-builder/client-dev-server.js +3 -3
  330. package/src/client-builder/client-icons.js +2 -2
  331. package/src/client-builder/ssr.js +3 -3
  332. package/src/client.build.js +3 -6
  333. package/src/client.dev.js +3 -6
  334. package/src/db/DataBaseProvider.js +186 -3
  335. package/src/db/mariadb/MariaDB.js +3 -2
  336. package/src/db/mongo/MongoBootstrap.js +273 -101
  337. package/src/db/mongo/MongooseDB.js +11 -8
  338. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  339. package/src/grpc/cyberia/grpc-server.js +1 -1
  340. package/src/index.js +103 -23
  341. package/src/mailer/EmailRender.js +2 -2
  342. package/src/mailer/MailerInterceptor.js +87 -0
  343. package/src/mailer/MailerProvider.js +50 -6
  344. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
  345. package/src/projects/cyberia/besu-genesis-generator.js +3 -3
  346. package/src/projects/cyberia/catalog-cyberia.js +54 -6
  347. package/src/projects/cyberia/gemini-client.js +1 -1
  348. package/src/projects/cyberia/generate-saga.js +15 -24
  349. package/src/projects/cyberia/hot-reload-trigger.js +1 -1
  350. package/src/projects/cyberia/instance-data.js +22 -3
  351. package/src/projects/cyberia/ipfs-client.js +4 -4
  352. package/src/projects/cyberia/map-preview-generator.js +1 -1
  353. package/src/projects/cyberia/object-layer.js +12 -22
  354. package/src/projects/cyberia/semantic-layer-generator.js +1 -1
  355. package/src/projects/underpost/catalog-underpost.js +13 -2
  356. package/src/proxy.js +4 -7
  357. package/src/runtime/cyberia-client/Dockerfile +9 -4
  358. package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
  359. package/src/runtime/cyberia-server/Dockerfile +9 -4
  360. package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
  361. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  362. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  363. package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
  364. package/src/runtime/engine-cyberia/compose.env +16 -0
  365. package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
  366. package/src/runtime/express/Express.js +32 -27
  367. package/src/runtime/lampp/Lampp.js +22 -70
  368. package/src/runtime/nginx/Nginx.js +1 -1
  369. package/src/runtime/wp/Wp.js +16 -48
  370. package/src/server/{catalog.js → build/catalog.js} +15 -5
  371. package/src/server/build/coverage.js +117 -0
  372. package/src/server/build/execution.js +402 -0
  373. package/src/server/build/package.js +465 -0
  374. package/src/server/build/testing.js +528 -0
  375. package/src/server/{dns.js → network/dns.js} +241 -14
  376. package/src/server/network/forward-proxy.js +541 -0
  377. package/src/server/{middlewares.js → network/middlewares.js} +59 -4
  378. package/src/server/network/node-capability.js +98 -0
  379. package/src/server/{peer.js → network/peer.js} +3 -3
  380. package/src/server/{proxy.js → network/proxy.js} +7 -13
  381. package/src/server/network/router.js +356 -0
  382. package/src/server/{tls.js → network/tls.js} +2 -2
  383. package/src/server/network/underpost-compression.js +186 -0
  384. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
  385. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
  386. package/src/server/{cri.js → ops/cri.js} +2 -2
  387. package/src/server/ops/cron.js +949 -0
  388. package/src/server/ops/event-notification.js +284 -0
  389. package/src/server/{logger.js → ops/logger.js} +108 -23
  390. package/src/server/ops/monitoring.js +1724 -0
  391. package/src/server/ops/systemd.js +259 -0
  392. package/src/server/{conf.js → runtime/conf.js} +521 -520
  393. package/src/server/runtime/config-scope.js +215 -0
  394. package/src/server/runtime/environment.js +149 -0
  395. package/src/server/{process.js → runtime/process.js} +153 -13
  396. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  397. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  398. package/src/server/{start.js → runtime/start.js} +128 -39
  399. package/src/server/{auth.js → security/auth.js} +7 -8
  400. package/src/server/security/container-storage.js +382 -0
  401. package/src/server/{crypto.js → security/crypto.js} +1 -1
  402. package/src/server/security/selinux.js +185 -0
  403. package/src/server/{backup.js → storage/backup.js} +17 -8
  404. package/src/server/{data-query.js → storage/data-query.js} +1 -1
  405. package/src/server/{downloader.js → storage/downloader.js} +2 -2
  406. package/src/server/storage/repository.js +68 -0
  407. package/src/server.js +4 -7
  408. package/src/ws/IoInterface.js +1 -1
  409. package/src/ws/IoServer.js +1 -1
  410. package/src/ws/core/core.ws.connection.js +1 -1
  411. package/src/ws/core/core.ws.emit.js +1 -1
  412. package/src/ws/core/core.ws.server.js +1 -1
  413. package/src/ws/default/default.ws.connection.js +1 -1
  414. package/src/ws/default/default.ws.emit.js +1 -1
  415. package/src/ws/default/default.ws.server.js +1 -1
  416. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  417. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  418. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  419. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  420. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
  421. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
  422. package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
  423. package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
  424. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  425. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  426. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  427. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  428. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  429. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  430. package/test/integration/infra/1-security/selinux.test.js +69 -0
  431. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  432. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  433. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  434. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  435. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  436. package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
  437. package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
  438. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  439. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  440. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  441. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  442. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  443. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  444. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +47 -6
  445. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -4
  446. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  447. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  448. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  449. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  450. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  451. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  452. package/test/support/shell-harness.js +73 -0
  453. package/test/unit/build-template.test.js +97 -0
  454. package/test/unit/build-workflow-offline.test.js +132 -0
  455. package/test/unit/catalog.test.js +71 -0
  456. package/test/unit/client-build-docs.test.js +334 -0
  457. package/test/unit/conf-loading.test.js +303 -0
  458. package/test/unit/conf-resolution.test.js +979 -0
  459. package/test/unit/coverage-artifact.test.js +130 -0
  460. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  461. package/test/unit/deploy-env-resolution.test.js +38 -0
  462. package/test/unit/deploy-log-table.test.js +447 -0
  463. package/test/unit/execution-profiles.test.js +219 -0
  464. package/test/unit/fleet-sync-source.test.js +149 -0
  465. package/test/unit/logger-redaction.test.js +112 -0
  466. package/test/unit/package.test.js +403 -0
  467. package/test/unit/prepare-host.test.js +299 -0
  468. package/test/unit/process-environment.test.js +18 -0
  469. package/test/unit/propagation-message.test.js +78 -0
  470. package/test/unit/redeploy-plan.test.js +24 -0
  471. package/test/unit/release-bump.test.js +474 -0
  472. package/test/unit/ssh-output-redaction.test.js +28 -0
  473. package/test/unit/start-options.test.js +46 -0
  474. package/test/unit/test-tiers.test.js +193 -0
  475. package/vitest.config.js +58 -0
  476. package/.nycrc +0 -9
  477. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  478. package/manifests/mongodb/pv-pvc.yaml +0 -59
  479. package/scripts/link-local-underpost-cli.sh +0 -6
  480. package/src/api/user/user.build.js +0 -16
  481. package/src/cli/env.js +0 -177
  482. package/src/client/components/core/Blockchain.js +0 -41
  483. package/src/client/components/core/Blog.js +0 -9
  484. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  485. package/src/client/public/default/assets/background/dark.jpg +0 -0
  486. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  487. package/src/client/public/default/assets/background/white0.jpg +0 -0
  488. package/src/client/public/doc/favicon.ico +0 -0
  489. package/src/client/public/doc/sitemap +0 -148
  490. package/src/server/cron.js +0 -476
package/src/cli/db.js CHANGED
@@ -6,12 +6,20 @@
6
6
  * Supports MariaDB and MongoDB with import/export capabilities, Git integration, and multi-pod operations.
7
7
  */
8
8
 
9
- import { mergeFile, splitFileFactory, loadConfServerJson, resolveConfSecrets, loadConfInstances } from '../server/conf.js';
10
- import { loggerFactory } from '../server/logger.js';
11
- import { shellExec } from '../server/process.js';
9
+ import {
10
+ loadConfInstances,
11
+ loadConfServerJson,
12
+ loadReplicas,
13
+ mergeFile,
14
+ splitFileFactory,
15
+ } from '../server/runtime/conf.js';
16
+ import { pathPortAssignmentFactory } from '../server/network/router.js';
17
+ import { loggerFactory } from '../server/ops/logger.js';
18
+ import { shellExec } from '../server/runtime/process.js';
19
+ import { cli } from '../server/build/execution.js';
12
20
  import fs from 'fs-extra';
13
21
  import { DataBaseProviderService } from '../db/DataBaseProvider.js';
14
- import { loadReplicas, pathPortAssignmentFactory, loadCronDeployEnv } from '../server/conf.js';
22
+ import { loadCronDeployEnv } from '../server/ops/cron.js';
15
23
  import { MongoBootstrap } from '../db/mongo/MongoBootstrap.js';
16
24
  import Underpost from '../index.js';
17
25
  import { timer } from '../client/components/core/CommonJs.js';
@@ -120,6 +128,11 @@ class UnderpostDB {
120
128
 
121
129
  logger.info('Importing MariaDB database', { podName, dbName });
122
130
 
131
+ if (!Underpost.kubectl.ensureExecReady({ podName, namespace })) {
132
+ logger.error('Pod is not accepting exec streams, skipping import', { podName, dbName });
133
+ return false;
134
+ }
135
+
123
136
  // Always ensure the database exists first — required for WP even when no backup is available
124
137
  Underpost.kubectl.run(
125
138
  `kubectl exec -n ${namespace} -i ${podName} -- mariadb -p${password} -e 'CREATE DATABASE IF NOT EXISTS ${dbName};'`,
@@ -151,9 +164,10 @@ class UnderpostDB {
151
164
  return false;
152
165
  }
153
166
 
154
- // Import SQL file
167
+ // Import SQL file. No retry: a replayed import would re-apply whatever the
168
+ // first attempt already wrote.
155
169
  const importCmd = `mariadb -u ${user} -p${password} ${dbName} < ${containerSqlPath}`;
156
- Underpost.kubectl.exec({ podName, namespace, command: importCmd });
170
+ Underpost.kubectl.exec({ podName, namespace, command: importCmd, retries: 0 });
157
171
 
158
172
  logger.info('Successfully imported MariaDB database', { podName, dbName });
159
173
  return true;
@@ -183,6 +197,11 @@ class UnderpostDB {
183
197
 
184
198
  logger.info('Exporting MariaDB database', { podName, dbName });
185
199
 
200
+ if (!Underpost.kubectl.ensureExecReady({ podName, namespace })) {
201
+ logger.error('Pod is not accepting exec streams, skipping export', { podName, dbName });
202
+ return false;
203
+ }
204
+
186
205
  // Remove existing SQL file in container
187
206
  Underpost.kubectl.exec({
188
207
  podName,
@@ -230,12 +249,22 @@ class UnderpostDB {
230
249
  * @param {string} params.bsonPath - BSON directory path.
231
250
  * @param {boolean} params.drop - Whether to drop existing database.
232
251
  * @param {boolean} params.preserveUUID - Whether to preserve UUIDs.
233
- * @param {string} [params.user=''] - MongoDB username for authenticated restore.
234
- * @param {string} [params.password=''] - MongoDB password for authenticated restore.
235
- * @param {string} [params.authDatabase='admin'] - Auth database for restore command.
252
+ * @param {string} [params.user=''] - MongoDB username for authenticated restore.
253
+ * @param {string} [params.password=''] - MongoDB password for authenticated restore.
254
+ * @param {string} [params.authDatabase='admin'] - Auth database for restore command.
236
255
  * @return {boolean} Success status.
237
256
  */
238
- _importMongoDB({ pod, namespace, dbName, bsonPath, drop, preserveUUID, user = '', password = '', authDatabase = 'admin' }) {
257
+ _importMongoDB({
258
+ pod,
259
+ namespace,
260
+ dbName,
261
+ bsonPath,
262
+ drop,
263
+ preserveUUID,
264
+ user = '',
265
+ password = '',
266
+ authDatabase = 'admin',
267
+ }) {
239
268
  try {
240
269
  const podName = pod.NAME;
241
270
  const containerBsonPath = `/${dbName}`;
@@ -252,6 +281,11 @@ class UnderpostDB {
252
281
  return true;
253
282
  }
254
283
 
284
+ if (!Underpost.kubectl.ensureExecReady({ podName, namespace })) {
285
+ logger.error('Pod is not accepting exec streams, skipping import', { podName, dbName });
286
+ return false;
287
+ }
288
+
255
289
  // Remove existing BSON directory in container
256
290
  Underpost.kubectl.exec({
257
291
  podName,
@@ -272,11 +306,14 @@ class UnderpostDB {
272
306
  }
273
307
 
274
308
  // Restore database
275
- const authFlags = user && password
276
- ? ` --username ${JSON.stringify(user)} --password ${JSON.stringify(password)} --authenticationDatabase ${JSON.stringify(authDatabase)}`
277
- : '';
309
+ const authFlags =
310
+ user && password
311
+ ? ` --username ${JSON.stringify(user)} --password ${JSON.stringify(password)} --authenticationDatabase ${JSON.stringify(authDatabase)}`
312
+ : '';
278
313
  const restoreCmd = `mongorestore -d ${dbName} ${containerBsonPath} --numParallelCollections=1 --numInsertionWorkersPerCollection=1 --batchSize=100 --stopOnError${drop ? ' --drop' : ''}${preserveUUID ? ' --preserveUUID' : ''}${authFlags}`;
279
- Underpost.kubectl.exec({ podName, namespace, command: restoreCmd });
314
+ // Only a `--drop` restore is idempotent; without it a replay would re-apply
315
+ // whatever the interrupted attempt already inserted, so it runs exactly once.
316
+ Underpost.kubectl.exec({ podName, namespace, command: restoreCmd, retries: drop ? undefined : 0 });
280
317
 
281
318
  logger.info('Successfully imported MongoDB database', { podName, dbName });
282
319
  return true;
@@ -296,18 +333,32 @@ class UnderpostDB {
296
333
  * @param {string} params.dbName - Database name.
297
334
  * @param {string} params.outputPath - Output directory path.
298
335
  * @param {string} [params.collections=''] - Comma-separated collection list.
299
- * @param {string} [params.user=''] - MongoDB username for authenticated dump.
300
- * @param {string} [params.password=''] - MongoDB password for authenticated dump.
301
- * @param {string} [params.authDatabase='admin'] - Auth database for dump command.
336
+ * @param {string} [params.user=''] - MongoDB username for authenticated dump.
337
+ * @param {string} [params.password=''] - MongoDB password for authenticated dump.
338
+ * @param {string} [params.authDatabase='admin'] - Auth database for dump command.
302
339
  * @return {boolean} Success status.
303
340
  */
304
- _exportMongoDB({ pod, namespace, dbName, outputPath, collections = '', user = '', password = '', authDatabase = 'admin' }) {
341
+ _exportMongoDB({
342
+ pod,
343
+ namespace,
344
+ dbName,
345
+ outputPath,
346
+ collections = '',
347
+ user = '',
348
+ password = '',
349
+ authDatabase = 'admin',
350
+ }) {
305
351
  try {
306
352
  const podName = pod.NAME;
307
353
  const containerBsonPath = `/${dbName}`;
308
354
 
309
355
  logger.info('Exporting MongoDB database', { podName, dbName, collections });
310
356
 
357
+ if (!Underpost.kubectl.ensureExecReady({ podName, namespace })) {
358
+ logger.error('Pod is not accepting exec streams, skipping export', { podName, dbName });
359
+ return false;
360
+ }
361
+
311
362
  // Remove existing BSON directory in container
312
363
  Underpost.kubectl.exec({
313
364
  podName,
@@ -316,19 +367,26 @@ class UnderpostDB {
316
367
  });
317
368
 
318
369
  // Dump database or specific collections
319
- const authFlags = user && password
320
- ? ` --username ${JSON.stringify(user)} --password ${JSON.stringify(password)} --authenticationDatabase ${JSON.stringify(authDatabase)}`
321
- : '';
370
+ const authFlags =
371
+ user && password
372
+ ? ` --username ${JSON.stringify(user)} --password ${JSON.stringify(password)} --authenticationDatabase ${JSON.stringify(authDatabase)}`
373
+ : '';
374
+
375
+ // Serial dump: mongodump defaults to 4 collections at once, and its buffers share the
376
+ // mongod container's memory limit. Parallel dumping is what pushes the container over
377
+ // that limit and gets it OOM-killed mid-backup.
378
+ const dumpFlags = ` -o / --numParallelCollections=1${authFlags}`;
322
379
 
323
380
  if (collections) {
324
- const collectionList = collections.split(',').map((c) => c.trim());
325
- for (const collection of collectionList) {
326
- const dumpCmd = `mongodump -d ${dbName} --collection ${collection} -o /${authFlags}`;
327
- Underpost.kubectl.exec({ podName, namespace, command: dumpCmd });
381
+ for (const collection of collections.split(',').map((c) => c.trim())) {
382
+ Underpost.kubectl.exec({
383
+ podName,
384
+ namespace,
385
+ command: `mongodump -d ${dbName} --collection ${collection}${dumpFlags}`,
386
+ });
328
387
  }
329
388
  } else {
330
- const dumpCmd = `mongodump -d ${dbName} -o /${authFlags}`;
331
- Underpost.kubectl.exec({ podName, namespace, command: dumpCmd });
389
+ Underpost.kubectl.exec({ podName, namespace, command: `mongodump -d ${dbName}${dumpFlags}` });
332
390
  }
333
391
 
334
392
  // Copy BSON directory from pod
@@ -359,9 +417,9 @@ class UnderpostDB {
359
417
  * @param {string} params.podName - Pod name.
360
418
  * @param {string} params.namespace - Namespace.
361
419
  * @param {string} params.dbName - Database name.
362
- * @param {string} [params.user=''] - MongoDB username for authenticated stats query.
363
- * @param {string} [params.password=''] - MongoDB password for authenticated stats query.
364
- * @param {string} [params.authDatabase='admin'] - Auth database for stats query.
420
+ * @param {string} [params.user=''] - MongoDB username for authenticated stats query.
421
+ * @param {string} [params.password=''] - MongoDB password for authenticated stats query.
422
+ * @param {string} [params.authDatabase='admin'] - Auth database for stats query.
365
423
  * @return {Object|null} Collection statistics or null on error.
366
424
  */
367
425
  _getMongoStats({ podName, namespace, dbName, user = '', password = '', authDatabase = 'admin' }) {
@@ -372,9 +430,10 @@ class UnderpostDB {
372
430
  const script = `db.getSiblingDB('${dbName}').getCollectionNames().map(function(c) { return { collection: c, count: db.getSiblingDB('${dbName}')[c].countDocuments() }; })`;
373
431
 
374
432
  // Execute the script
375
- const authFlags = user && password
376
- ? ` --authenticationDatabase ${JSON.stringify(authDatabase)} -u ${JSON.stringify(user)} -p ${JSON.stringify(password)}`
377
- : '';
433
+ const authFlags =
434
+ user && password
435
+ ? ` --authenticationDatabase ${JSON.stringify(authDatabase)} -u ${JSON.stringify(user)} -p ${JSON.stringify(password)}`
436
+ : '';
378
437
  const command = `sudo kubectl exec -n ${namespace} -i ${podName} -- mongosh --quiet${authFlags} --eval "${script}"`;
379
438
  const output = shellExec(command, { stdout: true, silent: true, silentOnError: true });
380
439
 
@@ -493,8 +552,6 @@ class UnderpostDB {
493
552
  console.log('='.repeat(70) + '\n');
494
553
  },
495
554
 
496
-
497
-
498
555
  /**
499
556
  * Main callback: Initiates database backup workflow.
500
557
  * Orchestrates the backup process for multiple deployments, handling
@@ -517,7 +574,6 @@ class UnderpostDB {
517
574
  * @param {string} [options.paths=''] - Comma-separated list of paths to filter databases.
518
575
  * @param {boolean} [options.allPods=false] - Whether to target all pods in deployment.
519
576
  * @param {boolean} [options.primaryPod=false] - Whether to target MongoDB primary pod only.
520
- * @param {string} [options.primaryPodEnsure=''] - Pod name to ensure MongoDB primary pod is running.
521
577
  * @param {boolean} [options.stats=false] - Whether to display database statistics.
522
578
  * @param {number} [options.macroRollbackExport=1] - Number of commits to rollback in macro export.
523
579
  * @param {boolean} [options.forceClone=false] - Whether to force re-clone Git repository.
@@ -546,7 +602,6 @@ class UnderpostDB {
546
602
  paths: '',
547
603
  allPods: false,
548
604
  primaryPod: false,
549
- primaryPodEnsure: '',
550
605
  stats: false,
551
606
  macroRollbackExport: 1,
552
607
  forceClone: false,
@@ -560,14 +615,14 @@ class UnderpostDB {
560
615
  },
561
616
  ) {
562
617
  // Ensure engine-private is available (clone if inside a deployment
563
- // container where globalSecretClean has already removed it).
618
+ // container where globalClean has already removed it).
564
619
  const firstDeployId = deployList !== 'dd' ? deployList.split(',')[0].trim() : '';
565
620
  try {
566
621
  loadCronDeployEnv();
567
622
  const newBackupTimestamp = new Date().getTime();
568
623
  const namespace = options.ns && typeof options.ns === 'string' ? options.ns : 'default';
569
624
 
570
- if (deployList === 'dd') deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
625
+ if (deployList === 'dd') deployList = readDeployRoutes().join(',');
571
626
 
572
627
  // Handle repository backup (git commit+push inside deployment pod)
573
628
  if (options.repoBackup) {
@@ -603,27 +658,13 @@ class UnderpostDB {
603
658
  export: options.export,
604
659
  });
605
660
 
606
- if (options.primaryPodEnsure) {
607
- const primaryPodName = MongoBootstrap.getPrimaryPodName({
608
- namespace,
609
- podName: options.primaryPodEnsure,
610
- username: process.env.MONGODB_USERNAME || process.env.DB_USER || '',
611
- password: process.env.MONGODB_PASSWORD || process.env.DB_PASSWORD || '',
612
- authDatabase: process.env.MONGODB_AUTH_DB || 'admin',
613
- });
614
- if (!primaryPodName) {
615
- const baseCommand = options.dev ? 'node bin' : 'underpost';
616
- const baseClusterCommand = options.dev ? ' --dev' : '';
617
- let clusterFlag = options.k3s ? ' --k3s' : options.kubeadm ? ' --kubeadm' : '';
618
- shellExec(`${baseCommand} cluster${baseClusterCommand}${clusterFlag} --mongodb`);
619
- }
620
- return;
621
- }
622
-
623
661
  // Track processed repositories to avoid duplicate Git operations
624
662
  const processedRepos = new Set();
625
663
  // Track processed host+path combinations to avoid duplicates
626
664
  const processedHostPaths = new Set();
665
+ // Every database that could not be exported/imported, reported at the end so a
666
+ // partial run is never logged as a success.
667
+ const failedOperations = [];
627
668
 
628
669
  for (const _deployId of deployList.split(',')) {
629
670
  const deployId = _deployId.trim();
@@ -796,10 +837,12 @@ class UnderpostDB {
796
837
  logger.warn('No MongoDB pods available to check for primary');
797
838
  podsToProcess = [];
798
839
  } else {
799
- const firstPod = targetPods[0].NAME;
840
+ // Resolved per database, never cached across them: a member that restarts
841
+ // mid-run triggers a re-election, and a stale primary makes every later
842
+ // dump fail with NotPrimaryOrSecondary.
800
843
  const primaryPodName = MongoBootstrap.getPrimaryPodName({
801
844
  namespace,
802
- podName: firstPod,
845
+ podName: targetPods[0].NAME,
803
846
  username: user,
804
847
  password,
805
848
  authDatabase: 'admin',
@@ -851,7 +894,7 @@ class UnderpostDB {
851
894
  }
852
895
 
853
896
  if (options.import === true) {
854
- Underpost.db._importMariaDB({
897
+ const success = Underpost.db._importMariaDB({
855
898
  pod,
856
899
  namespace,
857
900
  dbName,
@@ -859,6 +902,7 @@ class UnderpostDB {
859
902
  password,
860
903
  sqlPath: toSqlPath,
861
904
  });
905
+ if (!success) failedOperations.push({ deployId, provider, dbName, pod: pod.NAME, op: 'import' });
862
906
  }
863
907
 
864
908
  if (options.export === true) {
@@ -872,6 +916,7 @@ class UnderpostDB {
872
916
  outputPath,
873
917
  });
874
918
  exportSucceeded = exportSucceeded || success;
919
+ if (!success) failedOperations.push({ deployId, provider, dbName, pod: pod.NAME, op: 'export' });
875
920
  }
876
921
  break;
877
922
  }
@@ -893,7 +938,7 @@ class UnderpostDB {
893
938
 
894
939
  if (options.import === true) {
895
940
  const bsonPath = options.outPath || toBsonPath;
896
- Underpost.db._importMongoDB({
941
+ const success = Underpost.db._importMongoDB({
897
942
  pod,
898
943
  namespace,
899
944
  dbName,
@@ -904,6 +949,7 @@ class UnderpostDB {
904
949
  password,
905
950
  authDatabase: 'admin',
906
951
  });
952
+ if (!success) failedOperations.push({ deployId, provider, dbName, pod: pod.NAME, op: 'import' });
907
953
  }
908
954
 
909
955
  if (options.export === true) {
@@ -919,6 +965,7 @@ class UnderpostDB {
919
965
  authDatabase: 'admin',
920
966
  });
921
967
  exportSucceeded = exportSucceeded || success;
968
+ if (!success) failedOperations.push({ deployId, provider, dbName, pod: pod.NAME, op: 'export' });
922
969
  }
923
970
  break;
924
971
  }
@@ -949,6 +996,20 @@ class UnderpostDB {
949
996
  }
950
997
  }
951
998
 
999
+ // Whatever succeeded is already committed above — a partial backup still has
1000
+ // value — but the run must not report success, or a silently empty backup set
1001
+ // looks identical to a healthy one.
1002
+ if (failedOperations.length > 0) {
1003
+ logger.error('Database operation completed with failures', {
1004
+ failed: failedOperations.length,
1005
+ operations: failedOperations,
1006
+ });
1007
+ throw new Error(
1008
+ `Database operation failed for ${failedOperations.length} database(s): ` +
1009
+ failedOperations.map(({ deployId, dbName, op }) => `${deployId}/${dbName} (${op})`).join(', '),
1010
+ );
1011
+ }
1012
+
952
1013
  logger.info('Database operation completed successfully');
953
1014
  } catch (error) {
954
1015
  logger.error('Database operation failed', { error: error.message });
@@ -1022,15 +1083,13 @@ class UnderpostDB {
1022
1083
  logger.info('Creating cluster metadata', { deployId, host, path });
1023
1084
 
1024
1085
  const env = 'production';
1025
- const deployListPath = './engine-private/deploy/dd.router';
1086
+ const deployList = readDeployRoutes();
1026
1087
 
1027
- if (!fs.existsSync(deployListPath)) {
1028
- logger.error('Deploy router file not found', { path: deployListPath });
1029
- throw new Error(`Deploy router file not found: ${deployListPath}`);
1088
+ if (deployList.length === 0) {
1089
+ logger.error('Deploy route table not found', { path: DEPLOY_ROUTES_PATH });
1090
+ throw new Error(`Deploy route table not found: ${DEPLOY_ROUTES_PATH}`);
1030
1091
  }
1031
1092
 
1032
- const deployList = fs.readFileSync(deployListPath, 'utf8').split(',');
1033
-
1034
1093
  const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
1035
1094
  if (!fs.existsSync(confServerPath)) {
1036
1095
  logger.error('Server configuration not found', { path: confServerPath });
@@ -1216,7 +1275,7 @@ class UnderpostDB {
1216
1275
  const firstDeployId = deployList !== 'dd' ? deployList.split(',')[0].trim() : '';
1217
1276
  try {
1218
1277
  loadCronDeployEnv();
1219
- if (deployList === 'dd') deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
1278
+ if (deployList === 'dd') deployList = readDeployRoutes().join(',');
1220
1279
 
1221
1280
  logger.info('Starting File collection cleanup', { deployList, options });
1222
1281