cyberia 3.1.3 → 3.2.9

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 (377) hide show
  1. package/.env.example +0 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +10 -8
  3. package/.github/workflows/engine-cyberia.ci.yml +12 -29
  4. package/.github/workflows/ghpkg.ci.yml +4 -4
  5. package/.github/workflows/npmpkg.ci.yml +28 -11
  6. package/.github/workflows/publish.ci.yml +21 -2
  7. package/.github/workflows/pwa-microservices-template-page.cd.yml +4 -5
  8. package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
  9. package/.github/workflows/release.cd.yml +14 -10
  10. package/CHANGELOG.md +783 -1
  11. package/CLI-HELP.md +95 -18
  12. package/Dockerfile +0 -2
  13. package/README.md +290 -220
  14. package/bin/build.js +24 -7
  15. package/bin/cyberia.js +2838 -252
  16. package/bin/deploy.js +747 -125
  17. package/bin/file.js +9 -0
  18. package/bin/index.js +2838 -252
  19. package/bin/vs.js +1 -1
  20. package/conf.js +99 -65
  21. package/deployment.yaml +18 -164
  22. package/hardhat/hardhat.config.js +13 -13
  23. package/hardhat/ignition/modules/ObjectLayerToken.js +1 -1
  24. package/hardhat/package-lock.json +2559 -5864
  25. package/hardhat/package.json +14 -23
  26. package/hardhat/scripts/deployObjectLayerToken.js +1 -1
  27. package/hardhat/test/ObjectLayerToken.js +4 -2
  28. package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
  29. package/hardhat/types/ethers-contracts/common.ts +92 -0
  30. package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
  31. package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
  32. package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
  33. package/hardhat/types/ethers-contracts/index.ts +6 -0
  34. package/jsconfig.json +1 -1
  35. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +6 -5
  36. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +6 -5
  37. package/manifests/deployment/dd-cyberia-development/deployment.yaml +18 -164
  38. package/manifests/deployment/dd-cyberia-development/proxy.yaml +7 -79
  39. package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
  40. package/manifests/deployment/dd-test-development/deployment.yaml +112 -28
  41. package/manifests/deployment/dd-test-development/proxy.yaml +46 -1
  42. package/manifests/deployment/playwright/deployment.yaml +1 -1
  43. package/nodemon.json +1 -1
  44. package/package.json +39 -24
  45. package/proxy.yaml +7 -79
  46. package/scripts/k3s-node-setup.sh +2 -2
  47. package/scripts/nat-iptables.sh +103 -18
  48. package/scripts/rhel-grpc-setup.sh +56 -0
  49. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +58 -14
  50. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +23 -14
  51. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
  52. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +148 -20
  53. package/src/api/core/core.controller.js +10 -10
  54. package/src/api/core/core.service.js +10 -10
  55. package/src/api/crypto/crypto.controller.js +8 -8
  56. package/src/api/crypto/crypto.service.js +8 -8
  57. package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
  58. package/src/api/cyberia-action/cyberia-action.model.js +87 -0
  59. package/src/api/cyberia-action/cyberia-action.router.js +27 -0
  60. package/src/api/cyberia-action/cyberia-action.service.js +42 -0
  61. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
  62. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
  63. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
  64. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
  65. package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
  66. package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
  67. package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
  68. package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
  69. package/src/api/cyberia-instance/cyberia-fallback-world.js +178 -0
  70. package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
  71. package/src/api/cyberia-instance/cyberia-instance.model.js +87 -0
  72. package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
  73. package/src/api/cyberia-instance/cyberia-instance.service.js +156 -0
  74. package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
  75. package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
  76. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
  77. package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +574 -0
  78. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +231 -0
  79. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
  80. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
  81. package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
  82. package/src/api/cyberia-map/cyberia-map.model.js +30 -0
  83. package/src/api/cyberia-map/cyberia-map.router.js +40 -0
  84. package/src/api/cyberia-map/cyberia-map.service.js +74 -0
  85. package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
  86. package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
  87. package/src/api/cyberia-quest/cyberia-quest.router.js +27 -0
  88. package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
  89. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
  90. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
  91. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +27 -0
  92. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
  93. package/src/api/default/default.controller.js +10 -10
  94. package/src/api/default/default.service.js +10 -10
  95. package/src/api/document/document.controller.js +12 -12
  96. package/src/api/document/document.model.js +10 -16
  97. package/src/api/file/file.controller.js +8 -8
  98. package/src/api/file/file.model.js +10 -10
  99. package/src/api/file/file.ref.json +18 -0
  100. package/src/api/file/file.service.js +36 -36
  101. package/src/api/instance/instance.controller.js +10 -10
  102. package/src/api/instance/instance.model.js +4 -10
  103. package/src/api/instance/instance.service.js +10 -10
  104. package/src/api/ipfs/ipfs.controller.js +15 -36
  105. package/src/api/ipfs/ipfs.model.js +47 -47
  106. package/src/api/ipfs/ipfs.router.js +8 -13
  107. package/src/api/ipfs/ipfs.service.js +67 -129
  108. package/src/api/object-layer/object-layer.controller.js +12 -12
  109. package/src/api/object-layer/object-layer.model.js +4 -17
  110. package/src/api/object-layer/object-layer.router.js +30 -0
  111. package/src/api/object-layer/object-layer.service.js +126 -43
  112. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
  113. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
  114. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +18 -14
  115. package/src/api/test/test.controller.js +8 -8
  116. package/src/api/test/test.service.js +8 -8
  117. package/src/api/user/guest.service.js +99 -0
  118. package/src/api/user/user.controller.js +6 -6
  119. package/src/api/user/user.model.js +8 -13
  120. package/src/api/user/user.service.js +11 -27
  121. package/src/cli/cluster.js +68 -21
  122. package/src/cli/db.js +753 -825
  123. package/src/cli/deploy.js +215 -125
  124. package/src/cli/env.js +29 -0
  125. package/src/cli/fs.js +82 -8
  126. package/src/cli/image.js +43 -1
  127. package/src/cli/index.js +74 -3
  128. package/src/cli/kubectl.js +211 -0
  129. package/src/cli/release.js +340 -0
  130. package/src/cli/repository.js +475 -74
  131. package/src/cli/run.js +582 -43
  132. package/src/cli/secrets.js +73 -0
  133. package/src/cli/ssh.js +1 -1
  134. package/src/cli/static.js +43 -115
  135. package/src/cli/test.js +3 -3
  136. package/src/client/Cryptokoyn.index.js +18 -22
  137. package/src/client/CyberiaPortal.index.js +19 -24
  138. package/src/client/Default.index.js +21 -34
  139. package/src/client/Itemledger.index.js +20 -27
  140. package/src/client/Underpost.index.js +19 -24
  141. package/src/client/components/core/404.js +4 -4
  142. package/src/client/components/core/500.js +4 -4
  143. package/src/client/components/core/Account.js +73 -60
  144. package/src/client/components/core/AgGrid.js +23 -33
  145. package/src/client/components/core/Alert.js +12 -13
  146. package/src/client/components/core/AppStore.js +69 -0
  147. package/src/client/components/core/Auth.js +35 -37
  148. package/src/client/components/core/Badge.js +7 -13
  149. package/src/client/components/core/BtnIcon.js +15 -17
  150. package/src/client/components/core/CalendarCore.js +43 -64
  151. package/src/client/components/core/Chat.js +13 -15
  152. package/src/client/components/core/ClientEvents.js +87 -0
  153. package/src/client/components/core/ColorPaletteElement.js +309 -0
  154. package/src/client/components/core/Content.js +17 -14
  155. package/src/client/components/core/Css.js +15 -71
  156. package/src/client/components/core/CssCore.js +12 -16
  157. package/src/client/components/core/D3Chart.js +4 -4
  158. package/src/client/components/core/Docs.js +64 -91
  159. package/src/client/components/core/DropDown.js +194 -96
  160. package/src/client/components/core/EventBus.js +92 -0
  161. package/src/client/components/core/EventsUI.js +14 -17
  162. package/src/client/components/core/FileExplorer.js +96 -228
  163. package/src/client/components/core/FullScreen.js +47 -75
  164. package/src/client/components/core/Input.js +24 -69
  165. package/src/client/components/core/Keyboard.js +26 -19
  166. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  167. package/src/client/components/core/LoadingAnimation.js +25 -31
  168. package/src/client/components/core/LogIn.js +43 -43
  169. package/src/client/components/core/LogOut.js +25 -16
  170. package/src/client/components/core/Modal.js +462 -179
  171. package/src/client/components/core/NotificationManager.js +14 -18
  172. package/src/client/components/core/Panel.js +54 -51
  173. package/src/client/components/core/PanelForm.js +44 -144
  174. package/src/client/components/core/Polyhedron.js +110 -214
  175. package/src/client/components/core/PublicProfile.js +39 -32
  176. package/src/client/components/core/Recover.js +48 -44
  177. package/src/client/components/core/Responsive.js +88 -32
  178. package/src/client/components/core/RichText.js +9 -18
  179. package/src/client/components/core/Router.js +24 -3
  180. package/src/client/components/core/SearchBox.js +37 -37
  181. package/src/client/components/core/SignUp.js +39 -30
  182. package/src/client/components/core/SocketIo.js +112 -30
  183. package/src/client/components/core/SocketIoHandler.js +75 -0
  184. package/src/client/components/core/Stream.js +143 -95
  185. package/src/client/components/core/ToggleSwitch.js +8 -20
  186. package/src/client/components/core/ToolTip.js +5 -17
  187. package/src/client/components/core/Translate.js +56 -59
  188. package/src/client/components/core/Validator.js +26 -16
  189. package/src/client/components/core/Wallet.js +15 -26
  190. package/src/client/components/core/Webhook.js +40 -7
  191. package/src/client/components/core/Worker.js +163 -27
  192. package/src/client/components/core/windowGetDimensions.js +7 -7
  193. package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +59 -59
  194. package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
  195. package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
  196. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +9 -7
  197. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +8 -6
  198. package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
  199. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
  200. package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
  201. package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
  202. package/src/client/components/cyberia/InstanceEngineCyberia.js +781 -0
  203. package/src/client/components/cyberia/MapEngineCyberia.js +1836 -2
  204. package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
  205. package/src/client/components/cyberia/ObjectLayerEngineModal.js +1220 -99
  206. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +252 -316
  207. package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +136 -103
  208. package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
  209. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +462 -32
  210. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
  211. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +9 -7
  212. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +8 -6
  213. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
  214. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
  215. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
  216. package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
  217. package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
  218. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -4
  219. package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +91 -91
  220. package/src/client/components/default/AppStoreDefault.js +5 -0
  221. package/src/client/components/default/CssDefault.js +12 -12
  222. package/src/client/components/default/LogInDefault.js +9 -7
  223. package/src/client/components/default/LogOutDefault.js +8 -6
  224. package/src/client/components/default/RouterDefault.js +47 -0
  225. package/src/client/components/default/SettingsDefault.js +4 -4
  226. package/src/client/components/default/SignUpDefault.js +6 -4
  227. package/src/client/components/default/SocketIoDefault.js +3 -51
  228. package/src/client/components/default/TranslateDefault.js +3 -3
  229. package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +59 -59
  230. package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
  231. package/src/client/components/itemledger/CssItemledger.js +15 -15
  232. package/src/client/components/itemledger/LogInItemledger.js +9 -7
  233. package/src/client/components/itemledger/LogOutItemledger.js +8 -6
  234. package/src/client/components/itemledger/RouterItemledger.js +38 -0
  235. package/src/client/components/itemledger/SettingsItemledger.js +4 -4
  236. package/src/client/components/itemledger/SignUpItemledger.js +6 -4
  237. package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
  238. package/src/client/components/itemledger/TranslateItemledger.js +3 -3
  239. package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +92 -92
  240. package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
  241. package/src/client/components/underpost/CssUnderpost.js +14 -14
  242. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
  243. package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
  244. package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
  245. package/src/client/components/underpost/LogInUnderpost.js +9 -7
  246. package/src/client/components/underpost/LogOutUnderpost.js +8 -6
  247. package/src/client/components/underpost/RouterUnderpost.js +45 -0
  248. package/src/client/components/underpost/SettingsUnderpost.js +4 -4
  249. package/src/client/components/underpost/SignUpUnderpost.js +6 -4
  250. package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
  251. package/src/client/components/underpost/TranslateUnderpost.js +4 -4
  252. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
  253. package/src/client/public/cyberia-docs/ARCHITECTURE.md +443 -0
  254. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +417 -0
  255. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +313 -0
  256. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +260 -0
  257. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
  258. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
  259. package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
  260. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
  261. package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
  262. package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
  263. package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
  264. package/src/client/services/core/core.service.js +35 -55
  265. package/src/client/services/crypto/crypto.service.js +8 -13
  266. package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
  267. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +99 -0
  268. package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
  269. package/src/client/services/cyberia-entity/cyberia-entity.service.js +99 -0
  270. package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
  271. package/src/client/services/cyberia-instance/cyberia-instance.service.js +116 -0
  272. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +99 -0
  273. package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
  274. package/src/client/services/cyberia-map/cyberia-map.service.js +120 -0
  275. package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
  276. package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
  277. package/src/client/services/default/default.management.js +159 -267
  278. package/src/client/services/default/default.service.js +10 -16
  279. package/src/client/services/document/document.service.js +14 -19
  280. package/src/client/services/file/file.service.js +8 -13
  281. package/src/client/services/instance/instance.management.js +6 -6
  282. package/src/client/services/instance/instance.service.js +10 -15
  283. package/src/client/services/ipfs/ipfs.service.js +14 -40
  284. package/src/client/services/object-layer/object-layer.management.js +14 -14
  285. package/src/client/services/object-layer/object-layer.service.js +39 -24
  286. package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
  287. package/src/client/services/test/test.service.js +8 -13
  288. package/src/client/services/user/guest.service.js +86 -0
  289. package/src/client/services/user/user.management.js +6 -6
  290. package/src/client/services/user/user.service.js +14 -20
  291. package/src/client/ssr/body/404.js +3 -3
  292. package/src/client/ssr/body/500.js +3 -3
  293. package/src/client/ssr/body/CacheControl.js +5 -2
  294. package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
  295. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
  296. package/src/client/ssr/head/PwaItemledger.js +197 -60
  297. package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
  298. package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
  299. package/src/client/ssr/offline/Maintenance.js +12 -11
  300. package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
  301. package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
  302. package/src/client/ssr/pages/Test.js +2 -2
  303. package/src/client/sw/core.sw.js +212 -0
  304. package/src/grpc/cyberia/grpc-server.js +642 -0
  305. package/src/index.js +24 -1
  306. package/src/runtime/cyberia-client/Dockerfile +80 -0
  307. package/src/runtime/cyberia-server/Dockerfile +37 -0
  308. package/src/runtime/express/Dockerfile +5 -1
  309. package/src/runtime/express/Express.js +18 -1
  310. package/src/runtime/lampp/Dockerfile +17 -5
  311. package/src/runtime/lampp/Lampp.js +27 -4
  312. package/src/runtime/wp/Dockerfile +62 -0
  313. package/src/runtime/wp/Wp.js +639 -0
  314. package/src/server/atlas-sprite-sheet-generator.js +4 -2
  315. package/src/server/auth.js +24 -1
  316. package/src/server/backup.js +37 -9
  317. package/src/server/client-build-docs.js +52 -46
  318. package/src/server/client-build.js +356 -82
  319. package/src/server/client-formatted.js +140 -57
  320. package/src/server/conf.js +29 -13
  321. package/src/server/cron.js +25 -23
  322. package/src/server/data-query.js +32 -20
  323. package/src/server/dns.js +24 -1
  324. package/src/server/ipfs-client.js +253 -89
  325. package/src/server/object-layer.js +150 -114
  326. package/src/server/peer.js +8 -0
  327. package/src/server/process.js +13 -27
  328. package/src/server/runtime.js +25 -1
  329. package/src/server/semantic-layer-generator-floor.js +319 -0
  330. package/src/server/semantic-layer-generator-resource.js +259 -0
  331. package/src/server/semantic-layer-generator-skin.js +1164 -0
  332. package/src/server/semantic-layer-generator.js +211 -542
  333. package/src/server/shape-generator.js +108 -0
  334. package/src/server/start.js +19 -5
  335. package/src/server/valkey.js +141 -235
  336. package/src/ws/IoInterface.js +1 -10
  337. package/src/ws/IoServer.js +14 -33
  338. package/src/ws/core/channels/core.ws.chat.js +65 -20
  339. package/src/ws/core/channels/core.ws.mailer.js +113 -32
  340. package/src/ws/core/channels/core.ws.stream.js +90 -31
  341. package/src/ws/core/core.ws.connection.js +12 -33
  342. package/src/ws/core/core.ws.emit.js +10 -26
  343. package/src/ws/core/core.ws.server.js +25 -58
  344. package/src/ws/default/channels/default.ws.main.js +53 -12
  345. package/src/ws/default/default.ws.connection.js +26 -13
  346. package/src/ws/default/default.ws.server.js +30 -12
  347. package/tsconfig.docs.json +15 -0
  348. package/typedoc.dd-cyberia.json +29 -0
  349. package/typedoc.json +29 -0
  350. package/WHITE-PAPER.md +0 -1540
  351. package/hardhat/README.md +0 -531
  352. package/hardhat/WHITE-PAPER.md +0 -1540
  353. package/jsdoc.dd-cyberia.json +0 -59
  354. package/jsdoc.json +0 -59
  355. package/src/api/object-layer/README.md +0 -347
  356. package/src/client/components/core/ColorPalette.js +0 -5267
  357. package/src/client/components/core/JoyStick.js +0 -80
  358. package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
  359. package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
  360. package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
  361. package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
  362. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -58
  363. package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
  364. package/src/client/components/default/ElementsDefault.js +0 -38
  365. package/src/client/components/default/RoutesDefault.js +0 -49
  366. package/src/client/components/itemledger/CommonItemledger.js +0 -29
  367. package/src/client/components/itemledger/ElementsItemledger.js +0 -38
  368. package/src/client/components/itemledger/RoutesItemledger.js +0 -40
  369. package/src/client/components/underpost/CommonUnderpost.js +0 -29
  370. package/src/client/components/underpost/ElementsUnderpost.js +0 -38
  371. package/src/client/components/underpost/RoutesUnderpost.js +0 -47
  372. package/src/client/sw/default.sw.js +0 -127
  373. package/src/client/sw/template.sw.js +0 -84
  374. package/src/ws/core/management/core.ws.chat.js +0 -8
  375. package/src/ws/core/management/core.ws.mailer.js +0 -16
  376. package/src/ws/core/management/core.ws.stream.js +0 -8
  377. package/src/ws/default/management/default.ws.main.js +0 -8
package/src/cli/fs.js CHANGED
@@ -75,6 +75,7 @@ class UnderpostFileStorage {
75
75
  * @param {boolean} [options.force=false] - Flag to force file operations.
76
76
  * @param {boolean} [options.pull=false] - Flag to pull files from storage.
77
77
  * @param {boolean} [options.git=false] - Flag to use Git for file operations.
78
+ * @param {boolean} [options.omitUnzip=false] - If true, do not extract zip and keep downloaded zip file.
78
79
  * @param {string} [options.storageFilePath=''] - The path to the storage configuration file.
79
80
  * @returns {Promise<void>} A promise that resolves when the recursive callback is complete.
80
81
  * @memberof UnderpostFileStorage
@@ -88,10 +89,50 @@ class UnderpostFileStorage {
88
89
  force: false,
89
90
  pull: false,
90
91
  git: false,
92
+ omitUnzip: false,
91
93
  storageFilePath: '',
92
94
  },
93
95
  ) {
94
96
  const { storage, storageConf } = Underpost.fs.getStorageConf(options);
97
+
98
+ // In recursive remove mode, delete every tracked storage key under the requested path,
99
+ // even when local files/directories are already missing.
100
+ if (options.rm === true) {
101
+ const normalizedPath = typeof path === 'string' ? path.trim() : '';
102
+ const basePath = normalizedPath.replace(/\/+$/, '');
103
+ const hasPathFilter = basePath.length > 0;
104
+
105
+ const associatedPaths = Object.keys(storage || {}).filter((storedPath) => {
106
+ if (!hasPathFilter) return true;
107
+ return storedPath === basePath || storedPath.startsWith(`${basePath}/`);
108
+ });
109
+
110
+ for (const associatedPath of associatedPaths) {
111
+ await Underpost.fs.delete(associatedPath);
112
+ if (storage) delete storage[associatedPath];
113
+ }
114
+
115
+ if (hasPathFilter && options.force === true && fs.existsSync(basePath)) fs.removeSync(basePath);
116
+
117
+ Underpost.fs.writeStorageConf(storage, storageConf);
118
+
119
+ if (associatedPaths.length === 0)
120
+ logger.warn('No associated tracked storage paths found', { path: hasPathFilter ? basePath : '*' });
121
+ else
122
+ logger.info('Removed associated tracked storage paths', {
123
+ path: hasPathFilter ? basePath : '*',
124
+ removed: associatedPaths.length,
125
+ });
126
+
127
+ if (options.git === true) {
128
+ const gitPath = hasPathFilter ? basePath : '.';
129
+ shellExec(`cd ${gitPath} && git add .`);
130
+ shellExec(`underpost cmt ${gitPath} feat`);
131
+ }
132
+
133
+ return;
134
+ }
135
+
95
136
  const deleteFiles = options.pull === true ? [] : Underpost.repo.getDeleteFiles(path);
96
137
  for (const relativePath of deleteFiles) {
97
138
  const _path = path + '/' + relativePath;
@@ -101,13 +142,20 @@ class UnderpostFileStorage {
101
142
  }
102
143
  }
103
144
  if (options.pull === true) {
145
+ let pullSkipCount = 0;
104
146
  for (const _path of Object.keys(storage)) {
105
147
  if (!fs.existsSync(_path) || options.force === true) {
106
148
  if (options.force === true && fs.existsSync(_path)) fs.removeSync(_path);
107
149
  await Underpost.fs.pull(_path, options);
108
- } else logger.warn(`Pull path already exists`, _path);
150
+ } else pullSkipCount++;
151
+ }
152
+ if (pullSkipCount > 0) logger.warn(`Pull skipped ${pullSkipCount} files that already exist`);
153
+ // Only run git init/commit when the caller explicitly requests git tracking (--git flag).
154
+ // For bundle pulls into ./build the git step is unwanted and would error on a non-repo path.
155
+ if (options.git === true) {
156
+ Underpost.repo.initLocalRepo({ path });
157
+ shellExec(`cd ${path} && git add . && git commit -m "Base pull state"`);
109
158
  }
110
- shellExec(`cd ${path} && git init && git add . && git commit -m "Base pull state"`);
111
159
  } else {
112
160
  const files =
113
161
  options.git === true ? Underpost.repo.getChangedFiles(path) : await fs.readdir(path, { recursive: true });
@@ -140,12 +188,13 @@ class UnderpostFileStorage {
140
188
  * @param {boolean} [options.force=false] - Flag to force file operations.
141
189
  * @param {boolean} [options.pull=false] - Flag to pull files from storage.
142
190
  * @param {boolean} [options.git=false] - Flag to use Git for file operations.
191
+ * @param {boolean} [options.omitUnzip=false] - If true, do not extract zip and keep downloaded zip file.
143
192
  * @returns {Promise<void>} A promise that resolves when the callback is complete.
144
193
  * @memberof UnderpostFileStorage
145
194
  */
146
195
  async callback(
147
196
  path,
148
- options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
197
+ options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false, omitUnzip: false },
149
198
  ) {
150
199
  if (options.recursive === true || options.git === true)
151
200
  return await Underpost.fs.recursiveCallback(path, options);
@@ -158,11 +207,13 @@ class UnderpostFileStorage {
158
207
  * @description Uploads a file to Cloudinary.
159
208
  * @param {string} path - The path to the file to upload.
160
209
  * @param {object} [options] - An object containing options for the upload.
161
- * @param {boolean} [options.force=false] - Flag to force file operations.
210
+ * @param {string} [options.deployId=''] - The identifier for the deployment (used to locate the storage config file).
211
+ * @param {boolean} [options.force=false] - Flag to force file operations (overwrites existing remote asset).
162
212
  * @param {string} [options.storageFilePath=''] - The path to the storage configuration file.
163
213
  * @returns {Promise<object>} A promise that resolves to the upload result.
164
214
  * @memberof UnderpostFileStorage
165
215
  */
216
+
166
217
  async upload(
167
218
  path,
168
219
  options = { rm: false, recursive: false, deployId: '', force: false, pull: false, storageFilePath: '' },
@@ -188,22 +239,45 @@ class UnderpostFileStorage {
188
239
  * @method pull
189
240
  * @description Pulls a file from Cloudinary.
190
241
  * @param {string} path - The path to the file to pull.
242
+ * @param {object} [options] - Pull options.
243
+ * @param {boolean} [options.omitUnzip=false] - If true, do not extract zip and keep downloaded zip file.
244
+ * @param {boolean} [options.force=false] - If true, re-download even if the local zip already exists.
191
245
  * @returns {Promise<void>} A promise that resolves when the file is pulled.
192
246
  * @memberof UnderpostFileStorage
193
247
  */
194
- async pull(path) {
248
+ async pull(path, options = { omitUnzip: false, force: false }) {
195
249
  Underpost.fs.cloudinaryConfig();
196
250
  const folder = dir.dirname(path);
197
251
  if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
252
+ const zipPath = `${path}.zip`;
253
+
254
+ if (options.omitUnzip === true && options.force !== true && fs.existsSync(zipPath)) {
255
+ logger.warn('pull skipped, zip already exists and omit-unzip is enabled', { path, zipPath });
256
+ return;
257
+ }
258
+
198
259
  const downloadResult = await cloudinary.utils.download_archive_url({
199
260
  public_ids: [path],
200
261
  resource_type: 'raw',
201
262
  });
202
263
  logger.info('download result', downloadResult);
203
- await Downloader.downloadFile(downloadResult, path + '.zip');
204
- path = Underpost.fs.zip2File(path + '.zip');
205
- fs.removeSync(path + '.zip');
264
+ await Downloader.downloadFile(downloadResult, zipPath);
265
+
266
+ if (options.omitUnzip === true) {
267
+ logger.warn('omit unzip enabled, keeping downloaded zip file', { path, zipPath });
268
+ return;
269
+ }
270
+
271
+ path = Underpost.fs.zip2File(zipPath);
272
+ fs.removeSync(`${path}.zip`);
206
273
  },
274
+ /**
275
+ * @method delete
276
+ * @description Deletes a file from Cloudinary by its public ID.
277
+ * @param {string} path - The path (public ID) of the file to delete.
278
+ * @returns {Promise<object>} A promise that resolves to the Cloudinary delete result.
279
+ * @memberof UnderpostFileStorage
280
+ */
207
281
  async delete(path) {
208
282
  Underpost.fs.cloudinaryConfig();
209
283
  const deleteResult = await cloudinary.api
package/src/cli/image.js CHANGED
@@ -99,6 +99,7 @@ class UnderpostImage {
99
99
  if (!path) path = '.';
100
100
  if (!imageName) imageName = `rockylinux9-underpost:${Underpost.version}`;
101
101
  if (!imagePath) imagePath = '.';
102
+ if (imageName.match('/')) imageName = imageName.split('/')[1];
102
103
  if (!version) version = 'latest';
103
104
  version = imageName && imageName.match(':') ? '' : `:${version}`;
104
105
  const podManImg = `localhost/${imageName}${version}`;
@@ -178,6 +179,12 @@ class UnderpostImage {
178
179
  * @memberof UnderpostImage
179
180
  */
180
181
  pullDockerHubImage(options = { k3s: false, kubeadm: false, kind: false, dockerhubImage: '', version: '' }) {
182
+ if (options.dockerhubImage && options.dockerhubImage.startsWith('localhost')) {
183
+ logger.warn(`[image] pullDockerHubImage skipped — local image cannot be pulled from Docker Hub`, {
184
+ dockerhubImage: options.dockerhubImage,
185
+ });
186
+ return;
187
+ }
181
188
  if (options.dockerhubImage === 'underpost') {
182
189
  options.dockerhubImage = 'underpost/underpost-engine';
183
190
  if (!options.version) options.version = Underpost.version;
@@ -185,7 +192,42 @@ class UnderpostImage {
185
192
  if (!options.version) options.version = 'latest';
186
193
  const version = options.dockerhubImage && options.dockerhubImage.match(':') ? '' : `:${options.version}`;
187
194
  const image = `${options.dockerhubImage}${version}`;
188
- if (options.kind === true) {
195
+ const targetKind = options.kind === true;
196
+ const targetK3s = options.k3s === true;
197
+ const targetKubeadm = options.kubeadm === true || (!targetKind && !targetK3s);
198
+
199
+ const requestedRepo = image.replace(/:[^/]+$/, '');
200
+ const requestedTag = image.match(/:([^/]+)$/)?.[1] || 'latest';
201
+ const normalizeRepo = (repo = '') =>
202
+ repo
203
+ .trim()
204
+ .replace(/^localhost\//, '')
205
+ .replace(/^docker\.io\//, '')
206
+ .replace(/^library\//, '');
207
+
208
+ const currentImages = UnderpostImage.API.list({
209
+ kind: targetKind,
210
+ kubeadm: targetKubeadm,
211
+ k3s: targetK3s,
212
+ log: false,
213
+ });
214
+
215
+ const existsInCluster = currentImages.some((row) => {
216
+ const rowImageRaw = String(row.IMAGE || row.image || '').trim();
217
+ if (!rowImageRaw) return false;
218
+ const rowImage = rowImageRaw.replace(/:[^/]+$/, '');
219
+ const rowTag = String(row.TAG || rowImageRaw.match(/:([^/]+)$/)?.[1] || '').trim();
220
+ return normalizeRepo(rowImage) === normalizeRepo(requestedRepo) && rowTag === requestedTag;
221
+ });
222
+
223
+ if (existsInCluster) {
224
+ logger.info(`[image] pull skipped. Image already loaded`, {
225
+ image,
226
+ clusterType: targetKind ? 'kind' : targetK3s ? 'k3s' : 'kubeadm',
227
+ });
228
+ return;
229
+ }
230
+ if (targetKind) {
189
231
  shellExec(`docker pull ${image}`);
190
232
  shellExec(`sudo kind load docker-image ${image}`);
191
233
  } else {
package/src/cli/index.js CHANGED
@@ -46,6 +46,9 @@ program
46
46
  .option('--sync-env-port', 'Sync environment port assignments across all deploy IDs')
47
47
  .option('--single-replica', 'Build single replica folders instead of full client')
48
48
  .option('--build-zip', 'Create zip files of the builds')
49
+ .option('--split <mb>', 'Split generated zip files into parts of the specified size in MB')
50
+ .option('--unzip <build-prefix>', 'Extract a built client zip or split zip parts using the given build prefix')
51
+ .option('--merge-zip <build-prefix>', 'Merge split ZIP parts back into a single ZIP file for the given build prefix')
49
52
  .option('--lite-build', 'Skip full build (default is full build)')
50
53
  .option('--icons-build', 'Build icons')
51
54
  .description('Builds client assets, single replicas, and/or syncs environment ports.')
@@ -62,6 +65,11 @@ program
62
65
  .option('--build', 'Triggers the client-side application build process.')
63
66
  .option('--underpost-quickly-install', 'Uses Underpost Quickly Install for dependency installation.')
64
67
  .option('--skip-pull-base', 'Skips cloning repositories, uses current workspace code directly.')
68
+ .option('--skip-full-build', 'Skips the full client bundle build during deployment.')
69
+ .option(
70
+ '--pull-bundle',
71
+ 'Downloads the pre-built client bundle from Cloudinary via pull-bundle before starting. Use together with --skip-full-build to skip the local build entirely.',
72
+ )
65
73
  .action(Underpost.start.callback)
66
74
  .description('Initiates application servers, build pipelines, or other defined services based on the deployment ID.');
67
75
 
@@ -87,7 +95,7 @@ program
87
95
  .argument(`[commit-type]`, `The type of commit to perform. Options: ${Object.keys(commitData).join(', ')}.`)
88
96
  .argument(`[module-tag]`, 'Optional: Sets a specific module tag for the commit.')
89
97
  .argument(`[message]`, 'Optional: Provides an additional custom message for the commit.')
90
- .option(`--log <latest-n>`, 'Shows commit history from the specified number of latest n path commits.')
98
+ .option(`--log [latest-n]`, 'Shows commit history from the specified number of latest n path commits.')
91
99
  .option('--last-msg <latest-n>', 'Displays the last n commit message.')
92
100
  .option('--empty', 'Allows committing with empty files.')
93
101
  .option('--copy', 'Copies the generated commit message to the clipboard.')
@@ -108,7 +116,14 @@ program
108
116
  '--changelog-no-hash',
109
117
  'Excludes commit hashes from the generated changelog entries (used with --changelog-build).',
110
118
  )
119
+ .option('--unpush', 'With --log, automatically sets range to unpushed commits ahead of remote.')
111
120
  .option('-b', 'Shows the current Git branch name.')
121
+ .option('-p [branch]', 'Shows the reflog for the specified branch.')
122
+ .option('--bc <commit-hash>', 'Shows branches that contain the specified commit.')
123
+ .option(
124
+ '--is-remote-repo <url-repo>',
125
+ 'Checks whether a remote Git repository URL is reachable. Prints true or false.',
126
+ )
112
127
  .description('Manages commits to a GitHub repository, supporting various commit types and options.')
113
128
  .action(Underpost.repo.commit);
114
129
 
@@ -219,6 +234,7 @@ program
219
234
  .option('--ban-egress-clear', 'Clears all banned egress IP addresses.')
220
235
  .option('--ban-both-add', 'Adds IP addresses to both banned ingress and egress lists.')
221
236
  .option('--ban-both-remove', 'Removes IP addresses from both banned ingress and egress lists.')
237
+ .option('--mac', 'Prints the MAC address of the main network interface.')
222
238
  .description('Displays the current public machine IP addresses.')
223
239
  .action(Underpost.dns.ipDispatcher);
224
240
 
@@ -308,6 +324,9 @@ program
308
324
  'Retrieves current network traffic data from resource deployments and the host machine network configuration.',
309
325
  )
310
326
  .option('--kubeadm', 'Enables the kubeadm context for deployment operations.')
327
+ .option('--k3s', 'Enables the k3s context for deployment operations.')
328
+ .option('--kind', 'Enables the kind context for deployment operations.')
329
+ .option('--git-clean', 'Runs git clean on volume mount paths before copying.')
311
330
  .option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
312
331
  .option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
313
332
  .option('--disable-update-underpost-config', 'Disables updates to Underpost configuration during deployment.')
@@ -319,6 +338,14 @@ program
319
338
  'Sets the local:remote port to expose when --expose is active (overrides auto-detected service port).',
320
339
  )
321
340
  .option('--cmd <cmd>', 'Custom initialization command for deployment (comma-separated commands).')
341
+ .option(
342
+ '--skip-full-build',
343
+ 'Skip client bundle rebuild; container will pull pre-built bundle via pull-bundle instead.',
344
+ )
345
+ .option(
346
+ '--pull-bundle',
347
+ 'Explicitly pull the pre-built client bundle from Cloudinary inside the container. Use together with --skip-full-build.',
348
+ )
322
349
  .description('Manages application deployments, defaulting to deploying development pods.')
323
350
  .action(Underpost.deploy.callback);
324
351
 
@@ -327,10 +354,14 @@ program
327
354
  .argument('<platform>', `The secret management platform. Options: ${Object.keys(Underpost.secret).join(', ')}.`)
328
355
  .option('--init', 'Initializes the secrets platform environment.')
329
356
  .option('--create-from-file <path-env-file>', 'Creates secrets from a specified environment file.')
357
+ .option('--create-from-env', 'Creates secrets from container environment variables (envFrom: secretRef).')
358
+ .option('--global-clean', 'Removes all filesystem traces of secrets (engine-private, .env, conf cache).')
330
359
  .option('--list', 'Lists all available secrets for the platform.')
331
360
  .description(`Manages secrets for various platforms.`)
332
361
  .action((...args) => {
362
+ if (args[1].globalClean) return Underpost.secret.globalSecretClean();
333
363
  if (args[1].createFromFile) return Underpost.secret[args[0]].createFromEnvFile(args[1].createFromFile);
364
+ if (args[1].createFromEnv) return Underpost.secret[args[0]].createFromContainerEnv();
334
365
  if (args[1].list) return Underpost.secret[args[0]].list();
335
366
  if (args[1].init) return Underpost.secret[args[0]].init();
336
367
  });
@@ -413,6 +444,7 @@ program
413
444
  .option('--kubeadm', 'Enables the kubeadm context for database operations.')
414
445
  .option('--kind', 'Enables the kind context for database operations.')
415
446
  .option('--k3s', 'Enables the k3s context for database operations.')
447
+ .option('--repo-backup', 'Backs up repositories (git commit+push) inside deployment pods via kubectl exec.')
416
448
  .description(
417
449
  'Manages database operations with support for MariaDB and MongoDB, including import/export, multi-pod targeting, and Git integration.',
418
450
  )
@@ -429,6 +461,7 @@ program
429
461
  .option('--instances', 'Apply to instance data collection')
430
462
  .option('--generate', 'Generate cluster metadata')
431
463
  .option('--itc', 'Apply under container execution context')
464
+ .option('--dev', 'Sets the development cli context')
432
465
  .description('Manages cluster metadata operations, including import and export.')
433
466
  .action(Underpost.db.clusterMetadataBackupCallback);
434
467
 
@@ -458,7 +491,6 @@ program
458
491
  '--create-job-now',
459
492
  'After applying manifests, immediately create a Job from each CronJob (requires --apply).',
460
493
  )
461
- .option('--ssh', 'Execute backup commands via SSH on the remote node instead of locally.')
462
494
  .description('Manages cron jobs: execute jobs directly or generate and apply K8s CronJob manifests.')
463
495
  .action(Underpost.cron.callback);
464
496
 
@@ -470,6 +502,7 @@ program
470
502
  .option('--recursive', 'Uploads files recursively from the specified path.')
471
503
  .option('--deploy-id <deploy-id>', 'Specifies the deployment configuration ID for file operations.')
472
504
  .option('--pull', 'Downloads the specified file.')
505
+ .option('--omit-unzip', 'With --pull, keeps the downloaded .zip file and skips extraction.')
473
506
  .option('--force', 'Forces the action, overriding any warnings or conflicts.')
474
507
  .option('--storage-file-path <storage-file-path>', 'Specifies a custom file storage path.')
475
508
  .description('Manages file storage, defaulting to file upload operations.')
@@ -597,7 +630,7 @@ program
597
630
  .option('--kubeadm', 'Sets the kubeadm cluster context for the runner execution.')
598
631
  .option('--k3s', 'Sets the k3s cluster context for the runner execution.')
599
632
  .option('--kind', 'Sets the kind cluster context for the runner execution.')
600
- .option('--log-type <log-type>', 'Sets the log type for the runner execution.')
633
+ .option('--git-clean', 'Runs git clean on volume mount paths before copying.')
601
634
  .option('--deploy-id <deploy-id>', 'Sets deploy id context for the runner execution.')
602
635
  .option('--user <user>', 'Sets user context for the runner execution.')
603
636
  .option('--hosts <hosts>', 'Comma-separated list of hosts for the runner execution.')
@@ -640,6 +673,15 @@ program
640
673
  'Format: semicolon-separated entries of "ip=hostname1,hostname2" ' +
641
674
  '(e.g., "127.0.0.1=foo.local,bar.local;10.1.2.3=foo.remote,bar.remote").',
642
675
  )
676
+ .option('--copy', 'Copies the runner output to the clipboard (supported by: generate-pass, template-deploy-local).')
677
+ .option(
678
+ '--skip-full-build',
679
+ 'Skip client bundle rebuild; triggers pull-bundle in container startup (supported by: sync, template-deploy).',
680
+ )
681
+ .option(
682
+ '--pull-bundle',
683
+ 'Explicitly download the pre-built client bundle from Cloudinary inside the container (supported by: sync, template-deploy). Use together with --skip-full-build.',
684
+ )
643
685
  .description('Runs specified scripts using various runners.')
644
686
  .action(Underpost.run.callback);
645
687
 
@@ -764,4 +806,33 @@ program
764
806
  )
765
807
  .action(Underpost.baremetal.callback);
766
808
 
809
+ program
810
+ .command('release')
811
+ .argument('[version]', 'The new version string to set (e.g., "3.1.4"). Defaults to current version.')
812
+ .option('--build', 'Builds a new version: tests template, bumps versions, rebuilds manifests and configs.')
813
+ .option('--deploy', 'Deploys the release: syncs secrets, commits, and pushes to remote repositories.')
814
+ .option(
815
+ '--ci-push <deploy-id>',
816
+ 'Local equivalent of engine-*.ci.yml: builds dd-{deploy-id} and pushes to the engine-{deploy-id} repository. ' +
817
+ 'Accepts the suffix (e.g., "cyberia"), "dd-cyberia", or "engine-cyberia".',
818
+ )
819
+ .option(
820
+ '--message <message>',
821
+ 'Commit message for --ci-push or --pwa-build (defaults to last commit of the engine repository).',
822
+ )
823
+ .option(
824
+ '--pwa-build',
825
+ 'Runs the pwa-microservices-template update flow: always re-clones, syncs engine sources, installs, builds, and pushes.',
826
+ )
827
+ .description('Release orchestrator for building new versions and deploying releases of the Underpost CLI.')
828
+ .action(async (version, options) => {
829
+ if (options.build) return Underpost.release.build(version, options);
830
+ if (options.deploy) return Underpost.release.deploy(version, options);
831
+ if (options.ciPush) return Underpost.release.ci(options.ciPush, options.message, options);
832
+ if (options.pwaBuild) return Underpost.release.pwa(options.message, options);
833
+ console.log(
834
+ 'Please specify --build, --deploy, --ci-push, or --pwa-build. Use "underpost release --help" for details.',
835
+ );
836
+ });
837
+
767
838
  export { program };
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Kubectl module providing low-level Kubernetes resource management primitives.
3
+ * Centralises pod querying, file transfer, and in-container execution operations
4
+ * that were previously scattered across db, deploy, and cluster modules.
5
+ * @module src/cli/kubectl.js
6
+ * @namespace UnderpostKubectl
7
+ */
8
+
9
+ import { loggerFactory } from '../server/logger.js';
10
+ import { shellExec } from '../server/process.js';
11
+ import Underpost from '../index.js';
12
+
13
+ const logger = loggerFactory(import.meta);
14
+
15
+ /**
16
+ * Redacts credentials from shell command strings before logging.
17
+ * Masks passwords in `-p<password>`, `--password=<password>`, and `-P <password>` patterns.
18
+ * @param {string} cmd - The raw command string.
19
+ * @returns {string} The command with credentials replaced by `***`.
20
+ * @memberof UnderpostKubectl
21
+ */
22
+ const sanitizeCommand = (cmd) => {
23
+ if (typeof cmd !== 'string') return cmd;
24
+ return cmd
25
+ .replace(/-p['"]?[^\s'"]+/g, '-p***')
26
+ .replace(/--password=['"]?[^\s'"]+/g, '--password=***')
27
+ .replace(/-P\s+['"]?[^\s'"]+/g, '-P ***');
28
+ };
29
+
30
+ /**
31
+ * @class UnderpostKubectl
32
+ * @description Kubernetes cluster resource management primitives.
33
+ * Provides a unified interface for kubectl operations: resource listing, in-pod
34
+ * command execution, file transfer, and pod discovery/filtering.
35
+ * All methods are stateless and safe to call from any other CLI module.
36
+ * @memberof UnderpostKubectl
37
+ */
38
+ class UnderpostKubectl {
39
+ static API = {
40
+ /**
41
+ * Lists Kubernetes resources matching `deployId`, parsed into plain objects.
42
+ * Equivalent to `kubectl get <kindType> -o wide`, filtered by name substring.
43
+ * @param {string} deployId - Substring to match against resource names. Empty string returns all.
44
+ * @param {string} [kindType='pods'] - Resource kind: pods, deployments, svc, nodes, …
45
+ * @param {string} [namespace=''] - Namespace to query; empty string → --all-namespaces.
46
+ * @returns {Array<object>} Parsed rows keyed by column header (NAME, STATUS, NODE, …).
47
+ * @memberof UnderpostKubectl
48
+ */
49
+ get(deployId, kindType = 'pods', namespace = '') {
50
+ const raw = shellExec(
51
+ `sudo kubectl get ${kindType}${namespace ? ` -n ${namespace}` : ` --all-namespaces`} -o wide`,
52
+ { stdout: true, disableLog: true, silent: true },
53
+ );
54
+
55
+ const heads = raw
56
+ .split(`\n`)[0]
57
+ .split(' ')
58
+ .filter((_r) => _r.trim());
59
+
60
+ const pods = raw
61
+ .split(`\n`)
62
+ .filter((r) => (deployId ? r.match(deployId) : r.trim() && !r.match('NAME')))
63
+ .map((r) => r.split(' ').filter((_r) => _r.trim()));
64
+
65
+ const result = [];
66
+ for (const row of pods) {
67
+ const pod = {};
68
+ let index = -1;
69
+ for (const head of heads) {
70
+ index++;
71
+ pod[head] = row[index];
72
+ }
73
+ result.push(pod);
74
+ }
75
+ return result;
76
+ },
77
+
78
+ /**
79
+ * Executes a kubectl command with credential-safe logging and error propagation.
80
+ * @param {string} command - Full kubectl command string.
81
+ * @param {object} [options={}] - Execution options.
82
+ * @param {string} [options.context=''] - Human-readable label for log messages.
83
+ * @returns {string} stdout output from the command.
84
+ * @throws {Error} Re-throws any execution error after logging.
85
+ * @memberof UnderpostKubectl
86
+ */
87
+ run(command, options = {}) {
88
+ const { context = '' } = options;
89
+ try {
90
+ logger.info(`Executing kubectl command`, { command: sanitizeCommand(command), context });
91
+ return shellExec(command, { stdout: true, disableLog: true });
92
+ } catch (error) {
93
+ logger.error(`kubectl command failed`, { command: sanitizeCommand(command), error: error.message, context });
94
+ throw error;
95
+ }
96
+ },
97
+
98
+ /**
99
+ * Runs a shell command inside a pod container via `kubectl exec`.
100
+ * @param {object} params
101
+ * @param {string} params.podName - Target pod name.
102
+ * @param {string} params.namespace - Pod namespace.
103
+ * @param {string} params.command - Shell command to run inside the container.
104
+ * @returns {string} stdout output from the in-pod command.
105
+ * @throws {Error} Re-throws any execution error after logging.
106
+ * @memberof UnderpostKubectl
107
+ */
108
+ exec({ podName, namespace, command }) {
109
+ try {
110
+ const kubectlCmd = `sudo kubectl exec -n ${namespace} -i ${podName} -- sh -c "${command}"`;
111
+ return Underpost.kubectl.run(kubectlCmd, { context: `exec in pod ${podName}` });
112
+ } catch (error) {
113
+ logger.error('Failed to execute command in pod', {
114
+ podName,
115
+ command: sanitizeCommand(command),
116
+ error: error.message,
117
+ });
118
+ throw error;
119
+ }
120
+ },
121
+
122
+ /**
123
+ * Copies a local file into a pod via `kubectl cp`.
124
+ * @param {object} params
125
+ * @param {string} params.sourcePath - Local source path.
126
+ * @param {string} params.podName - Target pod name.
127
+ * @param {string} params.namespace - Pod namespace.
128
+ * @param {string} params.destPath - Destination path inside the container.
129
+ * @returns {boolean} `true` on success, `false` on error.
130
+ * @memberof UnderpostKubectl
131
+ */
132
+ cpTo({ sourcePath, podName, namespace, destPath }) {
133
+ try {
134
+ const command = `sudo kubectl cp ${sourcePath} ${namespace}/${podName}:${destPath}`;
135
+ Underpost.kubectl.run(command, { context: `copy to pod ${podName}` });
136
+ return true;
137
+ } catch (error) {
138
+ logger.error('Failed to copy file to pod', { sourcePath, podName, destPath, error: error.message });
139
+ return false;
140
+ }
141
+ },
142
+
143
+ /**
144
+ * Copies a file from a pod to the local filesystem via `kubectl cp`.
145
+ * @param {object} params
146
+ * @param {string} params.podName - Source pod name.
147
+ * @param {string} params.namespace - Pod namespace.
148
+ * @param {string} params.sourcePath - Source path inside the container.
149
+ * @param {string} params.destPath - Local destination path.
150
+ * @returns {boolean} `true` on success, `false` on error.
151
+ * @memberof UnderpostKubectl
152
+ */
153
+ cpFrom({ podName, namespace, sourcePath, destPath }) {
154
+ try {
155
+ const command = `sudo kubectl cp ${namespace}/${podName}:${sourcePath} ${destPath}`;
156
+ Underpost.kubectl.run(command, { context: `copy from pod ${podName}` });
157
+ return true;
158
+ } catch (error) {
159
+ logger.error('Failed to copy file from pod', { podName, sourcePath, destPath, error: error.message });
160
+ return false;
161
+ }
162
+ },
163
+
164
+ /**
165
+ * Checks whether a file exists inside a pod container.
166
+ * @param {object} params
167
+ * @param {string} params.podName - Pod name.
168
+ * @param {string} params.path - Absolute path inside the container to test.
169
+ * @returns {boolean} `true` if the file exists.
170
+ * @memberof UnderpostKubectl
171
+ */
172
+ existsFile({ podName, path }) {
173
+ const result = shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
174
+ stdout: true,
175
+ disableLog: true,
176
+ silent: true,
177
+ }).trim();
178
+ return result === 'true';
179
+ },
180
+
181
+ /**
182
+ * Returns a filtered list of pods from the cluster.
183
+ * Supports wildcard glob patterns on pod names and optional deployId substring filtering.
184
+ * @param {object} [criteria={}] - Filter criteria.
185
+ * @param {string} [criteria.deployId] - Substring to match against pod names (forwards to `get`).
186
+ * @param {string} [criteria.podNames] - Comma-separated glob patterns (supports `*`).
187
+ * @param {string} [criteria.namespace='default'] - Kubernetes namespace to query.
188
+ * @returns {Array<object>} Filtered pod rows from `get`.
189
+ * @memberof UnderpostKubectl
190
+ */
191
+ getFilteredPods(criteria = {}) {
192
+ const { podNames, namespace = 'default', deployId } = criteria;
193
+ try {
194
+ let pods = Underpost.kubectl.get(deployId || '', 'pods', namespace);
195
+ if (podNames) {
196
+ const patterns = podNames.split(',').map((p) => p.trim());
197
+ pods = pods.filter((pod) =>
198
+ patterns.some((pattern) => new RegExp('^' + pattern.replace(/\*/g, '.*') + '$').test(pod.NAME)),
199
+ );
200
+ }
201
+ logger.info(`Found ${pods.length} pod(s) matching criteria`, { criteria, podNames: pods.map((p) => p.NAME) });
202
+ return pods;
203
+ } catch (error) {
204
+ logger.error('Error filtering pods', { error: error.message, criteria });
205
+ return [];
206
+ }
207
+ },
208
+ };
209
+ }
210
+
211
+ export default UnderpostKubectl;