@underpostnet/cyberia 3.3.0 → 3.3.76

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 (568) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +17 -5
  3. package/.github/workflows/coverall.cyberia.ci.yml +39 -14
  4. package/.github/workflows/cyberia-client.cd.yml +5 -0
  5. package/.github/workflows/cyberia-server.cd.yml +5 -0
  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 +3 -0
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +35 -20
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/publish.cyberia.ci.yml +44 -0
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +1 -0
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +96 -0
  22. package/CHANGELOG.md +653 -2513
  23. package/CLI-HELP.md +323 -157
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +5 -5
  27. package/README.md +48 -28
  28. package/bin/build.js +86 -41
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +1494 -1403
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +1494 -1403
  33. package/compose.env +17 -5
  34. package/conf.js +98 -7
  35. package/deploy/cyberia-client/deploy.sh +46 -0
  36. package/deploy/cyberia-client/package.sh +17 -0
  37. package/deploy/cyberia-client/state.sh +15 -0
  38. package/deploy/cyberia-server/deploy.sh +46 -0
  39. package/deploy/cyberia-server/package.sh +17 -0
  40. package/deploy/cyberia-server/state.sh +15 -0
  41. package/deploy/dd-cyberia/deploy.sh +9 -29
  42. package/deploy/dd-cyberia/init.sh +38 -45
  43. package/deploy/dd-cyberia/package.sh +16 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +133 -147
  46. package/deploy/lib/config.sh +29 -0
  47. package/deploy/lib/github-actions-logging.sh +610 -0
  48. package/deploy/lib/host.sh +194 -0
  49. package/deploy/lib/state.sh +65 -0
  50. package/deploy/pwa-microservices-template/deploy.sh +17 -42
  51. package/deploy/release/deploy.sh +9 -41
  52. package/deployment.yaml +7 -2
  53. package/docker-compose.yml +23 -17
  54. package/examples/static-page/README.md +19 -19
  55. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  56. package/hardhat/hardhat.config.js +1 -6
  57. package/hardhat/package-lock.json +101 -40
  58. package/hardhat/package.json +2 -2
  59. package/manifests/alertmanager/deployment.yaml +81 -0
  60. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  61. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
  62. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
  63. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  64. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  65. package/manifests/deployment/mongo-express/deployment.yaml +46 -27
  66. package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
  67. package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
  68. package/manifests/deployment/mongo-express/service.yaml +16 -0
  69. package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
  70. package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
  71. package/manifests/grafana/deployment.yaml +26 -7
  72. package/manifests/grafana/kustomization.yaml +1 -0
  73. package/manifests/grafana/service.yaml +6 -1
  74. package/manifests/mariadb/pv.yaml +1 -0
  75. package/manifests/mongodb/statefulset.yaml +9 -2
  76. package/manifests/mysql/pv-pvc.yaml +14 -1
  77. package/manifests/postgresql/pv.yaml +12 -1
  78. package/manifests/postgresql/pvc.yaml +1 -0
  79. package/manifests/prometheus/deployment.yaml +18 -22
  80. package/package.json +87 -12
  81. package/scripts/event-monitor.sh +56 -0
  82. package/scripts/k3s-node-setup.sh +27 -14
  83. package/scripts/kubeadm-node-setup.sh +31 -11
  84. package/scripts/maas-setup.sh +8 -8
  85. package/scripts/selinux-normalize.sh +907 -0
  86. package/scripts/shutdown-machine.sh +843 -0
  87. package/scripts/test-monitor.sh +5 -5
  88. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
  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 +3 -3
  99. package/src/api/cyberia-action/cyberia-action.service.js +5 -6
  100. package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
  101. package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
  102. package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
  103. package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
  104. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +2 -4
  105. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
  106. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
  107. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
  108. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  109. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
  110. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
  111. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  112. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  113. package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
  114. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  115. package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
  116. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
  117. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
  118. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -2
  119. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
  120. package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
  121. package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -40
  122. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
  123. package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
  124. package/src/api/cyberia-instance/cyberia-instance-map.service.js +35 -142
  125. package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
  126. package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
  127. package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
  128. package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
  129. package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
  130. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  131. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
  132. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  133. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
  134. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  135. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  136. package/src/api/cyberia-map/cyberia-map.service.js +8 -4
  137. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
  138. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
  139. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
  140. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
  141. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  142. package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
  143. package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
  144. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  145. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
  146. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  147. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  148. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  149. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  150. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  151. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -214
  152. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  153. package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
  154. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  155. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  156. package/src/api/default/default.controller.js +1 -1
  157. package/src/api/default/default.router.js +1 -1
  158. package/src/api/default/default.service.js +2 -2
  159. package/src/api/document/document.controller.js +1 -1
  160. package/src/api/document/document.router.js +1 -1
  161. package/src/api/document/document.service.js +2 -2
  162. package/src/api/file/file.controller.js +1 -1
  163. package/src/api/file/file.ref.js +153 -0
  164. package/src/api/file/file.ref.json +11 -2
  165. package/src/api/file/file.router.js +1 -1
  166. package/src/api/file/file.service.js +2 -2
  167. package/src/api/instance/instance.controller.js +1 -1
  168. package/src/api/instance/instance.router.js +1 -1
  169. package/src/api/instance/instance.service.js +2 -2
  170. package/src/api/ipfs/ipfs.controller.js +1 -1
  171. package/src/api/ipfs/ipfs.router.js +2 -2
  172. package/src/api/ipfs/ipfs.service.js +2 -2
  173. package/src/api/object-layer/object-layer.controller.js +1 -1
  174. package/src/api/object-layer/object-layer.model.js +47 -12
  175. package/src/api/object-layer/object-layer.router.js +12 -5
  176. package/src/api/object-layer/object-layer.service.js +116 -123
  177. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  178. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  179. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  180. package/src/api/test/test.controller.js +1 -1
  181. package/src/api/test/test.service.js +1 -1
  182. package/src/api/user/guest.service.js +3 -3
  183. package/src/api/user/user.controller.js +1 -1
  184. package/src/api/user/user.router.js +2 -2
  185. package/src/api/user/user.service.js +4 -4
  186. package/src/api.js +5 -9
  187. package/src/cli/app.js +402 -0
  188. package/src/cli/baremetal.js +30 -35
  189. package/src/cli/client.js +306 -0
  190. package/src/cli/cloud-init.js +3 -3
  191. package/src/cli/cluster.js +191 -82
  192. package/src/cli/db.js +120 -68
  193. package/src/cli/deploy.js +157 -75
  194. package/src/cli/docker-compose.js +5 -5
  195. package/src/cli/domains.js +184 -0
  196. package/src/cli/dotenv-store.js +143 -0
  197. package/src/cli/event.js +2281 -0
  198. package/src/cli/fs-selection.js +115 -0
  199. package/src/cli/fs.js +159 -343
  200. package/src/cli/host.js +672 -0
  201. package/src/cli/image.js +4 -6
  202. package/src/cli/index.js +343 -151
  203. package/src/cli/ipfs.js +34 -30
  204. package/src/cli/kickstart.js +1 -1
  205. package/src/cli/kubectl.js +218 -41
  206. package/src/cli/lxd.js +3 -3
  207. package/src/cli/monitor.js +1359 -26
  208. package/src/cli/package.js +90 -0
  209. package/src/cli/release.js +16 -12
  210. package/src/cli/repository.js +586 -363
  211. package/src/cli/run.js +398 -843
  212. package/src/cli/secrets.js +2158 -964
  213. package/src/cli/ssh.js +478 -279
  214. package/src/cli/state.js +394 -0
  215. package/src/cli/static.js +2 -2
  216. package/src/cli/system.js +1 -1
  217. package/src/cli/test.js +203 -125
  218. package/src/cli/vultr.js +61 -21
  219. package/src/cli/wireguard.js +1112 -306
  220. package/src/client/components/core/CalendarCore.js +53 -96
  221. package/src/client/components/core/Docs.js +327 -303
  222. package/src/client/components/core/FileExplorer.js +0 -21
  223. package/src/client/components/core/Modal.js +56 -1
  224. package/src/client/components/core/PanelForm.js +4 -4
  225. package/src/client/components/core/Repository.js +56 -0
  226. package/src/client/components/core/Translate.js +7 -0
  227. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  228. package/src/client/components/core/Wallet.js +0 -11
  229. package/src/client/components/core/Worker.js +7 -1
  230. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  231. package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
  232. package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
  233. package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
  234. package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
  235. package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
  236. package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
  237. package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
  238. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
  239. package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
  240. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -35
  241. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
  242. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
  243. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  244. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
  245. package/src/client/components/default/AppShellDefault.js +1 -1
  246. package/src/client/components/default/SettingsDefault.js +2 -2
  247. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  248. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  249. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  250. package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
  251. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
  252. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
  253. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
  254. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
  255. package/src/client/public/cyberia-docs/CYBERIA.md +48 -28
  256. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
  257. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  258. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  259. package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
  260. package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
  261. package/src/client/public/default/android-chrome-144x144.png +0 -0
  262. package/src/client/public/default/android-chrome-192x192.png +0 -0
  263. package/src/client/public/default/android-chrome-256x256.png +0 -0
  264. package/src/client/public/default/android-chrome-36x36.png +0 -0
  265. package/src/client/public/default/android-chrome-384x384.png +0 -0
  266. package/src/client/public/default/android-chrome-48x48.png +0 -0
  267. package/src/client/public/default/android-chrome-512x512.png +0 -0
  268. package/src/client/public/default/android-chrome-72x72.png +0 -0
  269. package/src/client/public/default/android-chrome-96x96.png +0 -0
  270. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  271. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  272. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  273. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  274. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  275. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  276. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  277. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  278. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  279. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  280. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  281. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  282. package/src/client/public/default/apple-touch-icon.png +0 -0
  283. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  284. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  285. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  286. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  287. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  288. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  289. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  290. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  291. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  292. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  293. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  294. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  295. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  296. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  297. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  298. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  299. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  300. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  301. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  302. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  303. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  304. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  305. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  306. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  307. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  308. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  309. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  310. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  311. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  312. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  313. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  314. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  315. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  316. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  317. package/src/client/public/default/assets/background/white.jpg +0 -0
  318. package/src/client/public/default/browserconfig.xml +1 -1
  319. package/src/client/public/default/favicon-16x16.png +0 -0
  320. package/src/client/public/default/favicon-32x32.png +0 -0
  321. package/src/client/public/default/favicon-48x48.png +0 -0
  322. package/src/client/public/default/favicon.ico +0 -0
  323. package/src/client/public/default/manifest.webmanifest +5 -5
  324. package/src/client/public/default/mstile-144x144.png +0 -0
  325. package/src/client/public/default/mstile-150x150.png +0 -0
  326. package/src/client/public/default/mstile-310x150.png +0 -0
  327. package/src/client/public/default/mstile-310x310.png +0 -0
  328. package/src/client/public/default/mstile-70x70.png +0 -0
  329. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  330. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  331. package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
  332. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
  333. package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
  334. package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
  335. package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
  336. package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
  337. package/src/client/services/object-layer/object-layer.management.js +6 -10
  338. package/src/client/services/object-layer/object-layer.service.js +3 -1
  339. package/src/client/ssr/RootDocument.js +1 -1
  340. package/src/client/ssr/body/404.js +1 -1
  341. package/src/client/ssr/body/500.js +1 -1
  342. package/src/client/ssr/body/CacheControl.js +1 -1
  343. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  344. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  345. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  346. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  347. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  348. package/src/client/ssr/head/Css.js +1 -1
  349. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  350. package/src/client/ssr/head/DefaultScripts.js +1 -1
  351. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  352. package/src/client/ssr/head/Microdata.js +1 -1
  353. package/src/client/ssr/head/Production.js +1 -1
  354. package/src/client/ssr/head/Pwa.js +1 -1
  355. package/src/client/ssr/head/PwaItemledger.js +1 -1
  356. package/src/client/ssr/head/Seo.js +1 -1
  357. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  358. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  359. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  360. package/src/client/ssr/views/Cyberia404.js +7 -5
  361. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  362. package/src/client/ssr/views/Maintenance.js +1 -1
  363. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  364. package/src/client/ssr/views/Test.js +1 -1
  365. package/src/client/sw/core.sw.js +20 -14
  366. package/src/client-builder/client-build-docs.js +92 -77
  367. package/src/client-builder/client-build-live.js +2 -2
  368. package/src/client-builder/client-build.js +105 -74
  369. package/src/client-builder/client-bundle.js +347 -0
  370. package/src/client-builder/client-dev-server.js +3 -3
  371. package/src/client-builder/client-icons.js +2 -2
  372. package/src/client-builder/ssr.js +3 -3
  373. package/src/client.build.js +3 -6
  374. package/src/client.dev.js +3 -6
  375. package/src/db/DataBaseProvider.js +186 -3
  376. package/src/db/mariadb/MariaDB.js +3 -2
  377. package/src/db/mongo/MongoBootstrap.js +273 -101
  378. package/src/db/mongo/MongoExpress.js +187 -0
  379. package/src/db/mongo/MongooseDB.js +7 -8
  380. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  381. package/src/grpc/cyberia/grpc-server.js +6 -8
  382. package/src/index.js +79 -23
  383. package/src/mailer/EmailRender.js +2 -2
  384. package/src/mailer/MailerInterceptor.js +87 -0
  385. package/src/mailer/MailerProvider.js +50 -6
  386. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +144 -147
  387. package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
  388. package/src/projects/cyberia/besu-genesis-generator.js +8 -17
  389. package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
  390. package/src/projects/cyberia/catalog-cyberia.js +54 -10
  391. package/src/projects/cyberia/gemini-client.js +4 -4
  392. package/src/projects/cyberia/generate-saga.js +5 -12
  393. package/src/projects/cyberia/hot-reload-trigger.js +18 -29
  394. package/src/projects/cyberia/instance-backup.js +210 -0
  395. package/src/projects/cyberia/instance-data.js +178 -258
  396. package/src/projects/cyberia/ipfs-client.js +4 -4
  397. package/src/projects/cyberia/map-preview-generator.js +33 -69
  398. package/src/projects/cyberia/object-layer.js +153 -320
  399. package/src/projects/cyberia/seed-audio.js +139 -0
  400. package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
  401. package/src/projects/cyberia/semantic-layer-generator.js +3 -19
  402. package/src/projects/cyberia/stat-balance.js +81 -0
  403. package/src/projects/cyberia/stat-commands.js +23 -0
  404. package/src/projects/cyberia/stat-contract-generator.js +101 -0
  405. package/src/projects/underpost/catalog-underpost.js +9 -1
  406. package/src/proxy.js +4 -7
  407. package/src/runtime/cyberia-client/Dockerfile +17 -8
  408. package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
  409. package/src/runtime/cyberia-server/Dockerfile +18 -6
  410. package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
  411. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  412. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  413. package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
  414. package/src/runtime/engine-cyberia/compose.env +17 -5
  415. package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
  416. package/src/runtime/express/Express.js +32 -27
  417. package/src/runtime/lampp/Lampp.js +22 -70
  418. package/src/runtime/nginx/Nginx.js +1 -1
  419. package/src/runtime/wp/Wp.js +16 -48
  420. package/src/server/{catalog.js → build/catalog.js} +15 -5
  421. package/src/server/build/coverage.js +188 -0
  422. package/src/server/build/execution.js +402 -0
  423. package/src/server/build/package.js +508 -0
  424. package/src/server/build/testing.js +578 -0
  425. package/src/server/{dns.js → network/dns.js} +144 -11
  426. package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
  427. package/src/server/{middlewares.js → network/middlewares.js} +11 -5
  428. package/src/server/network/node-capability.js +98 -0
  429. package/src/server/{peer.js → network/peer.js} +3 -3
  430. package/src/server/{proxy.js → network/proxy.js} +7 -13
  431. package/src/server/network/router.js +356 -0
  432. package/src/server/{tls.js → network/tls.js} +2 -2
  433. package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
  434. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
  435. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
  436. package/src/server/{cri.js → ops/cri.js} +2 -2
  437. package/src/server/{cron.js → ops/cron.js} +349 -74
  438. package/src/server/ops/event-notification.js +284 -0
  439. package/src/server/{logger.js → ops/logger.js} +143 -23
  440. package/src/server/ops/monitoring.js +1724 -0
  441. package/src/server/{systemd.js → ops/systemd.js} +55 -1
  442. package/src/server/{conf.js → runtime/conf.js} +516 -423
  443. package/src/server/runtime/config-scope.js +215 -0
  444. package/src/server/runtime/environment.js +149 -0
  445. package/src/server/{process.js → runtime/process.js} +153 -12
  446. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  447. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  448. package/src/server/{start.js → runtime/start.js} +128 -39
  449. package/src/server/{auth.js → security/auth.js} +7 -8
  450. package/src/server/security/container-storage.js +382 -0
  451. package/src/server/{crypto.js → security/crypto.js} +1 -1
  452. package/src/server/{selinux.js → security/selinux.js} +1 -1
  453. package/src/server/{backup.js → storage/backup.js} +17 -8
  454. package/src/server/{data-query.js → storage/data-query.js} +17 -1
  455. package/src/server/storage/downloader.js +121 -0
  456. package/src/server/storage/repository.js +68 -0
  457. package/src/server/storage/zip.js +153 -0
  458. package/src/server.js +4 -7
  459. package/src/ws/IoInterface.js +1 -1
  460. package/src/ws/IoServer.js +1 -1
  461. package/src/ws/core/core.ws.connection.js +1 -1
  462. package/src/ws/core/core.ws.emit.js +1 -1
  463. package/src/ws/core/core.ws.server.js +1 -1
  464. package/src/ws/default/default.ws.connection.js +1 -1
  465. package/src/ws/default/default.ws.emit.js +1 -1
  466. package/src/ws/default/default.ws.server.js +1 -1
  467. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  468. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  469. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  470. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  471. package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
  472. package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
  473. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +64 -0
  474. package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
  475. package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
  476. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
  477. package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
  478. package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
  479. package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
  480. package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
  481. package/test/integration/app/cyberia/fallback-world-capture.test.js +338 -0
  482. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  483. package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
  484. package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
  485. package/test/integration/app/cyberia/seed-audio.test.js +275 -0
  486. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  487. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  488. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  489. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  490. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  491. package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
  492. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  493. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  494. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  495. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  496. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  497. package/test/integration/infra/2-network/wireguard-cli.test.js +1187 -0
  498. package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
  499. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  500. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  501. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  502. package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
  503. package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
  504. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  505. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  506. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  507. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
  508. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
  509. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  510. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  511. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  512. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  513. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  514. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  515. package/test/support/shell-harness.js +73 -0
  516. package/test/unit/build-template.test.js +97 -0
  517. package/test/unit/build-workflow-offline.test.js +132 -0
  518. package/test/unit/catalog.test.js +71 -0
  519. package/test/unit/client-build-docs.test.js +361 -0
  520. package/test/unit/client-bundle.test.js +313 -0
  521. package/test/unit/conf-loading.test.js +303 -0
  522. package/test/unit/conf-resolution.test.js +996 -0
  523. package/test/unit/coverage-artifact.test.js +221 -0
  524. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  525. package/test/unit/cyberia/instance-backup.test.js +183 -0
  526. package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
  527. package/test/unit/cyberia/publish-workflow.test.js +22 -0
  528. package/test/unit/cyberia/stat-balance.test.js +69 -0
  529. package/test/unit/deploy-env-resolution.test.js +38 -0
  530. package/test/unit/deploy-log-table.test.js +518 -0
  531. package/test/unit/downloader-integrity.test.js +98 -0
  532. package/test/unit/execution-profiles.test.js +219 -0
  533. package/test/unit/file-reference-registry.test.js +141 -0
  534. package/test/unit/fleet-sync-source.test.js +149 -0
  535. package/test/unit/fs-storage-paths.test.js +596 -0
  536. package/test/unit/logger-redaction.test.js +141 -0
  537. package/test/unit/package.test.js +457 -0
  538. package/test/unit/prepare-host.test.js +382 -0
  539. package/test/unit/process-environment.test.js +18 -0
  540. package/test/unit/propagation-message.test.js +78 -0
  541. package/test/unit/redeploy-plan.test.js +24 -0
  542. package/test/unit/release-bump.test.js +474 -0
  543. package/test/unit/ssh-output-redaction.test.js +28 -0
  544. package/test/unit/start-options.test.js +46 -0
  545. package/test/unit/test-tiers.test.js +220 -0
  546. package/test/unit/zip-archive.test.js +142 -0
  547. package/vitest.config.js +66 -0
  548. package/.nycrc +0 -9
  549. package/deploy/lib/logging.sh +0 -96
  550. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  551. package/manifests/mongodb/pv-pvc.yaml +0 -59
  552. package/scripts/coverall-test-cyberia.sh +0 -24
  553. package/scripts/coverall-test.sh +0 -24
  554. package/scripts/link-local-underpost-cli.sh +0 -6
  555. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
  556. package/src/api/user/user.build.js +0 -16
  557. package/src/cli/env.js +0 -177
  558. package/src/client/components/core/Blockchain.js +0 -41
  559. package/src/client/components/core/Blog.js +0 -9
  560. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  561. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
  562. package/src/client/public/default/assets/background/dark.jpg +0 -0
  563. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  564. package/src/client/public/default/assets/background/white0.jpg +0 -0
  565. package/src/client/public/doc/favicon.ico +0 -0
  566. package/src/client/public/doc/sitemap +0 -148
  567. package/src/server/downloader.js +0 -73
  568. package/src/server/environment.js +0 -98
package/src/cli/app.js ADDED
@@ -0,0 +1,402 @@
1
+ /**
2
+ * App domain: one application deployment's runtime environment.
3
+ *
4
+ * Its durable source is that deployment's env file under `engine-private/conf/<deployId>/`.
5
+ * The deployment id is resolved from the repository context, never passed as a path, so a
6
+ * caller says `--env development` and gets `.env.development` — or its sub-configuration
7
+ * variant when `--args sub-conf=<name>` names one.
8
+ *
9
+ * A custom instance is a deployment too: `--args instance-id=<id>` addresses that instance's own
10
+ * `instances/<id>/env/<env>.env` and its own `<deployId>-<instanceId>-<env>-env` Secret, so an
11
+ * instance's runtime environment is managed through this domain rather than by reaching into the
12
+ * private conf tree by hand.
13
+ *
14
+ * Implements the canonical domain action set; see {@link UnderpostDomains.DOMAIN_ACTIONS}.
15
+ * @module src/cli/app.js
16
+ * @namespace UnderpostApp
17
+ */
18
+
19
+ import dotenv from 'dotenv';
20
+ import fs from 'fs-extra';
21
+
22
+ import {
23
+ cleanDeployEnvFiles,
24
+ DEFAULT_DEPLOY_ID,
25
+ deployEnvContentFactory,
26
+ deployEnvFilePath,
27
+ deployOciEnvFilePath,
28
+ instanceEnvFilePath,
29
+ loadConf,
30
+ } from '../server/runtime/conf.js';
31
+ import { domainContextFactory } from './domains.js';
32
+ import { loggerFactory } from '../server/ops/logger.js';
33
+ import { readDeployRoutes } from '../server/network/router.js';
34
+ import { shellExec } from '../server/runtime/process.js';
35
+ import { writeEnv } from '../server/runtime/environment.js';
36
+ import { isReservedEnvKey } from './host.js';
37
+ import Underpost from '../index.js';
38
+
39
+ const logger = loggerFactory(import.meta);
40
+
41
+ /**
42
+ * Name of the Kubernetes Secret a deployment's environment is projected into. An instance carries
43
+ * its own, under the `<deployId>-<instanceId>` prefix every other instance object already uses.
44
+ */
45
+ const appSecretName = (deployId, env, instanceId = '') =>
46
+ `${instanceId ? `${deployId}-${instanceId}` : deployId}-${env}-env`;
47
+
48
+ // This domain's local runtime: the working-tree file `loadConf` materializes and the server
49
+ // reads. `publish` is the inverse of `load`, so both ends name the same file.
50
+ const LOCAL_RUNTIME_ENV_PATH = './.env';
51
+
52
+ /**
53
+ * @class UnderpostApp
54
+ * @description Application deployment environment domain.
55
+ * @memberof UnderpostApp
56
+ */
57
+ class UnderpostApp {
58
+ static API = {
59
+ /**
60
+ * Resolves the deployment id from the repository/deployment context.
61
+ *
62
+ * Most specific first: an explicit `--args deploy-id=`, the ambient `DEPLOY_ID` a loaded
63
+ * environment exports, the host store the node was bootstrapped with, then the first routed
64
+ * deploy. Falls back to the default deploy id, so resolution is total.
65
+ * @param {object} [context] - Normalized domain context, or `{ args }`.
66
+ * @returns {string} Deployment id.
67
+ * @memberof UnderpostApp
68
+ */
69
+ deployId(context = {}) {
70
+ const routed = readDeployRoutes();
71
+ return (
72
+ `${context.args?.['deploy-id'] ?? context.deployId ?? ''}`.trim() ||
73
+ `${process.env.DEPLOY_ID || ''}`.trim() ||
74
+ `${Underpost.host.store.get('DEPLOY_ID', undefined, { disableLog: true }) || ''}`.trim() ||
75
+ (routed.length > 0 ? routed[0] : '') ||
76
+ DEFAULT_DEPLOY_ID
77
+ );
78
+ },
79
+
80
+ /**
81
+ * Resolves the custom instance this invocation addresses, if any.
82
+ * @param {object} [context] - Normalized domain context, or `{ args }`.
83
+ * @returns {string} Instance id, or the empty string for the deployment itself.
84
+ * @memberof UnderpostApp
85
+ */
86
+ instanceId(context = {}) {
87
+ return `${context.args?.['instance-id'] ?? context.instanceId ?? ''}`.trim();
88
+ },
89
+
90
+ /**
91
+ * Resolves the durable source for an environment.
92
+ *
93
+ * `--args instance-id=` selects that instance's own env file. Otherwise a named
94
+ * sub-configuration selects `.env.<env>.<subConf>` when that file exists and degrades
95
+ * to the plain `.env.<env>` when it does not — the same precedence
96
+ * {@link ServerConfBuilder.loadConf} applies, so both agree on which file is in effect.
97
+ * @param {object} [context] - Normalized domain context.
98
+ * @returns {string} Path to the deployment or instance env file.
99
+ * @memberof UnderpostApp
100
+ */
101
+ envPath(context = {}) {
102
+ const env = `${context.env ?? ''}`.trim() || 'production';
103
+ const instanceId = UnderpostApp.API.instanceId(context);
104
+ if (instanceId) return instanceEnvFilePath(UnderpostApp.API.deployId(context), instanceId, env);
105
+ return deployEnvFilePath(
106
+ UnderpostApp.API.deployId(context),
107
+ env,
108
+ `${context.args?.['sub-conf'] ?? process.env.DEPLOY_SUB_CONF ?? ''}`.trim(),
109
+ );
110
+ },
111
+
112
+ /**
113
+ * Resolves the environment for a container runtime: the durable source with its
114
+ * `.env.<env>.oci` overlay applied. Used wherever the consumer is a container image rather
115
+ * than this host — the cluster Secret projection above all.
116
+ * @param {object} [context] - Normalized domain context.
117
+ * @returns {{source: string, overlay: string|null, content: string, values: Object<string,string>}}
118
+ * The resolved environment.
119
+ * @memberof UnderpostApp
120
+ */
121
+ ociEnv(context = {}) {
122
+ // An instance env file is already the container's environment — `instance-build-manifest`
123
+ // derives it for that runtime — so there is no host/container split to overlay away.
124
+ const source = UnderpostApp.API.envPath(context);
125
+ if (UnderpostApp.API.instanceId(context))
126
+ return {
127
+ source,
128
+ overlay: null,
129
+ content: fs.existsSync(source) ? fs.readFileSync(source, 'utf8') : '',
130
+ values: UnderpostApp.API.read(context),
131
+ };
132
+ return deployEnvContentFactory(
133
+ UnderpostApp.API.deployId(context),
134
+ `${context.env ?? ''}`.trim() || 'production',
135
+ `${context.args?.['sub-conf'] ?? process.env.DEPLOY_SUB_CONF ?? ''}`.trim(),
136
+ { oci: true },
137
+ );
138
+ },
139
+
140
+ /**
141
+ * Parses a deployment's environment. An absent source reads as `{}`.
142
+ * @param {object} [context] - Normalized domain context.
143
+ * @returns {Object<string, string>} Parsed deployment environment.
144
+ * @memberof UnderpostApp
145
+ */
146
+ read(context = {}) {
147
+ const envPath = UnderpostApp.API.envPath(context);
148
+ return fs.existsSync(envPath) ? dotenv.parse(fs.readFileSync(envPath, 'utf8')) : {};
149
+ },
150
+
151
+ // ── canonical domain actions ────────────────────────────────────────────────────────────
152
+
153
+ /**
154
+ * Onboards the app domain: resolves the deployment id, confirms its environment source
155
+ * exists, then loads it. Idempotent.
156
+ * @param {object} context - Normalized domain context.
157
+ * @returns {{deployId: string, source: string, keys: number}} What was onboarded.
158
+ * @memberof UnderpostApp
159
+ */
160
+ setup(context = {}) {
161
+ context = domainContextFactory(context);
162
+ const deployId = UnderpostApp.API.deployId(context);
163
+ const source = UnderpostApp.API.envPath(context);
164
+ if (!fs.existsSync(source)) throw new Error(`[app] deployment environment not found: ${source}`);
165
+ if (context.dryRun) {
166
+ logger.info('[dry-run] app setup would load', { deployId, source });
167
+ return { deployId, source, keys: Object.keys(UnderpostApp.API.read(context)).length };
168
+ }
169
+ const { keys } = UnderpostApp.API.load(context);
170
+ return { deployId, source, keys };
171
+ },
172
+
173
+ /**
174
+ * Materializes the deployment environment into this domain's local runtime: the working-tree
175
+ * `./.env` copies and the in-process `Config.default` the server reads.
176
+ *
177
+ * Deterministic: the same environment selector and repository context always resolve the
178
+ * same file, and the working tree is rebuilt from it rather than merged into.
179
+ * @param {object} context - Normalized domain context.
180
+ * @returns {{source: string, keys: number}} Which file was loaded and how much of it.
181
+ * @memberof UnderpostApp
182
+ */
183
+ load(context = {}) {
184
+ context = domainContextFactory(context);
185
+ const deployId = UnderpostApp.API.deployId(context);
186
+ const envPath = UnderpostApp.API.envPath(context);
187
+ if (!fs.existsSync(envPath)) throw new Error(`[app] deployment environment not found: ${envPath}`);
188
+ const values = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
189
+ if (context.dryRun) {
190
+ logger.info('[dry-run] app load would materialize the working tree', {
191
+ deployId,
192
+ source: envPath,
193
+ keys: Object.keys(values).length,
194
+ });
195
+ return { source: envPath, keys: Object.keys(values).length };
196
+ }
197
+ // Deliberately not the host configuration store: that store is host-scoped and holds the node's
198
+ // own configuration, so writing a deployment's environment there would erase it.
199
+ process.env.NODE_ENV = context.env;
200
+ const instanceId = UnderpostApp.API.instanceId(context);
201
+ // `loadConf` materializes a deployment's working tree from its own conf; an instance has no
202
+ // conf of its own, so its file is the local runtime env directly.
203
+ if (instanceId) writeEnv(LOCAL_RUNTIME_ENV_PATH, values);
204
+ else loadConf(deployId, `${context.args['sub-conf'] ?? ''}`.trim() || undefined);
205
+ // The resolution loadConf performed, not `ociEnv()`, which forces the overlay on: a
206
+ // skipped overlay and an applied one were indistinguishable in the pod log.
207
+ const resolved = deployEnvContentFactory(deployId, context.env, `${context.args?.['sub-conf'] ?? ''}`.trim());
208
+ const inContainer = Underpost.state.isInsideContainer();
209
+ logger.info('Deployment environment loaded', {
210
+ deployId,
211
+ instanceId: instanceId || null,
212
+ source: envPath,
213
+ inContainer,
214
+ ociOverlay: resolved.overlay,
215
+ keys: Object.keys(values).length,
216
+ });
217
+ // A container that resolves no overlay runs on the host-scoped endpoints of the base file —
218
+ // a loopback database, a local cache — and fails minutes later at the first connection,
219
+ // pointing at the endpoint rather than at the conf checkout that is missing the overlay.
220
+ // Named rather than thrown: a deployment is allowed to have no overlay for an environment.
221
+ if (inContainer && !instanceId && !resolved.overlay)
222
+ logger.warn('No OCI env overlay resolved; container is running on host-scoped values', {
223
+ deployId,
224
+ env: context.env,
225
+ expected: deployOciEnvFilePath(deployId, context.env),
226
+ });
227
+ return { source: envPath, keys: Object.keys(values).length };
228
+ },
229
+
230
+ /**
231
+ * Writes this domain's local runtime back into the deployment's durable source.
232
+ *
233
+ * The exact inverse of `load`, so it reads the working-tree `./.env` that `load` materialized
234
+ * — never the host configuration store, which belongs to the host domain and carries the node's
235
+ * configuration rather than this deployment's.
236
+ * Refuses to overwrite an existing source without `--force`.
237
+ * @param {object} context - Normalized domain context.
238
+ * @returns {{target: string, keys: number}} What was written.
239
+ * @memberof UnderpostApp
240
+ */
241
+ publish(context = {}) {
242
+ context = domainContextFactory(context);
243
+ const target = UnderpostApp.API.envPath(context);
244
+ const source = LOCAL_RUNTIME_ENV_PATH;
245
+ if (!fs.existsSync(source))
246
+ throw new Error(`[app] ${source} not found; run \`underpost app load\` before publishing`);
247
+ const values = dotenv.parse(fs.readFileSync(source, 'utf8'));
248
+ const keys = Object.keys(values);
249
+ if (keys.length === 0) throw new Error(`[app] ${source} is empty; nothing to publish`);
250
+ if (fs.existsSync(target) && !context.force)
251
+ throw new Error(`[app] ${target} already exists; re-run with --force to overwrite it`);
252
+ if (context.dryRun) {
253
+ logger.info('[dry-run] app publish would write', { target, keys: keys.length });
254
+ return { target, keys: keys.length };
255
+ }
256
+ writeEnv(target, values);
257
+ logger.info('Deployment environment published', { target, keys: keys.length });
258
+ return { target, keys: keys.length };
259
+ },
260
+
261
+ /**
262
+ * Projects the deployment environment into the cluster as its own Secret, so a workload can
263
+ * inject it with `envFrom` alongside the host configuration.
264
+ * Idempotent — delete-then-apply converges on the current source.
265
+ * @param {object} context - Normalized domain context.
266
+ * @returns {{secret: string, namespace: string, env: string}} What was projected.
267
+ * @memberof UnderpostApp
268
+ */
269
+ apply(context = {}) {
270
+ context = domainContextFactory(context);
271
+ const deployId = UnderpostApp.API.deployId(context);
272
+ const envFilePath = UnderpostApp.API.envPath(context);
273
+ if (!fs.existsSync(envFilePath)) throw new Error(`[app] deployment environment not found: ${envFilePath}`);
274
+ const secret = appSecretName(deployId, context.env, UnderpostApp.API.instanceId(context));
275
+ // This Secret is consumed only by container workloads, so the OCI overlay is applied
276
+ // unconditionally here — the host projecting it is not the runtime that reads it.
277
+ const { overlay, content } = UnderpostApp.API.ociEnv(context);
278
+ if (context.dryRun) {
279
+ logger.info('[dry-run] app apply would publish the Secret', {
280
+ secret,
281
+ namespace: context.namespace,
282
+ source: envFilePath,
283
+ overlay,
284
+ });
285
+ return { secret, namespace: context.namespace, env: context.env, overlay };
286
+ }
287
+ // The same reserved-key filter the host domain applies: an injected PATH would override
288
+ // the container image's own no matter which Secret carried it.
289
+ const sanitizedEnvPath = `${envFilePath}.secret`;
290
+ fs.writeFileSync(
291
+ sanitizedEnvPath,
292
+ content
293
+ .split('\n')
294
+ .filter((line) => {
295
+ const trimmed = line.trimStart();
296
+ if (!trimmed || trimmed.startsWith('#')) return true;
297
+ const key = line.slice(0, line.indexOf('=')).trim();
298
+ return !key || !isReservedEnvKey(key);
299
+ })
300
+ .join('\n'),
301
+ );
302
+ try {
303
+ shellExec(`kubectl delete secret ${secret} -n ${context.namespace} --ignore-not-found`);
304
+ shellExec(
305
+ `kubectl create secret generic ${secret} --from-env-file=${sanitizedEnvPath} --dry-run=client -o yaml | kubectl apply -f - -n ${context.namespace}`,
306
+ );
307
+ } finally {
308
+ fs.removeSync(sanitizedEnvPath);
309
+ }
310
+ logger.info('Deployment environment applied', {
311
+ secret,
312
+ env: context.env,
313
+ namespace: context.namespace,
314
+ overlay,
315
+ });
316
+ return { secret, namespace: context.namespace, env: context.env, overlay };
317
+ },
318
+
319
+ /**
320
+ * Read-only report: the resolved deployment id, which source is in effect, and whether the
321
+ * cluster projection exists.
322
+ * @param {object} context - Normalized domain context.
323
+ * @returns {object} Report.
324
+ * @memberof UnderpostApp
325
+ */
326
+ status(context = {}) {
327
+ context = domainContextFactory(context);
328
+ const deployId = UnderpostApp.API.deployId(context);
329
+ const source = UnderpostApp.API.envPath(context);
330
+ const present = fs.existsSync(source);
331
+ const secret = appSecretName(deployId, context.env, UnderpostApp.API.instanceId(context));
332
+ const projected = shellExec(`kubectl get secret ${secret} -n ${context.namespace} -o name`, {
333
+ silent: true,
334
+ stdout: true,
335
+ silentOnError: true,
336
+ disableLog: true,
337
+ });
338
+ const instanceId = UnderpostApp.API.instanceId(context);
339
+ const ociOverlay = instanceId ? '' : deployOciEnvFilePath(deployId, context.env);
340
+ const report = {
341
+ domain: 'app',
342
+ env: context.env,
343
+ namespace: context.namespace,
344
+ deployId,
345
+ instanceId: instanceId || null,
346
+ source,
347
+ sourcePresent: present,
348
+ ociOverlay: ociOverlay && fs.existsSync(ociOverlay) ? ociOverlay : null,
349
+ keys: present ? Object.keys(UnderpostApp.API.read(context)).length : 0,
350
+ clusterSecret: `${projected ?? ''}`.trim() ? secret : null,
351
+ };
352
+ logger.info('app status', report);
353
+ return report;
354
+ },
355
+
356
+ /**
357
+ * Replaces the live projection: deletes the deployment's Secret and re-applies it.
358
+ * @param {object} context - Normalized domain context.
359
+ * @returns {object} The re-applied projection.
360
+ * @memberof UnderpostApp
361
+ */
362
+ rotate(context = {}) {
363
+ context = domainContextFactory(context);
364
+ const secret = appSecretName(
365
+ UnderpostApp.API.deployId(context),
366
+ context.env,
367
+ UnderpostApp.API.instanceId(context),
368
+ );
369
+ if (context.dryRun) {
370
+ logger.info('[dry-run] app rotate would re-project the Secret', { secret, namespace: context.namespace });
371
+ return { secret, namespace: context.namespace, env: context.env };
372
+ }
373
+ shellExec(`kubectl delete secret ${secret} -n ${context.namespace} --ignore-not-found`);
374
+ return UnderpostApp.API.apply(context);
375
+ },
376
+
377
+ /**
378
+ * Withdraws the deployment environment from the local filesystem: removes the working-tree
379
+ * `.env*` files `loadConf` materializes. `--force` also drops the deployment's cluster Secret.
380
+ * @param {object} context - Normalized domain context.
381
+ * @returns {{removed: Array<string>, removedSecret: string|null}} What was withdrawn.
382
+ * @memberof UnderpostApp
383
+ */
384
+ clean(context = {}) {
385
+ context = domainContextFactory(context);
386
+ const secret = context.force
387
+ ? appSecretName(UnderpostApp.API.deployId(context), context.env, UnderpostApp.API.instanceId(context))
388
+ : null;
389
+ if (context.dryRun) {
390
+ logger.info('[dry-run] app clean would remove the working-tree env files', { secret });
391
+ return { removed: [], removedSecret: secret };
392
+ }
393
+ const removed = cleanDeployEnvFiles();
394
+ if (secret) shellExec(`kubectl delete secret ${secret} -n ${context.namespace} --ignore-not-found`);
395
+ logger.info('Deployment environment withdrawn', { files: removed, secret });
396
+ return { removed, removedSecret: secret };
397
+ },
398
+ };
399
+ }
400
+
401
+ export default UnderpostApp;
402
+ export { appSecretName, UnderpostApp };
@@ -5,12 +5,12 @@
5
5
  */
6
6
 
7
7
  import { fileURLToPath } from 'url';
8
- import { getNpmRootPath } from '../server/environment.js';
9
- import { pbcopy, shellExec } from '../server/process.js';
10
- import { loggerFactory, loggerMiddleware } from '../server/logger.js';
8
+ import { getNpmRootPath } from '../server/runtime/environment.js';
9
+ import { pbcopy, shellExec } from '../server/runtime/process.js';
10
+ import { loggerFactory, loggerMiddleware } from '../server/ops/logger.js';
11
11
  import fs from 'fs-extra';
12
12
  import path from 'path';
13
- import Downloader from '../server/downloader.js';
13
+ import Downloader from '../server/storage/downloader.js';
14
14
  import { newInstance, range, s4, timer } from '../client/components/core/CommonJs.js';
15
15
  import { spawnSync } from 'child_process';
16
16
  import Underpost from '../index.js';
@@ -97,7 +97,7 @@ class UnderpostBaremetal {
97
97
  * @param {boolean} [options.worker=false] - Flag to designate the machine as a worker node.
98
98
  * @param {string} [options.control=''] - Specifies the control node for the baremetal machine.
99
99
  * @param {string} [options.sshKeyDir=''] - Specifies the directory containing SSH keys for the baremetal machine.
100
- * @param {string} [options.deployId=''] - Specifies the deployment ID for SSH key resolution.
100
+ * @param {string} [options.deployId=''] - Specifies the deployment ID used to resolve the private engine repo cloned onto the node.
101
101
  * @param {string} [options.engineRepo=''] - Specifies the custom engine repository URL.
102
102
  * @param {string} [options.engineBranch=''] - Specifies the custom engine repository branch.
103
103
  * @param {string} [options.enginePrivateRepo=''] - Specifies the custom private engine repository URL.
@@ -943,7 +943,7 @@ rm -rf ${artifacts.join(' ')}`);
943
943
  `id root`,
944
944
  `ls -la /home/root/.ssh/`,
945
945
  `cat /home/root/.ssh/authorized_keys`,
946
- 'underpost test',
946
+ 'cd /home/dd/engine && node bin test unit,infra',
947
947
  ],
948
948
  });
949
949
  }
@@ -1490,7 +1490,7 @@ rm -rf ${artifacts.join(' ')}`);
1490
1490
  if (!joinResult.ok || !joinCommand) {
1491
1491
  throw new Error(
1492
1492
  `Failed to retrieve kubeadm join command from control-plane ${controlUser}@${controlIp} using key "${keyPath}" (code ${joinResult.code}). ` +
1493
- `Ensure that key authorizes ${controlUser}@${controlIp} — pass --deploy-id <id> --user <user> (key from engine-private/conf/<id>/users/<user>) ` +
1493
+ `Ensure that key authorizes ${controlUser}@${controlIp} — pass --user <user> (key from engine-private/deploy/users/<user>) ` +
1494
1494
  `or --ssh-key-dir <dir> to use the key/user the control-plane accepts. stderr: ${joinResult.stderr.slice(-300)}`,
1495
1495
  );
1496
1496
  }
@@ -1514,7 +1514,6 @@ rm -rf ${artifacts.join(' ')}`);
1514
1514
  }
1515
1515
 
1516
1516
  // Secrets needed on the node to clone the private engine-private repo
1517
- // (engine-private/conf/.../.env.production for `node bin run secret`).
1518
1517
  const githubUsername = Underpost.baremetal.readEngineConfig('GITHUB_USERNAME') || 'underpostnet';
1519
1518
  const githubEnv = {
1520
1519
  GITHUB_TOKEN: Underpost.baremetal.readEngineConfig('GITHUB_TOKEN'),
@@ -1988,7 +1987,7 @@ rm -rf ${artifacts.join(' ')}`);
1988
1987
  try {
1989
1988
  return { machine };
1990
1989
  } catch (error) {
1991
- console.log(error);
1990
+ console.error(error);
1992
1991
  logger.error(error);
1993
1992
  throw new Error(`Failed to create MAAS machine. Output:\n${machine}`);
1994
1993
  }
@@ -2597,11 +2596,10 @@ shell
2597
2596
  *
2598
2597
  * Key-dir precedence:
2599
2598
  * 1. `--ssh-key-dir <dir>` (explicit path)
2600
- * 2. `--deploy-id <id>` (+ `--user <user>`) → `engine-private/conf/<id>/users/<user>`
2601
- * (the same user↔deployId↔key convention `src/cli/ssh.js` writes; no key path needed)
2602
- * 3. workflow `sshKeyDir`
2603
- * 4. workflow `deployId` (+ `user`)
2604
- * 5. default `engine-private/deploy`
2599
+ * 2. workflow `sshKeyDir`
2600
+ * 3. a non-root user `engine-private/deploy/users/<user>`
2601
+ * (the cluster scoped key store `src/cli/ssh.js` writes; no key path needed)
2602
+ * 4. default `engine-private/deploy` (the controller key, i.e. root)
2605
2603
  *
2606
2604
  * User precedence: `--user` > workflow `user` > `root`. A leading `~` in the
2607
2605
  * resolved dir is expanded to the user's home.
@@ -2615,13 +2613,13 @@ shell
2615
2613
  resolveSshKeyPaths({ options = {}, workflowsConfig = {}, workflowId = '' } = {}) {
2616
2614
  const wf = workflowsConfig?.[workflowId] || {};
2617
2615
  const user = options.user || wf.user || 'root';
2616
+ // Kept for the private engine repo naming only; SSH keys are cluster scoped.
2618
2617
  const deployId = options.deployId || wf.deployId || '';
2619
2618
 
2620
2619
  let dir;
2621
2620
  if (options.sshKeyDir) dir = options.sshKeyDir;
2622
- else if (options.deployId) dir = `engine-private/conf/${options.deployId}/users/${user}`;
2623
2621
  else if (wf.sshKeyDir) dir = wf.sshKeyDir;
2624
- else if (deployId) dir = `engine-private/conf/${deployId}/users/${user}`;
2622
+ else if (user !== 'root') dir = path.normalize(Underpost.ssh.userKeyDir(user));
2625
2623
  else dir = 'engine-private/deploy';
2626
2624
 
2627
2625
  if (dir.startsWith('~')) dir = path.join(process.env.HOME || '', dir.slice(1));
@@ -2633,10 +2631,10 @@ shell
2633
2631
  * @description Resolves the login accounts baked into the deployed OS. Always
2634
2632
  * creates TWO admin accounts so a console login is guaranteed:
2635
2633
  * 1. the MAAS admin (MAAS_ADMIN_USERNAME / MAAS_ADMIN_PASS) — password login,
2636
- * 2. the deploy user (`--user`, e.g. admin) — its conf.node.json
2637
- * password (or MAAS_ADMIN_PASS), plus the SSH key.
2638
- * root always gets MAAS_ADMIN_PASS. The deploy user/password come from
2639
- * `engine-private/conf/<deployId>/conf.node.json` (`users[user]`).
2634
+ * 2. the deploy user (`--user`, e.g. admin) — its cluster config password
2635
+ * (or MAAS_ADMIN_PASS), plus the SSH key.
2636
+ * root always gets MAAS_ADMIN_PASS. The deploy user/password come from the
2637
+ * cluster users registry `engine-private/deploy/conf.users.json`.
2640
2638
  * @param {object} params
2641
2639
  * @param {object} [params.options={}] - CLI options.
2642
2640
  * @param {object} [params.workflowsConfig={}] - Loaded workflows config.
@@ -2645,21 +2643,18 @@ shell
2645
2643
  * @memberof UnderpostBaremetal
2646
2644
  */
2647
2645
  resolveInstallCredentials({ options = {}, workflowsConfig = {}, workflowId = '' } = {}) {
2648
- const { user, deployId } = Underpost.baremetal.resolveSshKeyPaths({ options, workflowsConfig, workflowId });
2646
+ const { user } = Underpost.baremetal.resolveSshKeyPaths({ options, workflowsConfig, workflowId });
2649
2647
 
2650
2648
  let confUser = {};
2651
- if (deployId) {
2652
- const confPath = `engine-private/conf/${deployId}/conf.node.json`;
2653
- if (fs.existsSync(confPath)) {
2654
- try {
2655
- confUser = JSON.parse(fs.readFileSync(confPath, 'utf8'))?.users?.[user] || {};
2656
- } catch (error) {
2657
- logger.warn(`Failed to parse ${confPath}: ${error.message}`);
2658
- }
2659
- } else {
2660
- logger.warn(`conf.node.json not found at ${confPath}; using MAAS_ADMIN_* defaults`);
2661
- }
2649
+ try {
2650
+ confUser = Underpost.ssh.findUser(user) || {};
2651
+ } catch (error) {
2652
+ logger.warn(`Failed to parse ${Underpost.ssh.usersConfPath()}: ${error.message}`);
2662
2653
  }
2654
+ if (!confUser.user)
2655
+ logger.warn(
2656
+ `User '${user}' is not registered in ${Underpost.ssh.usersConfPath()}; using MAAS_ADMIN_* defaults`,
2657
+ );
2663
2658
 
2664
2659
  const maasPass = process.env.MAAS_ADMIN_PASS || '';
2665
2660
  const rootPassword = maasPass;
@@ -2667,7 +2662,7 @@ shell
2667
2662
  const adminUsername = process.env.MAAS_ADMIN_USERNAME || 'maas';
2668
2663
  const adminPassword = maasPass;
2669
2664
  // User 2: the deploy user (only when distinct from root/maas admin).
2670
- const deployUsername = deployId && user && user !== 'root' && user !== adminUsername ? user : '';
2665
+ const deployUsername = user && user !== 'root' && user !== adminUsername ? user : '';
2671
2666
  const deployPassword = deployUsername ? confUser.password || maasPass : '';
2672
2667
 
2673
2668
  if (!rootPassword) {
@@ -2682,14 +2677,14 @@ shell
2682
2677
  * @method readEngineConfig
2683
2678
  * @description Reads an engine config/secret value (e.g. GITHUB_TOKEN) on the
2684
2679
  * controller. Prefers the loaded process env, falling back to
2685
- * `node bin config get --plain <key>`.
2680
+ * `node bin host get --plain <key>`.
2686
2681
  * @param {string} key - Config/env key name.
2687
2682
  * @returns {string} The resolved value, or '' if unset.
2688
2683
  * @memberof UnderpostBaremetal
2689
2684
  */
2690
2685
  readEngineConfig(key) {
2691
2686
  if (process.env[key]) return process.env[key];
2692
- const out = shellExec(`node bin config get --plain ${key}`, {
2687
+ const out = shellExec(`node bin host get --plain ${key}`, {
2693
2688
  stdout: true,
2694
2689
  silent: true,
2695
2690
  silentOnError: true,