@underpostnet/cyberia 3.3.0 → 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 (471) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/coverall.cyberia.ci.yml +34 -14
  3. package/.github/workflows/cyberia-client.cd.yml +5 -0
  4. package/.github/workflows/cyberia-server.cd.yml +5 -0
  5. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  6. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  7. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  8. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  9. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  10. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  11. package/.github/workflows/engine-cyberia.cd.yml +3 -0
  12. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  13. package/.github/workflows/ghpkg.ci.yml +35 -20
  14. package/.github/workflows/hardhat.ci.yml +12 -11
  15. package/.github/workflows/npmpkg.ci.yml +17 -15
  16. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  17. package/.github/workflows/release.cd.yml +1 -0
  18. package/.prettierignore +1 -0
  19. package/AGENTS.md +47 -0
  20. package/CHANGELOG.md +565 -2510
  21. package/CLI-HELP.md +306 -147
  22. package/Dockerfile +25 -9
  23. package/Dockerfile.dev +25 -9
  24. package/Dockerfile.test +4 -4
  25. package/README.md +21 -1
  26. package/bin/build.js +66 -41
  27. package/bin/build.template.js +8 -3
  28. package/bin/cyberia.js +308 -91
  29. package/bin/deploy.js +18 -104
  30. package/bin/index.js +308 -91
  31. package/conf.js +91 -4
  32. package/deploy/cyberia-client/deploy.sh +47 -0
  33. package/deploy/cyberia-client/package.sh +18 -0
  34. package/deploy/cyberia-client/state.sh +14 -0
  35. package/deploy/cyberia-server/deploy.sh +47 -0
  36. package/deploy/cyberia-server/package.sh +18 -0
  37. package/deploy/cyberia-server/state.sh +14 -0
  38. package/deploy/dd-cyberia/deploy.sh +6 -26
  39. package/deploy/dd-cyberia/init.sh +35 -43
  40. package/deploy/dd-cyberia/package.sh +17 -0
  41. package/deploy/dd-cyberia/state.sh +14 -0
  42. package/deploy/dd-cyberia/sync-deploy.sh +92 -170
  43. package/deploy/lib/github-actions-logging.sh +594 -0
  44. package/deploy/lib/host.sh +185 -0
  45. package/deploy/lib/state.sh +62 -0
  46. package/deploy/pwa-microservices-template/deploy.sh +12 -39
  47. package/deploy/release/deploy.sh +9 -39
  48. package/deployment.yaml +7 -2
  49. package/docker-compose.yml +7 -7
  50. package/examples/static-page/README.md +19 -19
  51. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  52. package/hardhat/hardhat.config.js +1 -6
  53. package/hardhat/package-lock.json +101 -40
  54. package/hardhat/package.json +2 -2
  55. package/manifests/alertmanager/deployment.yaml +81 -0
  56. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  57. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
  58. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
  59. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  60. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  61. package/manifests/grafana/deployment.yaml +26 -7
  62. package/manifests/grafana/kustomization.yaml +1 -0
  63. package/manifests/grafana/service.yaml +6 -1
  64. package/manifests/mariadb/pv.yaml +1 -0
  65. package/manifests/mongodb/statefulset.yaml +9 -2
  66. package/manifests/mysql/pv-pvc.yaml +14 -1
  67. package/manifests/postgresql/pv.yaml +12 -1
  68. package/manifests/postgresql/pvc.yaml +1 -0
  69. package/manifests/prometheus/deployment.yaml +18 -22
  70. package/package.json +83 -10
  71. package/scripts/event-monitor.sh +56 -0
  72. package/scripts/k3s-node-setup.sh +27 -14
  73. package/scripts/kubeadm-node-setup.sh +31 -11
  74. package/scripts/maas-setup.sh +8 -8
  75. package/scripts/selinux-normalize.sh +907 -0
  76. package/scripts/shutdown-machine.sh +843 -0
  77. package/scripts/test-monitor.sh +3 -3
  78. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
  79. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
  80. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
  81. package/src/api/core/core.controller.js +1 -1
  82. package/src/api/core/core.router.js +2 -2
  83. package/src/api/core/core.service.js +2 -2
  84. package/src/api/crypto/crypto.controller.js +1 -1
  85. package/src/api/crypto/crypto.service.js +1 -1
  86. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  87. package/src/api/cyberia-action/cyberia-action.router.js +1 -1
  88. package/src/api/cyberia-action/cyberia-action.service.js +2 -2
  89. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
  90. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
  91. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
  92. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  93. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  94. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  95. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  96. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  97. package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
  98. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
  99. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
  100. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
  101. package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
  102. package/src/api/cyberia-instance/cyberia-fallback-world.js +8 -0
  103. package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
  104. package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -1
  105. package/src/api/cyberia-instance/cyberia-instance.router.js +2 -2
  106. package/src/api/cyberia-instance/cyberia-instance.service.js +2 -2
  107. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  108. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  109. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
  110. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  111. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  112. package/src/api/cyberia-map/cyberia-map.service.js +2 -2
  113. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  114. package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
  115. package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
  116. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  117. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  118. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  119. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  120. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  121. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  122. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +0 -26
  123. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  124. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  125. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  126. package/src/api/default/default.controller.js +1 -1
  127. package/src/api/default/default.router.js +1 -1
  128. package/src/api/default/default.service.js +2 -2
  129. package/src/api/document/document.controller.js +1 -1
  130. package/src/api/document/document.router.js +1 -1
  131. package/src/api/document/document.service.js +2 -2
  132. package/src/api/file/file.controller.js +1 -1
  133. package/src/api/file/file.router.js +1 -1
  134. package/src/api/file/file.service.js +2 -2
  135. package/src/api/instance/instance.controller.js +1 -1
  136. package/src/api/instance/instance.router.js +1 -1
  137. package/src/api/instance/instance.service.js +2 -2
  138. package/src/api/ipfs/ipfs.controller.js +1 -1
  139. package/src/api/ipfs/ipfs.router.js +2 -2
  140. package/src/api/ipfs/ipfs.service.js +2 -2
  141. package/src/api/object-layer/object-layer.controller.js +1 -1
  142. package/src/api/object-layer/object-layer.router.js +2 -2
  143. package/src/api/object-layer/object-layer.service.js +3 -3
  144. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  145. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  146. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  147. package/src/api/test/test.controller.js +1 -1
  148. package/src/api/test/test.service.js +1 -1
  149. package/src/api/user/guest.service.js +3 -3
  150. package/src/api/user/user.controller.js +1 -1
  151. package/src/api/user/user.router.js +2 -2
  152. package/src/api/user/user.service.js +4 -4
  153. package/src/api.js +5 -9
  154. package/src/cli/app.js +391 -0
  155. package/src/cli/baremetal.js +30 -35
  156. package/src/cli/client.js +306 -0
  157. package/src/cli/cloud-init.js +3 -3
  158. package/src/cli/cluster.js +184 -82
  159. package/src/cli/db.js +120 -68
  160. package/src/cli/deploy.js +153 -71
  161. package/src/cli/docker-compose.js +5 -5
  162. package/src/cli/domains.js +184 -0
  163. package/src/cli/dotenv-store.js +143 -0
  164. package/src/cli/event.js +2281 -0
  165. package/src/cli/fs.js +3 -3
  166. package/src/cli/host.js +672 -0
  167. package/src/cli/image.js +4 -6
  168. package/src/cli/index.js +322 -142
  169. package/src/cli/ipfs.js +34 -30
  170. package/src/cli/kickstart.js +1 -1
  171. package/src/cli/kubectl.js +218 -41
  172. package/src/cli/lxd.js +3 -3
  173. package/src/cli/monitor.js +1359 -26
  174. package/src/cli/package.js +90 -0
  175. package/src/cli/release.js +16 -12
  176. package/src/cli/repository.js +558 -363
  177. package/src/cli/run.js +331 -650
  178. package/src/cli/secrets.js +2158 -964
  179. package/src/cli/ssh.js +478 -279
  180. package/src/cli/state.js +394 -0
  181. package/src/cli/static.js +2 -2
  182. package/src/cli/system.js +1 -1
  183. package/src/cli/test.js +199 -125
  184. package/src/cli/vultr.js +61 -21
  185. package/src/cli/wireguard.js +1111 -306
  186. package/src/client/components/core/CalendarCore.js +53 -96
  187. package/src/client/components/core/Docs.js +258 -211
  188. package/src/client/components/core/FileExplorer.js +0 -21
  189. package/src/client/components/core/PanelForm.js +4 -4
  190. package/src/client/components/core/Repository.js +56 -0
  191. package/src/client/components/core/Translate.js +7 -0
  192. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  193. package/src/client/components/core/Wallet.js +0 -11
  194. package/src/client/components/core/Worker.js +7 -1
  195. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  196. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -1
  197. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  198. package/src/client/components/default/AppShellDefault.js +1 -1
  199. package/src/client/components/default/SettingsDefault.js +2 -2
  200. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  201. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  202. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  203. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
  204. package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
  205. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  206. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  207. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  208. package/src/client/public/default/android-chrome-144x144.png +0 -0
  209. package/src/client/public/default/android-chrome-192x192.png +0 -0
  210. package/src/client/public/default/android-chrome-256x256.png +0 -0
  211. package/src/client/public/default/android-chrome-36x36.png +0 -0
  212. package/src/client/public/default/android-chrome-384x384.png +0 -0
  213. package/src/client/public/default/android-chrome-48x48.png +0 -0
  214. package/src/client/public/default/android-chrome-512x512.png +0 -0
  215. package/src/client/public/default/android-chrome-72x72.png +0 -0
  216. package/src/client/public/default/android-chrome-96x96.png +0 -0
  217. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  218. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  219. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  220. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  221. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  222. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  223. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  224. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  225. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  226. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  227. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  228. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  229. package/src/client/public/default/apple-touch-icon.png +0 -0
  230. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  231. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  232. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  233. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  234. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  235. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  236. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  237. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  238. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  239. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  240. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  241. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  242. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  243. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  244. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  245. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  246. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  247. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  248. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  249. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  250. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  251. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  252. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  253. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  254. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  255. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  256. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  257. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  258. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  259. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  260. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  261. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  262. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  263. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  264. package/src/client/public/default/assets/background/white.jpg +0 -0
  265. package/src/client/public/default/browserconfig.xml +1 -1
  266. package/src/client/public/default/favicon-16x16.png +0 -0
  267. package/src/client/public/default/favicon-32x32.png +0 -0
  268. package/src/client/public/default/favicon-48x48.png +0 -0
  269. package/src/client/public/default/favicon.ico +0 -0
  270. package/src/client/public/default/manifest.webmanifest +5 -5
  271. package/src/client/public/default/mstile-144x144.png +0 -0
  272. package/src/client/public/default/mstile-150x150.png +0 -0
  273. package/src/client/public/default/mstile-310x150.png +0 -0
  274. package/src/client/public/default/mstile-310x310.png +0 -0
  275. package/src/client/public/default/mstile-70x70.png +0 -0
  276. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  277. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  278. package/src/client/ssr/RootDocument.js +1 -1
  279. package/src/client/ssr/body/404.js +1 -1
  280. package/src/client/ssr/body/500.js +1 -1
  281. package/src/client/ssr/body/CacheControl.js +1 -1
  282. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  283. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  284. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  285. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  286. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  287. package/src/client/ssr/head/Css.js +1 -1
  288. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  289. package/src/client/ssr/head/DefaultScripts.js +1 -1
  290. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  291. package/src/client/ssr/head/Microdata.js +1 -1
  292. package/src/client/ssr/head/Production.js +1 -1
  293. package/src/client/ssr/head/Pwa.js +1 -1
  294. package/src/client/ssr/head/PwaItemledger.js +1 -1
  295. package/src/client/ssr/head/Seo.js +1 -1
  296. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  297. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  298. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  299. package/src/client/ssr/views/Cyberia404.js +7 -5
  300. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  301. package/src/client/ssr/views/Maintenance.js +1 -1
  302. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  303. package/src/client/ssr/views/Test.js +1 -1
  304. package/src/client/sw/core.sw.js +20 -14
  305. package/src/client-builder/client-build-docs.js +61 -46
  306. package/src/client-builder/client-build-live.js +2 -2
  307. package/src/client-builder/client-build.js +38 -30
  308. package/src/client-builder/client-dev-server.js +3 -3
  309. package/src/client-builder/client-icons.js +2 -2
  310. package/src/client-builder/ssr.js +3 -3
  311. package/src/client.build.js +3 -6
  312. package/src/client.dev.js +3 -6
  313. package/src/db/DataBaseProvider.js +186 -3
  314. package/src/db/mariadb/MariaDB.js +3 -2
  315. package/src/db/mongo/MongoBootstrap.js +273 -101
  316. package/src/db/mongo/MongooseDB.js +7 -8
  317. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  318. package/src/grpc/cyberia/grpc-server.js +1 -1
  319. package/src/index.js +79 -23
  320. package/src/mailer/EmailRender.js +2 -2
  321. package/src/mailer/MailerInterceptor.js +87 -0
  322. package/src/mailer/MailerProvider.js +50 -6
  323. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
  324. package/src/projects/cyberia/besu-genesis-generator.js +3 -3
  325. package/src/projects/cyberia/catalog-cyberia.js +53 -10
  326. package/src/projects/cyberia/gemini-client.js +1 -1
  327. package/src/projects/cyberia/generate-saga.js +1 -1
  328. package/src/projects/cyberia/hot-reload-trigger.js +1 -1
  329. package/src/projects/cyberia/instance-data.js +1 -1
  330. package/src/projects/cyberia/ipfs-client.js +4 -4
  331. package/src/projects/cyberia/map-preview-generator.js +1 -1
  332. package/src/projects/cyberia/object-layer.js +1 -1
  333. package/src/projects/cyberia/semantic-layer-generator.js +1 -1
  334. package/src/projects/underpost/catalog-underpost.js +9 -1
  335. package/src/proxy.js +4 -7
  336. package/src/runtime/cyberia-client/Dockerfile +9 -4
  337. package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
  338. package/src/runtime/cyberia-server/Dockerfile +9 -4
  339. package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
  340. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  341. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  342. package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
  343. package/src/runtime/engine-cyberia/docker-compose.yml +7 -7
  344. package/src/runtime/express/Express.js +32 -27
  345. package/src/runtime/lampp/Lampp.js +22 -70
  346. package/src/runtime/nginx/Nginx.js +1 -1
  347. package/src/runtime/wp/Wp.js +16 -48
  348. package/src/server/{catalog.js → build/catalog.js} +15 -5
  349. package/src/server/build/coverage.js +117 -0
  350. package/src/server/build/execution.js +402 -0
  351. package/src/server/build/package.js +465 -0
  352. package/src/server/build/testing.js +528 -0
  353. package/src/server/{dns.js → network/dns.js} +144 -11
  354. package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
  355. package/src/server/{middlewares.js → network/middlewares.js} +3 -3
  356. package/src/server/network/node-capability.js +98 -0
  357. package/src/server/{peer.js → network/peer.js} +3 -3
  358. package/src/server/{proxy.js → network/proxy.js} +7 -13
  359. package/src/server/network/router.js +356 -0
  360. package/src/server/{tls.js → network/tls.js} +2 -2
  361. package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
  362. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
  363. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
  364. package/src/server/{cri.js → ops/cri.js} +2 -2
  365. package/src/server/{cron.js → ops/cron.js} +349 -74
  366. package/src/server/ops/event-notification.js +284 -0
  367. package/src/server/{logger.js → ops/logger.js} +108 -23
  368. package/src/server/ops/monitoring.js +1724 -0
  369. package/src/server/{systemd.js → ops/systemd.js} +55 -1
  370. package/src/server/{conf.js → runtime/conf.js} +513 -422
  371. package/src/server/runtime/config-scope.js +215 -0
  372. package/src/server/runtime/environment.js +149 -0
  373. package/src/server/{process.js → runtime/process.js} +153 -12
  374. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  375. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  376. package/src/server/{start.js → runtime/start.js} +128 -39
  377. package/src/server/{auth.js → security/auth.js} +7 -8
  378. package/src/server/security/container-storage.js +382 -0
  379. package/src/server/{crypto.js → security/crypto.js} +1 -1
  380. package/src/server/{selinux.js → security/selinux.js} +1 -1
  381. package/src/server/{backup.js → storage/backup.js} +17 -8
  382. package/src/server/{data-query.js → storage/data-query.js} +1 -1
  383. package/src/server/{downloader.js → storage/downloader.js} +2 -2
  384. package/src/server/storage/repository.js +68 -0
  385. package/src/server.js +4 -7
  386. package/src/ws/IoInterface.js +1 -1
  387. package/src/ws/IoServer.js +1 -1
  388. package/src/ws/core/core.ws.connection.js +1 -1
  389. package/src/ws/core/core.ws.emit.js +1 -1
  390. package/src/ws/core/core.ws.server.js +1 -1
  391. package/src/ws/default/default.ws.connection.js +1 -1
  392. package/src/ws/default/default.ws.emit.js +1 -1
  393. package/src/ws/default/default.ws.server.js +1 -1
  394. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  395. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  396. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  397. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  398. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
  399. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +1 -1
  400. package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
  401. package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
  402. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  403. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  404. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  405. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  406. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  407. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  408. package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
  409. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  410. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  411. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  412. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  413. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  414. package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
  415. package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +609 -55
  416. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  417. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  418. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  419. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  420. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  421. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  422. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
  423. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
  424. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  425. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  426. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  427. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  428. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  429. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  430. package/test/support/shell-harness.js +73 -0
  431. package/test/unit/build-template.test.js +97 -0
  432. package/test/unit/build-workflow-offline.test.js +132 -0
  433. package/test/unit/catalog.test.js +71 -0
  434. package/test/unit/client-build-docs.test.js +334 -0
  435. package/test/unit/conf-loading.test.js +303 -0
  436. package/test/unit/conf-resolution.test.js +979 -0
  437. package/test/unit/coverage-artifact.test.js +130 -0
  438. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  439. package/test/unit/deploy-env-resolution.test.js +38 -0
  440. package/test/unit/deploy-log-table.test.js +447 -0
  441. package/test/unit/execution-profiles.test.js +219 -0
  442. package/test/unit/fleet-sync-source.test.js +149 -0
  443. package/test/unit/logger-redaction.test.js +112 -0
  444. package/test/unit/package.test.js +403 -0
  445. package/test/unit/prepare-host.test.js +299 -0
  446. package/test/unit/process-environment.test.js +18 -0
  447. package/test/unit/propagation-message.test.js +78 -0
  448. package/test/unit/redeploy-plan.test.js +24 -0
  449. package/test/unit/release-bump.test.js +474 -0
  450. package/test/unit/ssh-output-redaction.test.js +28 -0
  451. package/test/unit/start-options.test.js +46 -0
  452. package/test/unit/test-tiers.test.js +193 -0
  453. package/vitest.config.js +58 -0
  454. package/.nycrc +0 -9
  455. package/deploy/lib/logging.sh +0 -96
  456. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  457. package/manifests/mongodb/pv-pvc.yaml +0 -59
  458. package/scripts/coverall-test-cyberia.sh +0 -24
  459. package/scripts/coverall-test.sh +0 -24
  460. package/scripts/link-local-underpost-cli.sh +0 -6
  461. package/src/api/user/user.build.js +0 -16
  462. package/src/cli/env.js +0 -177
  463. package/src/client/components/core/Blockchain.js +0 -41
  464. package/src/client/components/core/Blog.js +0 -9
  465. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  466. package/src/client/public/default/assets/background/dark.jpg +0 -0
  467. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  468. package/src/client/public/default/assets/background/white0.jpg +0 -0
  469. package/src/client/public/doc/favicon.ico +0 -0
  470. package/src/client/public/doc/sitemap +0 -148
  471. package/src/server/environment.js +0 -98
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Provides a comprehensive set of DNS and IP management utilities,
3
3
  * primarily focused on dynamic DNS (DDNS) updates and network checks.
4
- * @module src/server/dns.js
4
+ * @module src/server/network/dns.js
5
5
  * @namespace UnderpostDns
6
6
  */
7
7
  import axios from 'axios';
8
8
  import validator from 'validator';
9
- import { loggerFactory } from './logger.js';
9
+ import { loggerFactory } from '../ops/logger.js';
10
10
  import dns from 'node:dns';
11
11
  import os from 'node:os';
12
- import { shellExec, pbcopy } from './process.js';
13
- import Underpost from '../index.js';
14
- import { readConfJson } from './conf.js';
12
+ import { shellExec, pbcopy } from '../runtime/process.js';
13
+ import Underpost from '../../index.js';
14
+ import { readConfJson } from '../runtime/conf.js';
15
15
 
16
16
  const logger = loggerFactory(import.meta);
17
17
 
@@ -276,7 +276,50 @@ class Dns {
276
276
  * @static
277
277
  * @memberof UnderpostDns
278
278
  */
279
+ static ensureFilterChains(chains = ['output', 'forward']) {
280
+ // A stock RHEL 9 host with firewalld keeps its rules in `inet firewalld`;
281
+ // there is no `inet filter` table, so every policy command below fails with
282
+ // "No such file or directory". They used to fail silently, which is the
283
+ // worst possible outcome for this subsystem: the caller logged a successful
284
+ // block, the bandwidth guard latched, and the overage it exists to stop
285
+ // kept accruing against a host that was never blocked.
286
+ //
287
+ // Creating our own base chains is additive rather than a firewalld
288
+ // takeover — nftables evaluates every table, so a drop here still wins.
289
+ const ran = (command) => shellExec(command, { silent: true, silentOnError: true })?.code === 0;
290
+ const chainExists = (chain) => ran(`sudo nft list chain inet filter ${chain}`);
291
+ const missing = chains.filter((chain) => !chainExists(chain));
292
+ if (missing.length === 0) return true;
293
+ if (!ran(`sudo nft add table inet filter`)) return false;
294
+ for (const chain of missing) {
295
+ const hook = chain === 'input' ? 'input' : chain;
296
+ if (!ran(`sudo nft add chain inet filter ${chain} '{ type filter hook ${hook} priority 0; policy accept; }'`))
297
+ return false;
298
+ }
299
+ return chains.every(chainExists);
300
+ }
301
+
302
+ /**
303
+ * Whether a chain currently carries the given policy.
304
+ * @static
305
+ * @param {string} chain - Chain name in `inet filter`.
306
+ * @param {string} policy - `accept` or `drop`.
307
+ * @returns {boolean} True when the chain reports that policy.
308
+ * @memberof UnderpostDns
309
+ */
310
+ static chainPolicyIs(chain, policy) {
311
+ const listing = shellExec(`sudo nft list chain inet filter ${chain}`, {
312
+ silent: true,
313
+ stdout: true,
314
+ silentOnError: true,
315
+ });
316
+ return `${listing || ''}`.includes(`policy ${policy}`);
317
+ }
318
+
279
319
  static blockAllEgress() {
320
+ if (!Dns.ensureFilterChains(['output', 'forward']))
321
+ throw new Error('[dns] could not create the inet filter chains; egress is NOT blocked');
322
+
280
323
  // Clear any existing egress rules.
281
324
  shellExec(`sudo nft flush chain inet filter output`, { silent: true });
282
325
  shellExec(`sudo nft flush chain inet filter forward`, { silent: true });
@@ -289,6 +332,12 @@ class Dns {
289
332
  shellExec(`sudo nft chain inet filter output '{ policy drop; }'`, { silent: true });
290
333
  shellExec(`sudo nft chain inet filter forward '{ policy drop; }'`, { silent: true });
291
334
 
335
+ // Read the policy back. The caller latches on this command's exit code, so
336
+ // reporting a block that did not land is what lets an overage run unbounded.
337
+ for (const chain of ['output', 'forward'])
338
+ if (!Dns.chainPolicyIs(chain, 'drop'))
339
+ throw new Error(`[dns] inet filter ${chain} is not 'policy drop'; egress is NOT blocked`);
340
+
292
341
  logger.info('All outbound traffic blocked.');
293
342
  }
294
343
 
@@ -299,6 +348,13 @@ class Dns {
299
348
  * @memberof UnderpostDns
300
349
  */
301
350
  static unblockAllEgress() {
351
+ // Nothing to restore when the chains were never created — that host was
352
+ // never blocked, and saying so beats failing on a missing table.
353
+ if (!Dns.ensureFilterChains(['output', 'forward'])) {
354
+ logger.info('No inet filter chains on this host; egress was never blocked.');
355
+ return;
356
+ }
357
+
302
358
  // Restore default chain policies to accept all traffic.
303
359
  shellExec(`sudo nft chain inet filter output '{ policy accept; }'`, { silent: true });
304
360
  shellExec(`sudo nft chain inet filter forward '{ policy accept; }'`, { silent: true });
@@ -307,9 +363,30 @@ class Dns {
307
363
  shellExec(`sudo nft flush chain inet filter output`, { silent: true });
308
364
  shellExec(`sudo nft flush chain inet filter forward`, { silent: true });
309
365
 
366
+ for (const chain of ['output', 'forward'])
367
+ if (!Dns.chainPolicyIs(chain, 'accept'))
368
+ throw new Error(`[dns] inet filter ${chain} is still not 'policy accept'; egress remains blocked`);
369
+
310
370
  logger.info('All outbound traffic unblocked and restored to default ACCEPT policy.');
311
371
  }
312
372
 
373
+ /**
374
+ * Ensures the chain every ingress rule is installed into exists.
375
+ *
376
+ * `inet filter` can be present with no `input` chain — a firewalld host keeps
377
+ * its rules in `inet firewalld` and never creates one — and every ingress
378
+ * command below then fails on a table that looks like it is there. Creating it
379
+ * with an accept policy and no rules changes nothing by itself.
380
+ * @static
381
+ * @memberof UnderpostDns
382
+ */
383
+ static ensureIngressChain() {
384
+ shellExec(`sudo nft add table inet filter`, { silent: true });
385
+ shellExec(`sudo nft add chain inet filter input '{ type filter hook input priority 0; policy accept; }'`, {
386
+ silent: true,
387
+ });
388
+ }
389
+
313
390
  /**
314
391
  * Blocks all new inbound traffic to this host, except for established/related connections.
315
392
  * This prevents any new incoming connections while keeping existing sessions (like SSH) alive.
@@ -317,6 +394,7 @@ class Dns {
317
394
  * @memberof UnderpostDns
318
395
  */
319
396
  static blockAllIngress() {
397
+ Dns.ensureIngressChain();
320
398
  // Clear any existing ingress rules.
321
399
  shellExec(`sudo nft flush chain inet filter input`, { silent: true });
322
400
 
@@ -330,6 +408,50 @@ class Dns {
330
408
  logger.info('All new inbound traffic blocked.');
331
409
  }
332
410
 
411
+ /**
412
+ * Blocks new inbound traffic to specific TCP ports, leaving every other port
413
+ * reachable.
414
+ *
415
+ * Unlike {@link UnderpostDns.blockAllIngress}, the management path survives:
416
+ * blocking the public edge ports takes published services down while the host
417
+ * can still be reached to put them back. That is the only form of induced
418
+ * ingress outage a remote operator can recover from.
419
+ * @static
420
+ * @param {string} ports - Comma-separated TCP ports.
421
+ * @memberof UnderpostDns
422
+ */
423
+ static blockIngressPort(ports) {
424
+ Dns.ensureIngressChain();
425
+ for (const port of Dns.portListFactory(ports))
426
+ shellExec(`sudo nft insert rule inet filter input tcp dport ${port} counter drop`, { silent: true });
427
+ logger.info('Inbound traffic blocked on ports', { ports: Dns.portListFactory(ports) });
428
+ }
429
+
430
+ /**
431
+ * Withdraws the port rules {@link UnderpostDns.blockIngressPort} installed.
432
+ * @static
433
+ * @param {string} ports - Comma-separated TCP ports.
434
+ * @memberof UnderpostDns
435
+ */
436
+ static unblockIngressPort(ports) {
437
+ Dns.ensureIngressChain();
438
+ for (const port of Dns.portListFactory(ports))
439
+ shellExec(
440
+ `sudo sh -c "nft -a list chain inet filter input | awk '/tcp dport ${port} .*drop/ {print \\$NF}' | ` +
441
+ `xargs -r -n1 nft delete rule inet filter input handle"`,
442
+ { silent: true },
443
+ );
444
+ logger.info('Inbound traffic unblocked on ports', { ports: Dns.portListFactory(ports) });
445
+ }
446
+
447
+ /** Parses a comma-separated port list, keeping only valid TCP ports. */
448
+ static portListFactory(ports = '') {
449
+ return `${ports || ''}`
450
+ .split(',')
451
+ .map((port) => Number(`${port}`.trim()))
452
+ .filter((port) => Number.isInteger(port) && port > 0 && port <= 65535);
453
+ }
454
+
333
455
  /**
334
456
  * Unblocks all inbound traffic to this host.
335
457
  * Restores default input chain policy to ACCEPT and clears ingress rules.
@@ -337,6 +459,7 @@ class Dns {
337
459
  * @memberof UnderpostDns
338
460
  */
339
461
  static unblockAllIngress() {
462
+ Dns.ensureIngressChain();
340
463
  // Restore default chain policy to accept all incoming traffic.
341
464
  shellExec(`sudo nft chain inet filter input '{ policy accept; }'`, { silent: true });
342
465
 
@@ -354,7 +477,7 @@ class Dns {
354
477
  * @memberof UnderpostDns
355
478
  * @param {string} deployList Comma-separated string of deployment IDs to process.
356
479
  * @returns {Promise<void>}
357
- */
480
+ */
358
481
  static async callback(deployList) {
359
482
  const isOnline = await Dns.isInternetConnection();
360
483
 
@@ -368,11 +491,11 @@ class Dns {
368
491
  logger.error(error, { testIp, stack: error.stack });
369
492
  }
370
493
 
371
- const currentIp = Underpost.env.get('ip');
494
+ const currentIp = Underpost.host.store.get('ip');
372
495
 
373
- if (validator.isIP(testIp) && currentIp !== testIp) {
496
+ if (testIp && validator.isIP(testIp) && currentIp !== testIp) {
374
497
  logger.info(`New IP detected`, testIp);
375
- Underpost.env.set('monitor-input', 'pause');
498
+ Underpost.host.store.set('monitor-input', 'pause');
376
499
 
377
500
  for (const _deployId of deployList.split(',')) {
378
501
  const deployId = _deployId.trim();
@@ -415,8 +538,8 @@ class Dns {
415
538
  logger.info(ipUrlTest + ' verify ip', verifyIp);
416
539
  if (verifyIp === testIp) {
417
540
  logger.info('IP updated successfully and verified', testIp);
418
- Underpost.env.set('ip', testIp);
419
- Underpost.env.delete('monitor-input');
541
+ Underpost.host.store.set('ip', testIp);
542
+ Underpost.host.store.delete('monitor-input');
420
543
  } else {
421
544
  logger.error('IP not updated or verification failed', { expected: testIp, received: verifyIp });
422
545
  }
@@ -517,6 +640,8 @@ class Dns {
517
640
  * @property {boolean} [options.unblockAllEgress=false] - Unblock all outbound traffic.
518
641
  * @property {boolean} [options.blockAllIngress=false] - Block all new inbound traffic to this host.
519
642
  * @property {boolean} [options.unblockAllIngress=false] - Unblock all inbound traffic.
643
+ * @property {string} [options.blockIngressPort=''] - Comma-separated TCP ports to block inbound.
644
+ * @property {string} [options.unblockIngressPort=''] - Comma-separated TCP ports to unblock inbound.
520
645
  * @property {boolean} [options.dhcp=false] - Get local DHCP IP instead of public IP.
521
646
  * @property {boolean} [options.copy=false] - Copy the public IP to clipboard.
522
647
  * @return {Promise<string|void>} The public IP if no ban/unban action is taken.
@@ -538,6 +663,8 @@ class Dns {
538
663
  unblockAllEgress: false,
539
664
  blockAllIngress: false,
540
665
  unblockAllIngress: false,
666
+ blockIngressPort: '',
667
+ unblockIngressPort: '',
541
668
  copy: false,
542
669
  dhcp: false,
543
670
  },
@@ -594,6 +721,12 @@ class Dns {
594
721
  if (options.unblockAllEgress) {
595
722
  return Dns.unblockAllEgress();
596
723
  }
724
+ if (options.blockIngressPort) {
725
+ return Dns.blockIngressPort(options.blockIngressPort);
726
+ }
727
+ if (options.unblockIngressPort) {
728
+ return Dns.unblockIngressPort(options.unblockIngressPort);
729
+ }
597
730
  if (options.blockAllIngress) {
598
731
  return Dns.blockAllIngress();
599
732
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Authenticated HTTP/HTTPS forward-proxy primitives.
3
- * @module src/server/forward-proxy.js
3
+ * @module src/server/network/forward-proxy.js
4
4
  * @namespace ForwardProxy
5
5
  */
6
6
  'use strict';
@@ -9,14 +9,15 @@ import http from 'node:http';
9
9
  import https from 'node:https';
10
10
  import net from 'node:net';
11
11
  import os from 'node:os';
12
- import { environmentValueFactory } from './environment.js';
13
- import { loggerFactory, loggerMiddleware } from './logger.js';
12
+ import { environmentValueFactory } from '../runtime/environment.js';
13
+ import { loggerFactory, loggerMiddleware } from '../ops/logger.js';
14
14
  import {
15
- homeDirectoryPathFactory,
16
- systemdRunCommandFactory,
15
+ nodeCandidatesFactory,
16
+ nodeProbeCommandFactory,
17
+ scriptProbeCommandFactory,
17
18
  systemdServiceCommandsFactory,
18
19
  systemdUnitFactory,
19
- } from './systemd.js';
20
+ } from '../ops/systemd.js';
20
21
 
21
22
  const logger = loggerFactory(import.meta);
22
23
  const proxyLogger = loggerFactory(import.meta, 'debug');
@@ -181,11 +182,7 @@ const forwardProxyCommandFactory = ({ host, port, execPath = process.execPath, s
181
182
  const forwardProxyNodeCandidatesFactory = ({
182
183
  execPath = process.execPath,
183
184
  systemPaths = FORWARD_PROXY.nodePaths,
184
- } = {}) => {
185
- const own = `${execPath || ''}`.trim();
186
- const inHome = homeDirectoryPathFactory(own);
187
- return [...new Set([...(own && !inHome ? [own] : []), ...systemPaths, ...(own && inHome ? [own] : [])])];
188
- };
185
+ } = {}) => nodeCandidatesFactory({ execPath, systemPaths });
189
186
 
190
187
  /**
191
188
  * Builds a transient systemd command that probes a Node executable.
@@ -196,7 +193,7 @@ const forwardProxyNodeCandidatesFactory = ({
196
193
  * @memberof ForwardProxy
197
194
  */
198
195
  const forwardProxyNodeProbeCommandFactory = (nodePath, user = os.userInfo().username) =>
199
- systemdRunCommandFactory({ command: `${nodePath} --version`, user, properties: { Type: 'oneshot' } });
196
+ nodeProbeCommandFactory(nodePath, user);
200
197
 
201
198
  /**
202
199
  * Builds a transient systemd command that probes the proxy entry script.
@@ -210,12 +207,7 @@ const forwardProxyStartProbeCommandFactory = ({
210
207
  scriptPath = process.argv[1],
211
208
  user = os.userInfo().username,
212
209
  workingDirectory = process.cwd(),
213
- }) =>
214
- systemdRunCommandFactory({
215
- command: `${nodePath} ${scriptPath} --version`,
216
- user,
217
- properties: { Type: 'oneshot', WorkingDirectory: workingDirectory },
218
- });
210
+ }) => scriptProbeCommandFactory({ nodePath, scriptPath, user, workingDirectory });
219
211
 
220
212
  /**
221
213
  * Renders the systemd unit used to supervise the forward proxy.
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Express middleware and controller/router helpers for engine APIs.
3
3
  *
4
- * @module src/server/middlewares.js
4
+ * @module src/server/network/middlewares.js
5
5
  * @namespace Middlewares
6
6
  */
7
7
 
8
- import { loggerFactory } from './logger.js';
9
- import { moderatorGuard, adminGuard } from './auth.js';
8
+ import { loggerFactory } from '../ops/logger.js';
9
+ import { moderatorGuard, adminGuard } from '../security/auth.js';
10
10
 
11
11
  const logger = loggerFactory(import.meta);
12
12
 
@@ -0,0 +1,98 @@
1
+ /**
2
+ * What each node role is allowed to do, as one table the rest of the platform reads.
3
+ *
4
+ * The roles are the three the topology already defines — `hub`, `control`, `worker` — and this
5
+ * module adds no fourth. What it adds is a single answer to a question that was previously spread
6
+ * across the commands that happened to ask it: `wireguard` knew HAProxy is hub-only, `event` knew
7
+ * the dispatcher is control-only, and the sync steps knew cron publication is control-only, but
8
+ * nothing stated the boundary those three agree on.
9
+ *
10
+ * The distinction the table exists to hold is between a Kubernetes **node** and a Kubernetes
11
+ * **administrator**. A worker runs the kubelet and joins the cluster; that is node runtime, and it
12
+ * is not permission to administer the cluster it belongs to. Being managed by the host domain is
13
+ * not permission either — `underpost host` is node-level operational configuration, and every role
14
+ * has it.
15
+ *
16
+ * @module src/server/network/node-capability.js
17
+ * @namespace NodeCapability
18
+ */
19
+
20
+ /**
21
+ * @constant NODE_CAPABILITIES
22
+ * @description Capabilities held by each role, derived from the operations the repository
23
+ * actually gates: HAProxy and the forward proxy refuse to configure themselves off the hub, the
24
+ * dispatcher refuses to install off a control node, and the sync sequence publishes CronJobs from
25
+ * the control node alone.
26
+ * @memberof NodeCapability
27
+ */
28
+ const NODE_CAPABILITIES = Object.freeze({
29
+ hub: Object.freeze([
30
+ 'host-configuration',
31
+ 'wireguard-hub',
32
+ 'haproxy',
33
+ 'forward-proxy',
34
+ 'edge-routing',
35
+ 'node-metrics',
36
+ ]),
37
+ control: Object.freeze([
38
+ 'host-configuration',
39
+ 'wireguard-spoke',
40
+ 'kubernetes-node',
41
+ 'kubernetes-administration',
42
+ 'cluster-secret-administration',
43
+ 'cron-publication',
44
+ 'event-service',
45
+ 'node-metrics',
46
+ ]),
47
+ worker: Object.freeze(['host-configuration', 'wireguard-spoke', 'kubernetes-node', 'node-metrics']),
48
+ });
49
+
50
+ /** The roles the topology defines. Ordered hub-first, as every fleet listing is. */
51
+ const NODE_ROLES = Object.freeze(Object.keys(NODE_CAPABILITIES));
52
+
53
+ /**
54
+ * Capabilities that reach the Kubernetes API with cluster-wide authority.
55
+ *
56
+ * Named apart from the rest because they are the ones a role must never acquire by side effect:
57
+ * possessing `kubectl`, joining the cluster, or carrying the host environment are each a reason
58
+ * someone might assume these follow, and none of them is.
59
+ * @memberof NodeCapability
60
+ */
61
+ const CLUSTER_ADMIN_CAPABILITIES = Object.freeze([
62
+ 'kubernetes-administration',
63
+ 'cluster-secret-administration',
64
+ 'cron-publication',
65
+ ]);
66
+
67
+ /**
68
+ * Whether a role holds a capability.
69
+ * @param {string} role - `hub`, `control` or `worker`.
70
+ * @param {string} capability - Capability name.
71
+ * @returns {boolean} True when the role holds it.
72
+ * @memberof NodeCapability
73
+ */
74
+ const roleHasCapability = (role, capability) => (NODE_CAPABILITIES[role] || []).includes(capability);
75
+
76
+ /**
77
+ * Refuses an operation the role does not hold the capability for.
78
+ *
79
+ * Fail-closed on an unknown role as well as an unheld capability: a node whose document names a
80
+ * role this table does not define has no capabilities, rather than the union of the ones it might
81
+ * have meant.
82
+ * @param {object} params - Assertion context.
83
+ * @param {string} params.role - Role of the node the operation would run on.
84
+ * @param {string} params.capability - Capability the operation requires.
85
+ * @param {string} params.operation - Operation being attempted, named in the refusal.
86
+ * @throws {Error} When the role does not hold the capability.
87
+ * @memberof NodeCapability
88
+ */
89
+ const assertRoleCapability = ({ role, capability, operation }) => {
90
+ if (roleHasCapability(role, capability)) return;
91
+ const held = NODE_CAPABILITIES[role];
92
+ throw new Error(
93
+ `[capability] ${operation} requires '${capability}', which the '${role || '(unset)'}' role does not hold; ` +
94
+ (held ? `it holds ${held.join(', ')}` : `known roles are ${NODE_ROLES.join(', ')}`),
95
+ );
96
+ };
97
+
98
+ export { CLUSTER_ADMIN_CAPABILITIES, NODE_CAPABILITIES, NODE_ROLES, assertRoleCapability, roleHasCapability };
@@ -3,14 +3,14 @@
3
3
  * Initializes and configures the PeerJS server instance, typically running
4
4
  * alongside a main Node.js application.
5
5
  *
6
- * @module src/server/peer.js
6
+ * @module src/server/network/peer.js
7
7
  * @namespace Peer
8
8
  */
9
9
 
10
10
  import { PeerServer } from 'peer';
11
11
  import dotenv from 'dotenv';
12
- import { loggerFactory } from './logger.js';
13
- import Underpost from '../index.js';
12
+ import { loggerFactory } from '../ops/logger.js';
13
+ import Underpost from '../../index.js';
14
14
 
15
15
  /**
16
16
  * Logger instance for this module, utilizing the framework's factory.
@@ -1,26 +1,20 @@
1
1
  /**
2
2
  * Manages the creation and configuration of the reverse proxy server,
3
3
  * including handling HTTP/HTTPS listeners and routing based on host configuration.
4
- * @module src/server/proxy.js
4
+ * @module src/server/network/proxy.js
5
5
  * @namespace ProxyService
6
6
  */
7
7
  'use strict';
8
8
 
9
9
  import express from 'express';
10
10
  import { createProxyMiddleware } from 'http-proxy-middleware';
11
- import { loggerFactory, loggerMiddleware } from './logger.js';
12
- import {
13
- buildPortProxyRouter,
14
- buildProxyRouter,
15
- etcHostFactory,
16
- getTlsHosts,
17
- isDevProxyContext,
18
- isTlsDevProxy,
19
- } from './conf.js';
20
-
21
- import { shellExec } from './process.js';
11
+ import { loggerFactory, loggerMiddleware } from '../ops/logger.js';
12
+ import { etcHostFactory, getTlsHosts, isDevProxyContext, isTlsDevProxy } from '../runtime/conf.js';
13
+ import { buildPortProxyRouter, buildProxyRouter } from './router.js';
14
+
15
+ import { shellExec } from '../runtime/process.js';
22
16
  import fs from 'fs-extra';
23
- import Underpost from '../index.js';
17
+ import Underpost from '../../index.js';
24
18
 
25
19
  const logger = loggerFactory(import.meta);
26
20