@underpostnet/cyberia 3.2.90 → 3.3.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +16 -0
  3. package/.github/workflows/coverall.cyberia.ci.yml +107 -0
  4. package/.github/workflows/cyberia-client.cd.yml +6 -18
  5. package/.github/workflows/cyberia-server.cd.yml +6 -18
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +6 -78
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +42 -21
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +2 -9
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +47 -0
  22. package/CHANGELOG.md +581 -2417
  23. package/CLI-HELP.md +416 -127
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +4 -4
  27. package/README.md +21 -1
  28. package/bin/build.js +70 -43
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +372 -135
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +372 -135
  33. package/compose.env +16 -0
  34. package/conf.js +93 -4
  35. package/deploy/cyberia-client/deploy.sh +47 -0
  36. package/deploy/cyberia-client/package.sh +18 -0
  37. package/deploy/cyberia-client/state.sh +14 -0
  38. package/deploy/cyberia-server/deploy.sh +47 -0
  39. package/deploy/cyberia-server/package.sh +18 -0
  40. package/deploy/cyberia-server/state.sh +14 -0
  41. package/deploy/dd-cyberia/deploy.sh +22 -0
  42. package/deploy/dd-cyberia/init.sh +55 -0
  43. package/deploy/dd-cyberia/package.sh +17 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +116 -0
  46. package/deploy/lib/github-actions-logging.sh +594 -0
  47. package/deploy/lib/host.sh +185 -0
  48. package/deploy/lib/state.sh +62 -0
  49. package/deploy/pwa-microservices-template/deploy.sh +45 -0
  50. package/deploy/release/deploy.sh +32 -0
  51. package/deployment.yaml +7 -2
  52. package/docker-compose.yml +31 -37
  53. package/examples/static-page/README.md +19 -19
  54. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  55. package/hardhat/hardhat.config.js +1 -6
  56. package/hardhat/package-lock.json +104 -43
  57. package/hardhat/package.json +3 -3
  58. package/manifests/alertmanager/deployment.yaml +81 -0
  59. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  60. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
  61. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
  62. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  63. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  64. package/manifests/grafana/deployment.yaml +26 -7
  65. package/manifests/grafana/kustomization.yaml +1 -0
  66. package/manifests/grafana/service.yaml +6 -1
  67. package/manifests/mariadb/pv.yaml +1 -0
  68. package/manifests/mongodb/statefulset.yaml +9 -2
  69. package/manifests/mysql/pv-pvc.yaml +14 -1
  70. package/manifests/postgresql/pv.yaml +12 -1
  71. package/manifests/postgresql/pvc.yaml +1 -0
  72. package/manifests/prometheus/deployment.yaml +18 -22
  73. package/package.json +83 -10
  74. package/scripts/audit-selinux.sh +64 -0
  75. package/scripts/event-monitor.sh +56 -0
  76. package/scripts/gpu-diag.sh +0 -0
  77. package/scripts/ip-info.sh +0 -0
  78. package/scripts/k3s-node-setup.sh +30 -14
  79. package/scripts/kubeadm-node-setup.sh +40 -31
  80. package/scripts/lxd-vm-setup.sh +0 -0
  81. package/scripts/maas-nat-firewalld.sh +0 -0
  82. package/scripts/maas-setup.sh +8 -8
  83. package/scripts/nat-iptables.sh +2 -0
  84. package/scripts/rhel-grpc-setup.sh +0 -0
  85. package/scripts/rocky-kickstart.sh +25 -9
  86. package/scripts/selinux-normalize.sh +907 -0
  87. package/scripts/shutdown-machine.sh +843 -0
  88. package/scripts/test-monitor.sh +3 -3
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +1 -1
  99. package/src/api/cyberia-action/cyberia-action.service.js +2 -2
  100. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
  101. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
  102. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
  103. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  104. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  105. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  106. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  107. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  108. package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
  109. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
  110. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
  111. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
  112. package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
  113. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
  114. package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
  115. package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
  116. package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
  117. package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
  118. package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
  119. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  120. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
  121. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  122. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
  123. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  124. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  125. package/src/api/cyberia-map/cyberia-map.service.js +2 -2
  126. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  127. package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
  128. package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
  129. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  130. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  131. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  132. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  133. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  134. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  135. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -29
  136. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  137. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  138. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  139. package/src/api/default/default.controller.js +1 -1
  140. package/src/api/default/default.router.js +1 -1
  141. package/src/api/default/default.service.js +2 -2
  142. package/src/api/document/document.controller.js +1 -1
  143. package/src/api/document/document.router.js +1 -1
  144. package/src/api/document/document.service.js +2 -2
  145. package/src/api/file/file.controller.js +1 -1
  146. package/src/api/file/file.router.js +1 -1
  147. package/src/api/file/file.service.js +2 -2
  148. package/src/api/instance/instance.controller.js +1 -1
  149. package/src/api/instance/instance.router.js +1 -1
  150. package/src/api/instance/instance.service.js +2 -2
  151. package/src/api/ipfs/ipfs.controller.js +1 -1
  152. package/src/api/ipfs/ipfs.router.js +2 -2
  153. package/src/api/ipfs/ipfs.service.js +2 -2
  154. package/src/api/object-layer/object-layer.controller.js +1 -1
  155. package/src/api/object-layer/object-layer.model.js +204 -3
  156. package/src/api/object-layer/object-layer.router.js +2 -2
  157. package/src/api/object-layer/object-layer.service.js +4 -17
  158. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  159. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  160. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  161. package/src/api/test/test.controller.js +1 -1
  162. package/src/api/test/test.service.js +1 -1
  163. package/src/api/user/guest.service.js +3 -3
  164. package/src/api/user/user.controller.js +1 -1
  165. package/src/api/user/user.router.js +2 -2
  166. package/src/api/user/user.service.js +4 -4
  167. package/src/api.js +5 -9
  168. package/src/cli/app.js +391 -0
  169. package/src/cli/baremetal.js +30 -36
  170. package/src/cli/client.js +306 -0
  171. package/src/cli/cloud-init.js +3 -3
  172. package/src/cli/cluster.js +242 -135
  173. package/src/cli/db.js +126 -67
  174. package/src/cli/deploy.js +158 -60
  175. package/src/cli/docker-compose.js +5 -5
  176. package/src/cli/domains.js +184 -0
  177. package/src/cli/dotenv-store.js +143 -0
  178. package/src/cli/event.js +2281 -0
  179. package/src/cli/fs.js +3 -3
  180. package/src/cli/host.js +672 -0
  181. package/src/cli/image.js +4 -7
  182. package/src/cli/index.js +426 -134
  183. package/src/cli/ipfs.js +34 -30
  184. package/src/cli/kickstart.js +1 -1
  185. package/src/cli/kubectl.js +218 -41
  186. package/src/cli/lxd.js +3 -3
  187. package/src/cli/monitor.js +1359 -26
  188. package/src/cli/package.js +90 -0
  189. package/src/cli/release.js +73 -34
  190. package/src/cli/repository.js +564 -367
  191. package/src/cli/run.js +362 -654
  192. package/src/cli/secrets.js +2158 -964
  193. package/src/cli/ssh.js +651 -331
  194. package/src/cli/state.js +394 -0
  195. package/src/cli/static.js +2 -2
  196. package/src/cli/system.js +26 -13
  197. package/src/cli/test.js +199 -125
  198. package/src/cli/vultr.js +623 -0
  199. package/src/cli/wireguard.js +2930 -0
  200. package/src/client/components/core/CalendarCore.js +53 -96
  201. package/src/client/components/core/Docs.js +258 -211
  202. package/src/client/components/core/FileExplorer.js +0 -21
  203. package/src/client/components/core/PanelForm.js +4 -4
  204. package/src/client/components/core/Repository.js +56 -0
  205. package/src/client/components/core/Translate.js +7 -0
  206. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  207. package/src/client/components/core/Wallet.js +0 -11
  208. package/src/client/components/core/Worker.js +7 -1
  209. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  210. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
  211. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
  212. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
  213. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  214. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
  215. package/src/client/components/default/AppShellDefault.js +1 -1
  216. package/src/client/components/default/SettingsDefault.js +2 -2
  217. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  218. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  219. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  220. package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
  221. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
  222. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
  223. package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
  224. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  225. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  226. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  227. package/src/client/public/default/android-chrome-144x144.png +0 -0
  228. package/src/client/public/default/android-chrome-192x192.png +0 -0
  229. package/src/client/public/default/android-chrome-256x256.png +0 -0
  230. package/src/client/public/default/android-chrome-36x36.png +0 -0
  231. package/src/client/public/default/android-chrome-384x384.png +0 -0
  232. package/src/client/public/default/android-chrome-48x48.png +0 -0
  233. package/src/client/public/default/android-chrome-512x512.png +0 -0
  234. package/src/client/public/default/android-chrome-72x72.png +0 -0
  235. package/src/client/public/default/android-chrome-96x96.png +0 -0
  236. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  237. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  238. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  239. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  240. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  241. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  242. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  243. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  244. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  245. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  246. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  247. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  248. package/src/client/public/default/apple-touch-icon.png +0 -0
  249. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  250. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  251. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  252. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  253. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  254. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  255. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  256. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  257. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  258. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  259. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  260. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  261. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  262. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  263. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  264. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  265. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  266. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  267. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  268. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  269. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  270. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  271. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  272. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  273. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  274. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  275. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  276. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  277. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  278. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  279. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  280. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  281. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  282. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  283. package/src/client/public/default/assets/background/white.jpg +0 -0
  284. package/src/client/public/default/browserconfig.xml +1 -1
  285. package/src/client/public/default/favicon-16x16.png +0 -0
  286. package/src/client/public/default/favicon-32x32.png +0 -0
  287. package/src/client/public/default/favicon-48x48.png +0 -0
  288. package/src/client/public/default/favicon.ico +0 -0
  289. package/src/client/public/default/manifest.webmanifest +5 -5
  290. package/src/client/public/default/mstile-144x144.png +0 -0
  291. package/src/client/public/default/mstile-150x150.png +0 -0
  292. package/src/client/public/default/mstile-310x150.png +0 -0
  293. package/src/client/public/default/mstile-310x310.png +0 -0
  294. package/src/client/public/default/mstile-70x70.png +0 -0
  295. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  296. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  297. package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
  298. package/src/client/services/object-layer/object-layer.management.js +4 -4
  299. package/src/client/ssr/RootDocument.js +1 -1
  300. package/src/client/ssr/body/404.js +1 -1
  301. package/src/client/ssr/body/500.js +1 -1
  302. package/src/client/ssr/body/CacheControl.js +1 -1
  303. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  304. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  305. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  306. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  307. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  308. package/src/client/ssr/head/Css.js +1 -1
  309. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  310. package/src/client/ssr/head/DefaultScripts.js +1 -1
  311. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  312. package/src/client/ssr/head/Microdata.js +1 -1
  313. package/src/client/ssr/head/Production.js +1 -1
  314. package/src/client/ssr/head/Pwa.js +1 -1
  315. package/src/client/ssr/head/PwaItemledger.js +1 -1
  316. package/src/client/ssr/head/Seo.js +1 -1
  317. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  318. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  319. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  320. package/src/client/ssr/views/Cyberia404.js +7 -5
  321. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  322. package/src/client/ssr/views/Maintenance.js +1 -1
  323. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  324. package/src/client/ssr/views/Test.js +1 -1
  325. package/src/client/sw/core.sw.js +20 -14
  326. package/src/client-builder/client-build-docs.js +61 -46
  327. package/src/client-builder/client-build-live.js +2 -2
  328. package/src/client-builder/client-build.js +58 -44
  329. package/src/client-builder/client-dev-server.js +3 -3
  330. package/src/client-builder/client-icons.js +2 -2
  331. package/src/client-builder/ssr.js +3 -3
  332. package/src/client.build.js +3 -6
  333. package/src/client.dev.js +3 -6
  334. package/src/db/DataBaseProvider.js +186 -3
  335. package/src/db/mariadb/MariaDB.js +3 -2
  336. package/src/db/mongo/MongoBootstrap.js +273 -101
  337. package/src/db/mongo/MongooseDB.js +11 -8
  338. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  339. package/src/grpc/cyberia/grpc-server.js +1 -1
  340. package/src/index.js +103 -23
  341. package/src/mailer/EmailRender.js +2 -2
  342. package/src/mailer/MailerInterceptor.js +87 -0
  343. package/src/mailer/MailerProvider.js +50 -6
  344. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
  345. package/src/projects/cyberia/besu-genesis-generator.js +3 -3
  346. package/src/projects/cyberia/catalog-cyberia.js +54 -6
  347. package/src/projects/cyberia/gemini-client.js +1 -1
  348. package/src/projects/cyberia/generate-saga.js +15 -24
  349. package/src/projects/cyberia/hot-reload-trigger.js +1 -1
  350. package/src/projects/cyberia/instance-data.js +22 -3
  351. package/src/projects/cyberia/ipfs-client.js +4 -4
  352. package/src/projects/cyberia/map-preview-generator.js +1 -1
  353. package/src/projects/cyberia/object-layer.js +12 -22
  354. package/src/projects/cyberia/semantic-layer-generator.js +1 -1
  355. package/src/projects/underpost/catalog-underpost.js +13 -2
  356. package/src/proxy.js +4 -7
  357. package/src/runtime/cyberia-client/Dockerfile +9 -4
  358. package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
  359. package/src/runtime/cyberia-server/Dockerfile +9 -4
  360. package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
  361. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  362. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  363. package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
  364. package/src/runtime/engine-cyberia/compose.env +16 -0
  365. package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
  366. package/src/runtime/express/Express.js +32 -27
  367. package/src/runtime/lampp/Lampp.js +22 -70
  368. package/src/runtime/nginx/Nginx.js +1 -1
  369. package/src/runtime/wp/Wp.js +16 -48
  370. package/src/server/{catalog.js → build/catalog.js} +15 -5
  371. package/src/server/build/coverage.js +117 -0
  372. package/src/server/build/execution.js +402 -0
  373. package/src/server/build/package.js +465 -0
  374. package/src/server/build/testing.js +528 -0
  375. package/src/server/{dns.js → network/dns.js} +241 -14
  376. package/src/server/network/forward-proxy.js +541 -0
  377. package/src/server/{middlewares.js → network/middlewares.js} +59 -4
  378. package/src/server/network/node-capability.js +98 -0
  379. package/src/server/{peer.js → network/peer.js} +3 -3
  380. package/src/server/{proxy.js → network/proxy.js} +7 -13
  381. package/src/server/network/router.js +356 -0
  382. package/src/server/{tls.js → network/tls.js} +2 -2
  383. package/src/server/network/underpost-compression.js +186 -0
  384. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
  385. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
  386. package/src/server/{cri.js → ops/cri.js} +2 -2
  387. package/src/server/ops/cron.js +949 -0
  388. package/src/server/ops/event-notification.js +284 -0
  389. package/src/server/{logger.js → ops/logger.js} +108 -23
  390. package/src/server/ops/monitoring.js +1724 -0
  391. package/src/server/ops/systemd.js +259 -0
  392. package/src/server/{conf.js → runtime/conf.js} +521 -520
  393. package/src/server/runtime/config-scope.js +215 -0
  394. package/src/server/runtime/environment.js +149 -0
  395. package/src/server/{process.js → runtime/process.js} +153 -13
  396. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  397. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  398. package/src/server/{start.js → runtime/start.js} +128 -39
  399. package/src/server/{auth.js → security/auth.js} +7 -8
  400. package/src/server/security/container-storage.js +382 -0
  401. package/src/server/{crypto.js → security/crypto.js} +1 -1
  402. package/src/server/security/selinux.js +185 -0
  403. package/src/server/{backup.js → storage/backup.js} +17 -8
  404. package/src/server/{data-query.js → storage/data-query.js} +1 -1
  405. package/src/server/{downloader.js → storage/downloader.js} +2 -2
  406. package/src/server/storage/repository.js +68 -0
  407. package/src/server.js +4 -7
  408. package/src/ws/IoInterface.js +1 -1
  409. package/src/ws/IoServer.js +1 -1
  410. package/src/ws/core/core.ws.connection.js +1 -1
  411. package/src/ws/core/core.ws.emit.js +1 -1
  412. package/src/ws/core/core.ws.server.js +1 -1
  413. package/src/ws/default/default.ws.connection.js +1 -1
  414. package/src/ws/default/default.ws.emit.js +1 -1
  415. package/src/ws/default/default.ws.server.js +1 -1
  416. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  417. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  418. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  419. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  420. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
  421. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
  422. package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
  423. package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
  424. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  425. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  426. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  427. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  428. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  429. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  430. package/test/integration/infra/1-security/selinux.test.js +69 -0
  431. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  432. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  433. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  434. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  435. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  436. package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
  437. package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
  438. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  439. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  440. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  441. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  442. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  443. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  444. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +47 -6
  445. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -4
  446. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  447. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  448. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  449. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  450. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  451. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  452. package/test/support/shell-harness.js +73 -0
  453. package/test/unit/build-template.test.js +97 -0
  454. package/test/unit/build-workflow-offline.test.js +132 -0
  455. package/test/unit/catalog.test.js +71 -0
  456. package/test/unit/client-build-docs.test.js +334 -0
  457. package/test/unit/conf-loading.test.js +303 -0
  458. package/test/unit/conf-resolution.test.js +979 -0
  459. package/test/unit/coverage-artifact.test.js +130 -0
  460. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  461. package/test/unit/deploy-env-resolution.test.js +38 -0
  462. package/test/unit/deploy-log-table.test.js +447 -0
  463. package/test/unit/execution-profiles.test.js +219 -0
  464. package/test/unit/fleet-sync-source.test.js +149 -0
  465. package/test/unit/logger-redaction.test.js +112 -0
  466. package/test/unit/package.test.js +403 -0
  467. package/test/unit/prepare-host.test.js +299 -0
  468. package/test/unit/process-environment.test.js +18 -0
  469. package/test/unit/propagation-message.test.js +78 -0
  470. package/test/unit/redeploy-plan.test.js +24 -0
  471. package/test/unit/release-bump.test.js +474 -0
  472. package/test/unit/ssh-output-redaction.test.js +28 -0
  473. package/test/unit/start-options.test.js +46 -0
  474. package/test/unit/test-tiers.test.js +193 -0
  475. package/vitest.config.js +58 -0
  476. package/.nycrc +0 -9
  477. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  478. package/manifests/mongodb/pv-pvc.yaml +0 -59
  479. package/scripts/link-local-underpost-cli.sh +0 -6
  480. package/src/api/user/user.build.js +0 -16
  481. package/src/cli/env.js +0 -177
  482. package/src/client/components/core/Blockchain.js +0 -41
  483. package/src/client/components/core/Blog.js +0 -9
  484. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  485. package/src/client/public/default/assets/background/dark.jpg +0 -0
  486. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  487. package/src/client/public/default/assets/background/white0.jpg +0 -0
  488. package/src/client/public/doc/favicon.ico +0 -0
  489. package/src/client/public/doc/sitemap +0 -148
  490. package/src/server/cron.js +0 -476
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Runtime status contract and the in-pod internal status endpoint.
2
+ * Runtime status contract and the in-pod internal status endpoint: the base module of the
3
+ * `state` domain, the runtime monitoring / telemetry layer.
3
4
  *
4
5
  * Single source of truth for the Underpost runtime readiness signal (Phase 2 of
5
6
  * the two-phase deployment monitor). The runtime publishes its lifecycle here;
@@ -7,23 +8,34 @@
7
8
  * `kubectl port-forward`. Kubernetes pod readiness (Phase 1) is owned by kubelet
8
9
  * and is intentionally not modeled in this module.
9
10
  *
11
+ * Three observations make up the layer, and they are deliberately separate:
12
+ * - **execution state** — where the runtime is in its lifecycle (`container-status`)
13
+ * - **health indicators** — whether it is ready and whether it is still booting
14
+ * - **performance metrics** — uptime, memory and CPU of the process serving it
15
+ * {@link runtimeStatusPayload} carries the first for the monitor's failure classification;
16
+ * {@link runtimeTelemetryPayload} carries all three for an agent exporting them off-cluster.
17
+ *
10
18
  * Cross-process contract:
11
- * - In-pod, the canonical value lives in the underpost root env key
19
+ * - In-pod, the canonical value lives in the container state store key
12
20
  * `container-status`, written by `start.js`. For non-error phases it carries
13
21
  * the namespaced form `<deployId>-<env>-<phase>`; a fatal fault collapses to
14
22
  * the bare value `error`.
15
23
  * - The internal HTTP server exposes that value (normalized to the bare
16
24
  * contract phase) and never exposes secrets, env dumps, or configuration.
25
+ * Neither payload is ever built from `process.env` wholesale — each field is
26
+ * named, so a new environment variable can never widen what is published.
17
27
  *
18
- * @module src/server/runtime-status.js
28
+ * @module src/server/runtime/runtime-status.js
19
29
  * @namespace RuntimeStatus
20
30
  */
21
31
 
22
32
  import http from 'node:http';
33
+ import os from 'node:os';
23
34
  import fs from 'fs-extra';
24
35
  import dotenv from 'dotenv';
25
- import Underpost from '../index.js';
26
- import { loggerFactory } from './logger.js';
36
+ import Underpost from '../../index.js';
37
+ import { EXECUTION_PROFILES, activeExecutionProfile } from '../build/execution.js';
38
+ import { loggerFactory } from '../ops/logger.js';
27
39
 
28
40
  const logger = loggerFactory(import.meta);
29
41
 
@@ -41,9 +53,15 @@ const RUNTIME_STATUS = {
41
53
 
42
54
  const CONTAINER_STATUS_KEY = 'container-status';
43
55
  const START_CONTAINER_STATUS_KEY = 'start-container-status';
56
+ // The boot latch: present from the moment a runtime starts configuring itself until that runtime
57
+ // is listening. Container-scoped like the two above — same owner, same lifetime — so it lives in
58
+ // the container state store. It was previously written to the host configuration store, where
59
+ // `host load` and `host clean` erase the whole file and would silently drop the latch mid-boot.
60
+ const AWAIT_DEPLOY_KEY = 'await-deploy';
44
61
  const INTERNAL_STATUS_PATH = '/_internal/status';
45
62
  const INTERNAL_READY_PATH = '/_internal/ready';
46
63
  const INTERNAL_HEALTH_PATH = '/_internal/health';
64
+ const INTERNAL_TELEMETRY_PATH = '/_internal/telemetry';
47
65
 
48
66
  /**
49
67
  * Resolves the internal status port. Defaults to the deployment base `PORT`
@@ -117,22 +135,47 @@ const normalizeContainerStatus = (raw) => {
117
135
  * @returns {string|undefined}
118
136
  */
119
137
  const getRuntimeStatus = () =>
120
- normalizeContainerStatus(Underpost.env.get(CONTAINER_STATUS_KEY, undefined, { disableLog: true }));
138
+ normalizeContainerStatus(Underpost.state.get(CONTAINER_STATUS_KEY, undefined, { disableLog: true }));
121
139
 
122
140
  /**
123
- * Reads the start-container-status env key — an insulated marker set by the
124
- * start pipeline after it completes the running phase. Unlike container-status
125
- * (which external scripts / backup failures may clobber), this key is written
126
- * once and survives globalSecretClean. Used exclusively by the readinessProbe
127
- * endpoint so K8s pod readiness is never derailed by lifecycle noise.
141
+ * Reads the start-container-status key — an insulated marker the start pipeline writes once
142
+ * after completing the running phase. Unlike container-status, which lifecycle hooks and failure
143
+ * latches also write, this is only ever set by that pipeline, so the readinessProbe endpoint is
144
+ * never derailed by lifecycle noise.
128
145
  * @memberof RuntimeStatus
129
146
  * @returns {string|undefined}
130
147
  */
131
148
  const getStartContainerStatus = () => {
132
- const raw = Underpost.env.get(START_CONTAINER_STATUS_KEY, undefined, { disableLog: true });
149
+ const raw = Underpost.state.get(START_CONTAINER_STATUS_KEY, undefined, { disableLog: true });
133
150
  return raw && typeof raw === 'string' && raw.trim() ? raw.trim() : undefined;
134
151
  };
135
152
 
153
+ /**
154
+ * Latches this container as still bringing its runtime up. Cleared by {@link clearAwaitDeploy}
155
+ * once the runtime is listening; polled by `awaitDeployMonitor` in between.
156
+ * @memberof RuntimeStatus
157
+ * @returns {void}
158
+ */
159
+ const latchAwaitDeploy = () => {
160
+ Underpost.state.set(AWAIT_DEPLOY_KEY, new Date().toISOString());
161
+ };
162
+
163
+ /**
164
+ * Whether a runtime in this container is still coming up.
165
+ * @memberof RuntimeStatus
166
+ * @returns {boolean}
167
+ */
168
+ const isAwaitingDeploy = () => Boolean(Underpost.state.get(AWAIT_DEPLOY_KEY, undefined, { disableLog: true }));
169
+
170
+ /**
171
+ * Releases the boot latch. Called by the runtime once every configured host and path is bound.
172
+ * @memberof RuntimeStatus
173
+ * @returns {void}
174
+ */
175
+ const clearAwaitDeploy = () => {
176
+ Underpost.state.delete(AWAIT_DEPLOY_KEY);
177
+ };
178
+
136
179
  /**
137
180
  * Minimal, secret-free payload served by the internal status endpoint and used
138
181
  * by the monitor for failure classification and observability.
@@ -145,6 +188,43 @@ const runtimeStatusPayload = () => ({
145
188
  env: process.env.NODE_ENV ?? null,
146
189
  });
147
190
 
191
+ /**
192
+ * Live execution state, health indicators and performance metrics for this container: what a
193
+ * telemetry agent collects and exports off-cluster.
194
+ *
195
+ * A superset of {@link runtimeStatusPayload}, kept separate from it because the monitor's
196
+ * failure classification must not start depending on metrics that move on every read. Every
197
+ * field is named individually and none is read from the environment in bulk, so this can never
198
+ * become an env dump.
199
+ * @memberof RuntimeStatus
200
+ * @returns {object} Secret-free telemetry observation.
201
+ */
202
+ const runtimeTelemetryPayload = () => {
203
+ const memory = process.memoryUsage();
204
+ const cpu = process.cpuUsage();
205
+ return {
206
+ ...runtimeStatusPayload(),
207
+ instanceId: process.env.INSTANCE_ID ?? null,
208
+ health: {
209
+ // The insulated readiness marker, not the lifecycle status: the two disagree exactly when
210
+ // a lifecycle hook has moved container-status after the start pipeline signed off.
211
+ ready: Boolean(getStartContainerStatus()),
212
+ awaitingDeploy: isAwaitingDeploy(),
213
+ inContainer: Underpost.state.isInsideContainer(),
214
+ },
215
+ metrics: {
216
+ uptimeSeconds: Math.round(process.uptime()),
217
+ rssBytes: memory.rss,
218
+ heapUsedBytes: memory.heapUsed,
219
+ heapTotalBytes: memory.heapTotal,
220
+ cpuUserMicros: cpu.user,
221
+ cpuSystemMicros: cpu.system,
222
+ loadAverage1m: os.loadavg()[0],
223
+ },
224
+ observedAt: new Date().toISOString(),
225
+ };
226
+ };
227
+
148
228
  /**
149
229
  * Emits a structured, secret-free deployment transition event.
150
230
  * @memberof RuntimeStatus
@@ -167,10 +247,56 @@ const emitRuntimeEvent = ({ deployId, env, phase }) => {
167
247
  * @param {string} phase - One of {@link RUNTIME_STATUS}.
168
248
  */
169
249
  const setRuntimeStatus = (deployId, env, phase) => {
170
- Underpost.env.set(CONTAINER_STATUS_KEY, containerStatusValue(deployId, env, phase));
250
+ Underpost.state.set(CONTAINER_STATUS_KEY, containerStatusValue(deployId, env, phase));
171
251
  emitRuntimeEvent({ deployId, env, phase });
172
252
  };
173
253
 
254
+ /**
255
+ * Whether this process is executing under a test runner.
256
+ * @memberof RuntimeStatus
257
+ * @returns {boolean} True under `NODE_ENV=test` or a Vitest worker.
258
+ */
259
+ const isTestRuntime = () =>
260
+ process.env.NODE_ENV === 'test' || Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
261
+
262
+ /**
263
+ * Whether this process may write the runtime status contract.
264
+ *
265
+ * Only a live workload observes itself. A test run and a non-live execution profile both
266
+ * execute commands whose non-zero exit is the expected outcome — a suite asserting a failure
267
+ * path, a hermetic build eliding a cluster call — and neither is an observation of a running
268
+ * deployment. Letting them latch `container-status` published a false `error` to the CD
269
+ * monitor and failed rollouts that were healthy.
270
+ * @memberof RuntimeStatus
271
+ * @returns {boolean} True when this process speaks for a live container.
272
+ */
273
+ const runtimeStatusWritable = () =>
274
+ Underpost.state.isInsideContainer() &&
275
+ !isTestRuntime() &&
276
+ activeExecutionProfile().name === EXECUTION_PROFILES.LIVE_CLUSTER.name;
277
+
278
+ /**
279
+ * Latches the container as failed, for a failure detected outside the lifecycle phases — a shell
280
+ * command, a database connection, a backup. A no-op wherever the contract is not writable:
281
+ * outside a container, under a test runner, or under a non-live execution profile.
282
+ * @memberof RuntimeStatus
283
+ * @returns {void}
284
+ */
285
+ const latchRuntimeError = () => {
286
+ if (runtimeStatusWritable()) Underpost.state.set(CONTAINER_STATUS_KEY, RUNTIME_STATUS.ERROR);
287
+ };
288
+
289
+ /**
290
+ * Marks the start pipeline's own completion. Written once, read only by the readinessProbe.
291
+ * @memberof RuntimeStatus
292
+ * @param {string} deployId
293
+ * @param {string} env
294
+ * @returns {void}
295
+ */
296
+ const setStartContainerStatus = (deployId, env) => {
297
+ Underpost.state.set(START_CONTAINER_STATUS_KEY, containerStatusValue(deployId, env, RUNTIME_STATUS.RUNNING));
298
+ };
299
+
174
300
  let internalServer;
175
301
 
176
302
  /**
@@ -178,9 +304,10 @@ let internalServer;
178
304
  * the already-listening server. Exposes only the three internal endpoints and
179
305
  * never serves secrets or configuration.
180
306
  *
181
- * GET /_internal/status → 200, `{status, deployId, env}` (monitor transport)
182
- * GET /_internal/ready → 200 iff running-deployment, else 503 (readinessProbe)
183
- * GET /_internal/health → 200 while the process is alive (livenessProbe)
307
+ * GET /_internal/status → 200, `{status, deployId, env}` (monitor transport)
308
+ * GET /_internal/ready → 200 iff running-deployment, else 503 (readinessProbe)
309
+ * GET /_internal/health → 200 while the process is alive (livenessProbe)
310
+ * GET /_internal/telemetry → 200, state + health + metrics (telemetry agent)
184
311
  *
185
312
  * @memberof RuntimeStatus
186
313
  * @param {number} [port]
@@ -208,6 +335,8 @@ const startInternalStatusServer = (port = resolveInternalStatusPort()) => {
208
335
  : sendJson(503, { status: getRuntimeStatus() ?? null });
209
336
  case INTERNAL_STATUS_PATH:
210
337
  return sendJson(200, runtimeStatusPayload());
338
+ case INTERNAL_TELEMETRY_PATH:
339
+ return sendJson(200, runtimeTelemetryPayload());
211
340
  default:
212
341
  return sendJson(404, { error: 'not_found' });
213
342
  }
@@ -236,16 +365,26 @@ export {
236
365
  RUNTIME_STATUS,
237
366
  CONTAINER_STATUS_KEY,
238
367
  START_CONTAINER_STATUS_KEY,
368
+ AWAIT_DEPLOY_KEY,
239
369
  INTERNAL_STATUS_PATH,
240
370
  INTERNAL_READY_PATH,
241
371
  INTERNAL_HEALTH_PATH,
372
+ INTERNAL_TELEMETRY_PATH,
242
373
  resolveInternalStatusPort,
243
374
  deployStatusPort,
244
375
  containerStatusValue,
245
376
  normalizeContainerStatus,
246
377
  getRuntimeStatus,
247
378
  getStartContainerStatus,
379
+ latchAwaitDeploy,
380
+ isAwaitingDeploy,
381
+ clearAwaitDeploy,
382
+ isTestRuntime,
383
+ latchRuntimeError,
384
+ runtimeStatusWritable,
385
+ setStartContainerStatus,
248
386
  runtimeStatusPayload,
387
+ runtimeTelemetryPayload,
249
388
  setRuntimeStatus,
250
389
  startInternalStatusServer,
251
390
  stopInternalStatusServer,
@@ -2,21 +2,22 @@
2
2
  * The main runtime orchestrator responsible for reading configuration,
3
3
  * initializing services (Prometheus, Ports, DB, Mailer), and building the
4
4
  * specific server runtime for each host/path (e.g., nodejs, lampp).
5
- * @module src/server/runtime.js
5
+ * @module src/server/runtime/runtime.js
6
6
  * @namespace Runtime
7
7
  */
8
8
 
9
9
  import * as promClient from 'prom-client';
10
10
 
11
- import { loggerFactory } from './logger.js';
12
- import { newInstance } from '../client/components/core/CommonJs.js';
13
- import { Lampp } from '../runtime/lampp/Lampp.js';
14
- import { WpService } from '../runtime/wp/Wp.js';
11
+ import { loggerFactory } from '../ops/logger.js';
12
+ import { newInstance } from '../../client/components/core/CommonJs.js';
13
+ import { Lampp } from '../../runtime/lampp/Lampp.js';
14
+ import { WpService } from '../../runtime/wp/Wp.js';
15
15
  import { getInstanceContext, readConfJson } from './conf.js';
16
+ import { clearAwaitDeploy } from './runtime-status.js';
16
17
 
17
- import ExpressService from '../runtime/express/Express.js';
18
+ import ExpressService from '../../runtime/express/Express.js';
18
19
 
19
- import Underpost from '../index.js';
20
+ import Underpost from '../../index.js';
20
21
 
21
22
  const logger = loggerFactory(import.meta);
22
23
 
@@ -140,6 +141,7 @@ const buildRuntime = async () => {
140
141
  path,
141
142
  directory,
142
143
  rootHostPath,
144
+ repository,
143
145
  redirect,
144
146
  redirectTarget,
145
147
  resetRouter: currentPort === initPort,
@@ -176,7 +178,9 @@ const buildRuntime = async () => {
176
178
  }
177
179
 
178
180
  if (Lampp.enabled() && Lampp.router) Lampp.initService();
179
- Underpost.env.delete('await-deploy');
181
+ // Container-scoped boot latch, not host configuration: this releases the runtime this
182
+ // container just brought up, so it belongs to the same store as `container-status`.
183
+ clearAwaitDeploy();
180
184
  Underpost.start.logRuntimeRouter();
181
185
  };
182
186
 
@@ -1,24 +1,26 @@
1
1
  /**
2
2
  * Manages the startup and runtime configuration of Underpost applications.
3
- * @module src/server/start.js
3
+ * @module src/server/runtime/start.js
4
4
  * @namespace UnderpostStartUp
5
5
  */
6
6
 
7
7
  import fs from 'fs-extra';
8
8
  import { awaitDeployMonitor } from './conf.js';
9
- import { actionInitLog, loggerFactory } from './logger.js';
10
- import { shellCd, shellExec } from './process.js';
9
+ import { actionInitLog, loggerFactory } from '../ops/logger.js';
10
+ import { shellArgumentFactory, shellCd, shellExec, shellExecAsync } from './process.js';
11
11
  import {
12
12
  RUNTIME_STATUS,
13
- START_CONTAINER_STATUS_KEY,
14
13
  setRuntimeStatus,
15
14
  startInternalStatusServer,
16
15
  deployStatusPort,
17
- containerStatusValue,
16
+ setStartContainerStatus,
18
17
  } from './runtime-status.js';
19
- import Underpost from '../index.js';
18
+ import Underpost from '../../index.js';
20
19
  const logger = loggerFactory(import.meta);
21
20
 
21
+ // Every deployment builds and runs out of this path inside the workload container.
22
+ const ENGINE_PATH = '/home/dd/engine';
23
+
22
24
  /**
23
25
  * @class UnderpostStartUp
24
26
  * @description Manages the startup and runtime configuration of Underpost applications.
@@ -139,9 +141,11 @@ class UnderpostStartUp {
139
141
  * @param {boolean} options.build - Whether to build the deployment.
140
142
  * @param {boolean} options.run - Whether to run the deployment.
141
143
  * @param {boolean} options.underpostQuicklyInstall - Whether to use underpost quickly install.
142
- * @param {boolean} options.skipPullBase - Whether to skip pulling the base code.
144
+ * @param {boolean} options.skipPullRepoBase - Whether to skip pulling the engine source repository.
145
+ * @param {boolean} options.skipPullPrivateRepo - Whether to skip cloning the private configuration repository.
143
146
  * @param {boolean} options.skipFullBuild - Whether to skip building the full client bundle.
144
147
  * @param {boolean} options.pullBundle - When true, download pre-built client bundle from Cloudinary via pull-bundle before starting.
148
+ * @param {boolean} options.privateTestRepo - When true, the base pull clones `engine-test-<id>` instead of `engine-<id>`.
145
149
  */
146
150
  async callback(
147
151
  deployId = 'dd-default',
@@ -150,11 +154,24 @@ class UnderpostStartUp {
150
154
  build: false,
151
155
  run: false,
152
156
  underpostQuicklyInstall: false,
153
- skipPullBase: false,
157
+ skipPullRepoBase: false,
158
+ skipPullPrivateRepo: false,
154
159
  skipFullBuild: false,
155
160
  pullBundle: false,
161
+ privateTestRepo: false,
156
162
  },
157
163
  ) {
164
+ // Host configuration first: the pod command names only `start`, so the container env the
165
+ // `underpost-config` Secret injects is folded into the host configuration store here rather than by
166
+ // a second command the image's CLI might not have. A direct call, not a shell-out, so it
167
+ // does not depend on CLI surface either.
168
+ if (Underpost.state.isInsideContainer()) Underpost.host.load({ env });
169
+
170
+ // One phase, and the source pull belongs to `build`: a pod arrives here either through
171
+ // its bootstrap, which already replaced this checkout and linked the CLI, or with
172
+ // `--build` and no `--skip-pull-repo-base`, which pulls it here. Every long step shells
173
+ // out through `node bin`, so those run the pulled source either way.
174
+ //
158
175
  // Bring the internal status endpoint up first so Phase-2 readiness is
159
176
  // observable through every lifecycle phase, including build and init. Bind
160
177
  // the deployment-resolved port so it always matches the monitor's target.
@@ -167,15 +184,85 @@ class UnderpostStartUp {
167
184
  } catch (error) {
168
185
  logger.error('Deployment build/init failed', { deployId, env, message: error?.message });
169
186
  setRuntimeStatus(deployId, env, RUNTIME_STATUS.ERROR);
170
- if (!Underpost.env.isInsideContainer()) throw error;
187
+ if (!Underpost.state.isInsideContainer()) throw error;
188
+ }
189
+ },
190
+ /**
191
+ * Replaces `/home/dd/engine` with the deployment's own source and points the global
192
+ * `underpost` command at it — the base pull that makes the rest of the flow independent
193
+ * of how recently the npm package was published.
194
+ *
195
+ * One pull per container: {@link UnderpostStartUp.build} performs it unless
196
+ * `--skip-pull-repo-base` says the pod's own bootstrap (`pod_bootstrap_cmd`) already
197
+ * replaced the checkout and linked the CLI before `start` was ever invoked.
198
+ * @param {string} deployId - The ID of the deployment.
199
+ * @param {Object} [options] - Options for the pull.
200
+ * @param {boolean} [options.underpostQuicklyInstall] - Use `underpost install` instead of `npm install`.
201
+ * @param {boolean} [options.privateTestRepo] - Clone `engine-test-<id>` instead of `engine-<id>`.
202
+ * @memberof UnderpostStartUp
203
+ */
204
+ pullRepoBase(deployId = 'dd-default', options = {}) {
205
+ const buildBasePath = `/home/dd`;
206
+ // `--private-test-repo` clones the isolated test source repo published by
207
+ // `node bin/build <deployId> --update-private`, instead of the production one.
208
+ const repoName = Underpost.repo.engineRepoFactory(deployId, { test: options?.privateTestRepo === true });
209
+ shellExec(`cd ${buildBasePath} && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}`);
210
+ shellExec(`mkdir -p ${ENGINE_PATH}`);
211
+ shellExec(`cd ${buildBasePath} && sudo cp -a ./${repoName}/. ./engine`);
212
+ shellExec(`cd ${buildBasePath} && sudo rm -rf ./${repoName}`);
213
+ shellCd(ENGINE_PATH);
214
+ // Dependencies before the link: stage 2 boots through this checkout's `bin/index.js`
215
+ // and cannot start without its node_modules.
216
+ shellExec(options?.underpostQuicklyInstall ? `underpost install` : `npm install`);
217
+ Underpost.start.linkRuntimeCli();
218
+ },
219
+ /**
220
+ * Repoints the global `underpost` command at the engine checkout.
221
+ *
222
+ * `--force` because the image already owns a global `underpost` from npm; without it npm
223
+ * refuses the bin with `EEXIST`. Only the bin is repointed — the published package
224
+ * directory stays in place, so `getUnderpostRootPath()` keeps resolving to it and both
225
+ * stages share the one container state store holding `container-status`.
226
+ *
227
+ * Failure is not fatal. A host that cannot write its global prefix falls back to the npm
228
+ * snapshot, which is exactly the behaviour before this step existed, rather than losing
229
+ * the deployment over a link.
230
+ * @param {string} [enginePath] - Checkout to link.
231
+ * @returns {boolean} Whether the global command now resolves to the checkout.
232
+ * @memberof UnderpostStartUp
233
+ */
234
+ linkRuntimeCli(enginePath = ENGINE_PATH) {
235
+ const checkout = shellArgumentFactory(enginePath);
236
+ const result = shellExec(
237
+ `cd ${checkout} && npm link --force && ` +
238
+ `test "$(readlink -f "$(command -v underpost)")" = "$(readlink -f ./bin/index.js)"`,
239
+ {
240
+ silent: true,
241
+ silentOnError: true,
242
+ },
243
+ );
244
+ if (result?.code === 0) {
245
+ logger.info('Global underpost CLI linked to the engine checkout', { enginePath });
246
+ return true;
171
247
  }
248
+ logger.warn('Could not link the global underpost CLI; continuing with the image snapshot', {
249
+ enginePath,
250
+ code: result?.code,
251
+ stderr: `${result?.stderr ?? ''}`.trim().split('\n').slice(-1)[0],
252
+ });
253
+ return false;
172
254
  },
173
255
  /**
174
- * Run itc-scripts and builds client bundle.
256
+ * Materializes the deployment environment and builds the client bundle.
257
+ *
258
+ * Container-specific values are not applied by a script here: `app load` resolves the
259
+ * deployment's `.env.<env>.oci` overlay when it runs inside a container, so the working tree
260
+ * this build renders from already carries the cluster endpoints.
175
261
  * @param {string} deployId - The ID of the deployment.
176
262
  * @param {string} env - The environment of the deployment.
177
263
  * @param {Object} options - Options for the build.
178
- * @param {boolean} options.skipPullBase - Whether to skip pulling the base code and use the current workspace code directly.
264
+ * @param {boolean} options.skipPullRepoBase - Whether to skip pulling the engine source repository and use the current workspace code directly.
265
+ * @param {boolean} options.skipPullPrivateRepo - Whether to skip cloning the private configuration repository, for a pod whose bootstrap already placed `engine-private`.
179
266
  * @param {boolean} options.underpostQuicklyInstall - Whether to use underpost quickly install.
180
267
  * @param {boolean} options.skipFullBuild - Whether to skip building the full client bundle.
181
268
  * @param {boolean} options.pullBundle - When true, download pre-built client bundle from Cloudinary via pull-bundle (must be pushed first with push-bundle).
@@ -187,31 +274,29 @@ class UnderpostStartUp {
187
274
  async build(
188
275
  deployId = 'dd-default',
189
276
  env = 'development',
190
- options = { underpostQuicklyInstall: false, skipPullBase: false, skipFullBuild: false, pullBundle: false },
277
+ options = {
278
+ underpostQuicklyInstall: false,
279
+ skipPullRepoBase: false,
280
+ skipPullPrivateRepo: false,
281
+ skipFullBuild: false,
282
+ pullBundle: false,
283
+ },
191
284
  ) {
192
- const buildBasePath = `/home/dd`;
193
- // `--private-test-repo` clones the isolated test source repo published by
194
- // `node bin/build <deployId> --update-private`, instead of the production one.
195
- const repoName = options?.privateTestRepo
196
- ? `engine-test-${deployId.split('-')[1]}`
197
- : `engine-${deployId.split('-')[1]}`;
198
- if (!options.skipPullBase) {
199
- shellExec(`cd ${buildBasePath} && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}`);
200
- shellExec(`mkdir -p ${buildBasePath}/engine`);
201
- shellExec(`cd ${buildBasePath} && sudo cp -a ./${repoName}/. ./engine`);
202
- shellExec(`cd ${buildBasePath} && sudo rm -rf ./${repoName}`);
203
- }
204
- shellCd(`${buildBasePath}/engine`);
205
- Underpost.repo.privateEngineRepoFactory(deployId);
206
- shellExec(options?.underpostQuicklyInstall ? `underpost install` : `npm install`);
207
- shellExec(`node bin env ${deployId} ${env}`);
208
- if (fs.existsSync('./engine-private/itc-scripts')) {
209
- const itcScripts = await fs.readdir('./engine-private/itc-scripts');
210
- for (const itcScript of itcScripts)
211
- if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
212
- }
213
- if (options.pullBundle === true) shellExec(`node bin run pull-bundle --deploy-id ${deployId}`);
214
- else if (!options.skipFullBuild) shellExec(`node bin client ${deployId}`);
285
+ if (options.skipPullRepoBase !== true) Underpost.start.pullRepoBase(deployId, options);
286
+ shellCd(ENGINE_PATH);
287
+ // Containers refresh private config because an image/bootstrap checkout may be stale.
288
+ // Hosts keep their local checkout, while explicit skip preserves caller-provided config.
289
+ if (options.skipPullPrivateRepo !== true)
290
+ Underpost.repo.privateEngineRepoFactory(deployId, { force: Underpost.state.isInsideContainer() });
291
+ // Awaited rather than blocking: these are the minutes-long steps of a deployment, and a
292
+ // synchronous child stalls the event loop for its whole duration — leaving the status
293
+ // endpoint bound but unable to answer, so telemetry went dark across the entire build.
294
+ await shellExecAsync(options?.underpostQuicklyInstall ? `underpost install` : `npm install`);
295
+ await shellExecAsync(`node bin app load --env ${env} --args deploy-id=${deployId}`);
296
+ if (options.pullBundle === true) await shellExecAsync(`node bin run pull-bundle --deploy-id ${deployId}`);
297
+ // `--env` is explicit rather than inherited: the container's ambient NODE_ENV comes from
298
+ // the injected `underpost-config`, and a build that guesses it renders the wrong conf.
299
+ else if (!options.skipFullBuild) await shellExecAsync(`node bin client ${deployId} --env ${env}`);
215
300
  },
216
301
  /**
217
302
  * Runs a deployment.
@@ -232,7 +317,7 @@ class UnderpostStartUp {
232
317
  const replicas = await fs.readdir(`./engine-private/replica`);
233
318
  for (const replica of replicas) {
234
319
  if (!replica.match(deployId)) continue;
235
- shellExec(`node bin env ${replica} ${env}`);
320
+ shellExec(`node bin app load --env ${env} --args deploy-id=${replica}`);
236
321
  const replicaCmd = `npm ${runCmd} ${replica}`;
237
322
  shellExec(replicaCmd, { async: true, callback: makeDeployCallback(replicaCmd) });
238
323
  const result = await awaitDeployMonitor();
@@ -242,15 +327,19 @@ class UnderpostStartUp {
242
327
  }
243
328
  }
244
329
  }
245
- shellExec(`node bin env ${deployId} ${env}`);
330
+ shellExec(`node bin app load --env ${env} --args deploy-id=${deployId}`);
246
331
  const deployCmd = `npm ${runCmd} ${deployId}`;
247
332
  shellExec(deployCmd, { async: true, callback: makeDeployCallback(deployCmd) });
248
333
  const result = await awaitDeployMonitor(true);
249
334
  if (result === true) {
250
- if (env === 'production' && Underpost.env.isInsideContainer()) Underpost.secret.globalSecretClean();
335
+ // Withdraw every domain's local traces once the deployment is serving. Three calls
336
+ // rather than one cross-domain sweep: each domain owns what it put on disk.
337
+ if (env === 'production' && Underpost.state.isInsideContainer())
338
+ for (const domain of [Underpost.secret, Underpost.host, Underpost.app])
339
+ domain.clean({ env, namespace: 'default', args: {}, dryRun: false, force: false });
251
340
  setTimeout(() => {
252
341
  setRuntimeStatus(deployId, env, RUNTIME_STATUS.RUNNING);
253
- Underpost.env.set(START_CONTAINER_STATUS_KEY, containerStatusValue(deployId, env, RUNTIME_STATUS.RUNNING));
342
+ setStartContainerStatus(deployId, env);
254
343
  });
255
344
  } else {
256
345
  setRuntimeStatus(deployId, env, RUNTIME_STATUS.ERROR);
@@ -1,27 +1,27 @@
1
1
  /**
2
2
  * Module for managing identity and authorization
3
- * @module src/server/auth.js
3
+ * @module src/server/security/auth.js
4
4
  * @namespace Auth
5
5
  */
6
6
 
7
7
  import jwt from 'jsonwebtoken';
8
- import { loggerFactory } from './logger.js';
8
+ import { loggerFactory } from '../ops/logger.js';
9
9
  import crypto from 'crypto';
10
10
  import { promisify } from 'util';
11
- import { UserDto } from '../api/user/user.model.js';
11
+ import { UserDto } from '../../api/user/user.model.js';
12
12
  import {
13
13
  commonAdminGuard,
14
14
  commonModeratorGuard,
15
15
  commonUserGuard,
16
16
  validatePassword,
17
- } from '../client/components/core/CommonJs.js';
17
+ } from '../../client/components/core/CommonJs.js';
18
18
  import helmet from 'helmet';
19
19
  import rateLimit from 'express-rate-limit';
20
20
  import slowDown from 'express-slow-down';
21
21
  import cors from 'cors';
22
22
  import cookieParser from 'cookie-parser';
23
- import { DataBaseProviderService } from '../db/DataBaseProvider.js';
24
- import { isDevProxyContext } from './conf.js';
23
+ import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
24
+ import { isDevProxyContext } from '../runtime/conf.js';
25
25
 
26
26
  const logger = loggerFactory(import.meta);
27
27
 
@@ -618,7 +618,7 @@ function applySecurity(app, opts = {}) {
618
618
 
619
619
  // Other helpful Helmet policies
620
620
  app.use(helmet.noSniff()); // X-Content-Type-Options: nosniff
621
- app.use(helmet.frameguard({ action: 'deny' })); // X-Frame-Options: DENY
621
+ app.use(helmet.frameguard({ action: 'sameorigin' }));
622
622
  app.use(helmet.referrerPolicy({ policy: 'no-referrer-when-downgrade' }));
623
623
 
624
624
  // Content-Security-Policy: include nonce from res.locals
@@ -630,7 +630,6 @@ function applySecurity(app, opts = {}) {
630
630
  directives: {
631
631
  defaultSrc: ["'self'"],
632
632
  baseUri: ["'self'"],
633
- blockAllMixedContent: [],
634
633
  fontSrc: ["'self'", httpDirective, 'data:'],
635
634
  frameAncestors: frameAncestors,
636
635
  imgSrc: ["'self'", 'data:', httpDirective, 'https:', 'blob:'],