@underpostnet/cyberia 3.3.0 → 3.3.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +17 -5
  3. package/.github/workflows/coverall.cyberia.ci.yml +39 -14
  4. package/.github/workflows/cyberia-client.cd.yml +5 -0
  5. package/.github/workflows/cyberia-server.cd.yml +5 -0
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +3 -0
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +35 -20
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/publish.cyberia.ci.yml +44 -0
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +1 -0
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +96 -0
  22. package/CHANGELOG.md +653 -2513
  23. package/CLI-HELP.md +323 -157
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +5 -5
  27. package/README.md +48 -28
  28. package/bin/build.js +86 -41
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +1494 -1403
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +1494 -1403
  33. package/compose.env +17 -5
  34. package/conf.js +98 -7
  35. package/deploy/cyberia-client/deploy.sh +46 -0
  36. package/deploy/cyberia-client/package.sh +17 -0
  37. package/deploy/cyberia-client/state.sh +15 -0
  38. package/deploy/cyberia-server/deploy.sh +46 -0
  39. package/deploy/cyberia-server/package.sh +17 -0
  40. package/deploy/cyberia-server/state.sh +15 -0
  41. package/deploy/dd-cyberia/deploy.sh +9 -29
  42. package/deploy/dd-cyberia/init.sh +38 -45
  43. package/deploy/dd-cyberia/package.sh +16 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +133 -147
  46. package/deploy/lib/config.sh +29 -0
  47. package/deploy/lib/github-actions-logging.sh +610 -0
  48. package/deploy/lib/host.sh +194 -0
  49. package/deploy/lib/state.sh +65 -0
  50. package/deploy/pwa-microservices-template/deploy.sh +17 -42
  51. package/deploy/release/deploy.sh +9 -41
  52. package/deployment.yaml +7 -2
  53. package/docker-compose.yml +23 -17
  54. package/examples/static-page/README.md +19 -19
  55. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  56. package/hardhat/hardhat.config.js +1 -6
  57. package/hardhat/package-lock.json +101 -40
  58. package/hardhat/package.json +2 -2
  59. package/manifests/alertmanager/deployment.yaml +81 -0
  60. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  61. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
  62. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
  63. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  64. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  65. package/manifests/deployment/mongo-express/deployment.yaml +46 -27
  66. package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
  67. package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
  68. package/manifests/deployment/mongo-express/service.yaml +16 -0
  69. package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
  70. package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
  71. package/manifests/grafana/deployment.yaml +26 -7
  72. package/manifests/grafana/kustomization.yaml +1 -0
  73. package/manifests/grafana/service.yaml +6 -1
  74. package/manifests/mariadb/pv.yaml +1 -0
  75. package/manifests/mongodb/statefulset.yaml +9 -2
  76. package/manifests/mysql/pv-pvc.yaml +14 -1
  77. package/manifests/postgresql/pv.yaml +12 -1
  78. package/manifests/postgresql/pvc.yaml +1 -0
  79. package/manifests/prometheus/deployment.yaml +18 -22
  80. package/package.json +87 -12
  81. package/scripts/event-monitor.sh +56 -0
  82. package/scripts/k3s-node-setup.sh +27 -14
  83. package/scripts/kubeadm-node-setup.sh +31 -11
  84. package/scripts/maas-setup.sh +8 -8
  85. package/scripts/selinux-normalize.sh +907 -0
  86. package/scripts/shutdown-machine.sh +843 -0
  87. package/scripts/test-monitor.sh +5 -5
  88. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +3 -3
  99. package/src/api/cyberia-action/cyberia-action.service.js +5 -6
  100. package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
  101. package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
  102. package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
  103. package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
  104. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +2 -4
  105. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
  106. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
  107. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
  108. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  109. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
  110. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
  111. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  112. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  113. package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
  114. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  115. package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
  116. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
  117. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
  118. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -2
  119. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
  120. package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
  121. package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -40
  122. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
  123. package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
  124. package/src/api/cyberia-instance/cyberia-instance-map.service.js +35 -142
  125. package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
  126. package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
  127. package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
  128. package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
  129. package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
  130. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  131. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
  132. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  133. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
  134. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  135. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  136. package/src/api/cyberia-map/cyberia-map.service.js +8 -4
  137. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
  138. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
  139. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
  140. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
  141. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  142. package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
  143. package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
  144. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  145. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
  146. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  147. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  148. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  149. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  150. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  151. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -214
  152. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  153. package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
  154. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  155. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  156. package/src/api/default/default.controller.js +1 -1
  157. package/src/api/default/default.router.js +1 -1
  158. package/src/api/default/default.service.js +2 -2
  159. package/src/api/document/document.controller.js +1 -1
  160. package/src/api/document/document.router.js +1 -1
  161. package/src/api/document/document.service.js +2 -2
  162. package/src/api/file/file.controller.js +1 -1
  163. package/src/api/file/file.ref.js +153 -0
  164. package/src/api/file/file.ref.json +11 -2
  165. package/src/api/file/file.router.js +1 -1
  166. package/src/api/file/file.service.js +2 -2
  167. package/src/api/instance/instance.controller.js +1 -1
  168. package/src/api/instance/instance.router.js +1 -1
  169. package/src/api/instance/instance.service.js +2 -2
  170. package/src/api/ipfs/ipfs.controller.js +1 -1
  171. package/src/api/ipfs/ipfs.router.js +2 -2
  172. package/src/api/ipfs/ipfs.service.js +2 -2
  173. package/src/api/object-layer/object-layer.controller.js +1 -1
  174. package/src/api/object-layer/object-layer.model.js +47 -12
  175. package/src/api/object-layer/object-layer.router.js +12 -5
  176. package/src/api/object-layer/object-layer.service.js +116 -123
  177. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  178. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  179. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  180. package/src/api/test/test.controller.js +1 -1
  181. package/src/api/test/test.service.js +1 -1
  182. package/src/api/user/guest.service.js +3 -3
  183. package/src/api/user/user.controller.js +1 -1
  184. package/src/api/user/user.router.js +2 -2
  185. package/src/api/user/user.service.js +4 -4
  186. package/src/api.js +5 -9
  187. package/src/cli/app.js +402 -0
  188. package/src/cli/baremetal.js +30 -35
  189. package/src/cli/client.js +306 -0
  190. package/src/cli/cloud-init.js +3 -3
  191. package/src/cli/cluster.js +191 -82
  192. package/src/cli/db.js +120 -68
  193. package/src/cli/deploy.js +157 -75
  194. package/src/cli/docker-compose.js +5 -5
  195. package/src/cli/domains.js +184 -0
  196. package/src/cli/dotenv-store.js +143 -0
  197. package/src/cli/event.js +2281 -0
  198. package/src/cli/fs-selection.js +115 -0
  199. package/src/cli/fs.js +159 -343
  200. package/src/cli/host.js +672 -0
  201. package/src/cli/image.js +4 -6
  202. package/src/cli/index.js +343 -151
  203. package/src/cli/ipfs.js +34 -30
  204. package/src/cli/kickstart.js +1 -1
  205. package/src/cli/kubectl.js +218 -41
  206. package/src/cli/lxd.js +3 -3
  207. package/src/cli/monitor.js +1359 -26
  208. package/src/cli/package.js +90 -0
  209. package/src/cli/release.js +16 -12
  210. package/src/cli/repository.js +586 -363
  211. package/src/cli/run.js +398 -843
  212. package/src/cli/secrets.js +2158 -964
  213. package/src/cli/ssh.js +478 -279
  214. package/src/cli/state.js +394 -0
  215. package/src/cli/static.js +2 -2
  216. package/src/cli/system.js +1 -1
  217. package/src/cli/test.js +203 -125
  218. package/src/cli/vultr.js +61 -21
  219. package/src/cli/wireguard.js +1112 -306
  220. package/src/client/components/core/CalendarCore.js +53 -96
  221. package/src/client/components/core/Docs.js +327 -303
  222. package/src/client/components/core/FileExplorer.js +0 -21
  223. package/src/client/components/core/Modal.js +56 -1
  224. package/src/client/components/core/PanelForm.js +4 -4
  225. package/src/client/components/core/Repository.js +56 -0
  226. package/src/client/components/core/Translate.js +7 -0
  227. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  228. package/src/client/components/core/Wallet.js +0 -11
  229. package/src/client/components/core/Worker.js +7 -1
  230. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  231. package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
  232. package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
  233. package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
  234. package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
  235. package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
  236. package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
  237. package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
  238. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
  239. package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
  240. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -35
  241. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
  242. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
  243. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  244. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
  245. package/src/client/components/default/AppShellDefault.js +1 -1
  246. package/src/client/components/default/SettingsDefault.js +2 -2
  247. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  248. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  249. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  250. package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
  251. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
  252. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
  253. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
  254. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
  255. package/src/client/public/cyberia-docs/CYBERIA.md +48 -28
  256. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
  257. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  258. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  259. package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
  260. package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
  261. package/src/client/public/default/android-chrome-144x144.png +0 -0
  262. package/src/client/public/default/android-chrome-192x192.png +0 -0
  263. package/src/client/public/default/android-chrome-256x256.png +0 -0
  264. package/src/client/public/default/android-chrome-36x36.png +0 -0
  265. package/src/client/public/default/android-chrome-384x384.png +0 -0
  266. package/src/client/public/default/android-chrome-48x48.png +0 -0
  267. package/src/client/public/default/android-chrome-512x512.png +0 -0
  268. package/src/client/public/default/android-chrome-72x72.png +0 -0
  269. package/src/client/public/default/android-chrome-96x96.png +0 -0
  270. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  271. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  272. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  273. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  274. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  275. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  276. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  277. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  278. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  279. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  280. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  281. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  282. package/src/client/public/default/apple-touch-icon.png +0 -0
  283. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  284. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  285. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  286. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  287. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  288. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  289. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  290. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  291. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  292. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  293. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  294. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  295. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  296. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  297. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  298. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  299. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  300. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  301. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  302. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  303. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  304. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  305. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  306. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  307. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  308. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  309. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  310. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  311. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  312. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  313. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  314. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  315. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  316. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  317. package/src/client/public/default/assets/background/white.jpg +0 -0
  318. package/src/client/public/default/browserconfig.xml +1 -1
  319. package/src/client/public/default/favicon-16x16.png +0 -0
  320. package/src/client/public/default/favicon-32x32.png +0 -0
  321. package/src/client/public/default/favicon-48x48.png +0 -0
  322. package/src/client/public/default/favicon.ico +0 -0
  323. package/src/client/public/default/manifest.webmanifest +5 -5
  324. package/src/client/public/default/mstile-144x144.png +0 -0
  325. package/src/client/public/default/mstile-150x150.png +0 -0
  326. package/src/client/public/default/mstile-310x150.png +0 -0
  327. package/src/client/public/default/mstile-310x310.png +0 -0
  328. package/src/client/public/default/mstile-70x70.png +0 -0
  329. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  330. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  331. package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
  332. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
  333. package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
  334. package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
  335. package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
  336. package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
  337. package/src/client/services/object-layer/object-layer.management.js +6 -10
  338. package/src/client/services/object-layer/object-layer.service.js +3 -1
  339. package/src/client/ssr/RootDocument.js +1 -1
  340. package/src/client/ssr/body/404.js +1 -1
  341. package/src/client/ssr/body/500.js +1 -1
  342. package/src/client/ssr/body/CacheControl.js +1 -1
  343. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  344. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  345. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  346. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  347. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  348. package/src/client/ssr/head/Css.js +1 -1
  349. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  350. package/src/client/ssr/head/DefaultScripts.js +1 -1
  351. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  352. package/src/client/ssr/head/Microdata.js +1 -1
  353. package/src/client/ssr/head/Production.js +1 -1
  354. package/src/client/ssr/head/Pwa.js +1 -1
  355. package/src/client/ssr/head/PwaItemledger.js +1 -1
  356. package/src/client/ssr/head/Seo.js +1 -1
  357. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  358. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  359. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  360. package/src/client/ssr/views/Cyberia404.js +7 -5
  361. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  362. package/src/client/ssr/views/Maintenance.js +1 -1
  363. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  364. package/src/client/ssr/views/Test.js +1 -1
  365. package/src/client/sw/core.sw.js +20 -14
  366. package/src/client-builder/client-build-docs.js +92 -77
  367. package/src/client-builder/client-build-live.js +2 -2
  368. package/src/client-builder/client-build.js +105 -74
  369. package/src/client-builder/client-bundle.js +347 -0
  370. package/src/client-builder/client-dev-server.js +3 -3
  371. package/src/client-builder/client-icons.js +2 -2
  372. package/src/client-builder/ssr.js +3 -3
  373. package/src/client.build.js +3 -6
  374. package/src/client.dev.js +3 -6
  375. package/src/db/DataBaseProvider.js +186 -3
  376. package/src/db/mariadb/MariaDB.js +3 -2
  377. package/src/db/mongo/MongoBootstrap.js +273 -101
  378. package/src/db/mongo/MongoExpress.js +187 -0
  379. package/src/db/mongo/MongooseDB.js +7 -8
  380. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  381. package/src/grpc/cyberia/grpc-server.js +6 -8
  382. package/src/index.js +79 -23
  383. package/src/mailer/EmailRender.js +2 -2
  384. package/src/mailer/MailerInterceptor.js +87 -0
  385. package/src/mailer/MailerProvider.js +50 -6
  386. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +144 -147
  387. package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
  388. package/src/projects/cyberia/besu-genesis-generator.js +8 -17
  389. package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
  390. package/src/projects/cyberia/catalog-cyberia.js +54 -10
  391. package/src/projects/cyberia/gemini-client.js +4 -4
  392. package/src/projects/cyberia/generate-saga.js +5 -12
  393. package/src/projects/cyberia/hot-reload-trigger.js +18 -29
  394. package/src/projects/cyberia/instance-backup.js +210 -0
  395. package/src/projects/cyberia/instance-data.js +178 -258
  396. package/src/projects/cyberia/ipfs-client.js +4 -4
  397. package/src/projects/cyberia/map-preview-generator.js +33 -69
  398. package/src/projects/cyberia/object-layer.js +153 -320
  399. package/src/projects/cyberia/seed-audio.js +139 -0
  400. package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
  401. package/src/projects/cyberia/semantic-layer-generator.js +3 -19
  402. package/src/projects/cyberia/stat-balance.js +81 -0
  403. package/src/projects/cyberia/stat-commands.js +23 -0
  404. package/src/projects/cyberia/stat-contract-generator.js +101 -0
  405. package/src/projects/underpost/catalog-underpost.js +9 -1
  406. package/src/proxy.js +4 -7
  407. package/src/runtime/cyberia-client/Dockerfile +17 -8
  408. package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
  409. package/src/runtime/cyberia-server/Dockerfile +18 -6
  410. package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
  411. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  412. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  413. package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
  414. package/src/runtime/engine-cyberia/compose.env +17 -5
  415. package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
  416. package/src/runtime/express/Express.js +32 -27
  417. package/src/runtime/lampp/Lampp.js +22 -70
  418. package/src/runtime/nginx/Nginx.js +1 -1
  419. package/src/runtime/wp/Wp.js +16 -48
  420. package/src/server/{catalog.js → build/catalog.js} +15 -5
  421. package/src/server/build/coverage.js +188 -0
  422. package/src/server/build/execution.js +402 -0
  423. package/src/server/build/package.js +508 -0
  424. package/src/server/build/testing.js +578 -0
  425. package/src/server/{dns.js → network/dns.js} +144 -11
  426. package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
  427. package/src/server/{middlewares.js → network/middlewares.js} +11 -5
  428. package/src/server/network/node-capability.js +98 -0
  429. package/src/server/{peer.js → network/peer.js} +3 -3
  430. package/src/server/{proxy.js → network/proxy.js} +7 -13
  431. package/src/server/network/router.js +356 -0
  432. package/src/server/{tls.js → network/tls.js} +2 -2
  433. package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
  434. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
  435. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
  436. package/src/server/{cri.js → ops/cri.js} +2 -2
  437. package/src/server/{cron.js → ops/cron.js} +349 -74
  438. package/src/server/ops/event-notification.js +284 -0
  439. package/src/server/{logger.js → ops/logger.js} +143 -23
  440. package/src/server/ops/monitoring.js +1724 -0
  441. package/src/server/{systemd.js → ops/systemd.js} +55 -1
  442. package/src/server/{conf.js → runtime/conf.js} +516 -423
  443. package/src/server/runtime/config-scope.js +215 -0
  444. package/src/server/runtime/environment.js +149 -0
  445. package/src/server/{process.js → runtime/process.js} +153 -12
  446. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  447. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  448. package/src/server/{start.js → runtime/start.js} +128 -39
  449. package/src/server/{auth.js → security/auth.js} +7 -8
  450. package/src/server/security/container-storage.js +382 -0
  451. package/src/server/{crypto.js → security/crypto.js} +1 -1
  452. package/src/server/{selinux.js → security/selinux.js} +1 -1
  453. package/src/server/{backup.js → storage/backup.js} +17 -8
  454. package/src/server/{data-query.js → storage/data-query.js} +17 -1
  455. package/src/server/storage/downloader.js +121 -0
  456. package/src/server/storage/repository.js +68 -0
  457. package/src/server/storage/zip.js +153 -0
  458. package/src/server.js +4 -7
  459. package/src/ws/IoInterface.js +1 -1
  460. package/src/ws/IoServer.js +1 -1
  461. package/src/ws/core/core.ws.connection.js +1 -1
  462. package/src/ws/core/core.ws.emit.js +1 -1
  463. package/src/ws/core/core.ws.server.js +1 -1
  464. package/src/ws/default/default.ws.connection.js +1 -1
  465. package/src/ws/default/default.ws.emit.js +1 -1
  466. package/src/ws/default/default.ws.server.js +1 -1
  467. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  468. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  469. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  470. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  471. package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
  472. package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
  473. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +64 -0
  474. package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
  475. package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
  476. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
  477. package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
  478. package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
  479. package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
  480. package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
  481. package/test/integration/app/cyberia/fallback-world-capture.test.js +338 -0
  482. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  483. package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
  484. package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
  485. package/test/integration/app/cyberia/seed-audio.test.js +275 -0
  486. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  487. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  488. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  489. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  490. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  491. package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
  492. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  493. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  494. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  495. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  496. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  497. package/test/integration/infra/2-network/wireguard-cli.test.js +1187 -0
  498. package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
  499. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  500. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  501. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  502. package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
  503. package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
  504. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  505. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  506. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  507. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
  508. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
  509. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  510. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  511. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  512. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  513. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  514. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  515. package/test/support/shell-harness.js +73 -0
  516. package/test/unit/build-template.test.js +97 -0
  517. package/test/unit/build-workflow-offline.test.js +132 -0
  518. package/test/unit/catalog.test.js +71 -0
  519. package/test/unit/client-build-docs.test.js +361 -0
  520. package/test/unit/client-bundle.test.js +313 -0
  521. package/test/unit/conf-loading.test.js +303 -0
  522. package/test/unit/conf-resolution.test.js +996 -0
  523. package/test/unit/coverage-artifact.test.js +221 -0
  524. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  525. package/test/unit/cyberia/instance-backup.test.js +183 -0
  526. package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
  527. package/test/unit/cyberia/publish-workflow.test.js +22 -0
  528. package/test/unit/cyberia/stat-balance.test.js +69 -0
  529. package/test/unit/deploy-env-resolution.test.js +38 -0
  530. package/test/unit/deploy-log-table.test.js +518 -0
  531. package/test/unit/downloader-integrity.test.js +98 -0
  532. package/test/unit/execution-profiles.test.js +219 -0
  533. package/test/unit/file-reference-registry.test.js +141 -0
  534. package/test/unit/fleet-sync-source.test.js +149 -0
  535. package/test/unit/fs-storage-paths.test.js +596 -0
  536. package/test/unit/logger-redaction.test.js +141 -0
  537. package/test/unit/package.test.js +457 -0
  538. package/test/unit/prepare-host.test.js +382 -0
  539. package/test/unit/process-environment.test.js +18 -0
  540. package/test/unit/propagation-message.test.js +78 -0
  541. package/test/unit/redeploy-plan.test.js +24 -0
  542. package/test/unit/release-bump.test.js +474 -0
  543. package/test/unit/ssh-output-redaction.test.js +28 -0
  544. package/test/unit/start-options.test.js +46 -0
  545. package/test/unit/test-tiers.test.js +220 -0
  546. package/test/unit/zip-archive.test.js +142 -0
  547. package/vitest.config.js +66 -0
  548. package/.nycrc +0 -9
  549. package/deploy/lib/logging.sh +0 -96
  550. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  551. package/manifests/mongodb/pv-pvc.yaml +0 -59
  552. package/scripts/coverall-test-cyberia.sh +0 -24
  553. package/scripts/coverall-test.sh +0 -24
  554. package/scripts/link-local-underpost-cli.sh +0 -6
  555. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
  556. package/src/api/user/user.build.js +0 -16
  557. package/src/cli/env.js +0 -177
  558. package/src/client/components/core/Blockchain.js +0 -41
  559. package/src/client/components/core/Blog.js +0 -9
  560. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  561. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
  562. package/src/client/public/default/assets/background/dark.jpg +0 -0
  563. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  564. package/src/client/public/default/assets/background/white0.jpg +0 -0
  565. package/src/client/public/doc/favicon.ico +0 -0
  566. package/src/client/public/doc/sitemap +0 -148
  567. package/src/server/downloader.js +0 -73
  568. package/src/server/environment.js +0 -98
@@ -0,0 +1,284 @@
1
+ import fs from 'fs-extra';
2
+ import { resolveConfSecrets } from '../runtime/conf.js';
3
+ import { loggerFactory } from './logger.js';
4
+ import { MailerProvider } from '../../mailer/MailerProvider.js';
5
+
6
+ /**
7
+ * The notification contract for operational events.
8
+ *
9
+ * Detection and remediation are declared in code because they are behaviour;
10
+ * who hears about them is deployment data, and lives in
11
+ * `engine-private/deploy/conf.event.json`. Adding a subscriber or repointing a
12
+ * transport is therefore a configuration change, and no recipient address or
13
+ * credential reaches the event registry, a rendered manifest, or this
14
+ * repository.
15
+ *
16
+ * @module src/server/ops/event-notification.js
17
+ * @namespace UnderpostEventNotification
18
+ */
19
+
20
+ const logger = loggerFactory(import.meta);
21
+
22
+ /**
23
+ * @constant EVENT_CONF_PATH
24
+ * @description The notification contract, read relative to the engine checkout
25
+ * every command already resolves its deploy configuration from.
26
+ * @memberof UnderpostEventNotification
27
+ */
28
+ const EVENT_CONF_PATH = './engine-private/deploy/conf.event.json';
29
+
30
+ const EMPTY_CONF = { 'notification-providers': {}, events: {} };
31
+
32
+ /** What a rule writes where its declared threshold belongs. */
33
+ const THRESHOLD_TOKEN = '<threshold>';
34
+
35
+ /**
36
+ * @method readEventConf
37
+ * @description Parses the contract without resolving `env:` references.
38
+ *
39
+ * Structure and secrets are read apart so the shape can be listed, validated
40
+ * and tested on a machine that holds none of the credentials.
41
+ * @returns {{'notification-providers': object, events: object}} Parsed contract.
42
+ * @throws {Error} When the file exists but does not parse.
43
+ * @memberof UnderpostEventNotification
44
+ */
45
+ const readEventConf = () => {
46
+ if (!fs.existsSync(EVENT_CONF_PATH)) return { ...EMPTY_CONF };
47
+ try {
48
+ const source = JSON.parse(fs.readFileSync(EVENT_CONF_PATH, 'utf8'));
49
+ return {
50
+ 'notification-providers': source['notification-providers'] || {},
51
+ events: source.events || {},
52
+ };
53
+ } catch (error) {
54
+ throw new Error(`[event] invalid notification contract ${EVENT_CONF_PATH}: ${error.message}`);
55
+ }
56
+ };
57
+
58
+ const recipientFactory = (subscriber = {}) => {
59
+ const email = `${subscriber.email || ''}`.trim();
60
+ const name = `${subscriber.name || ''}`.trim();
61
+ return email ? { email, name, address: name ? `${name} <${email}>` : email } : undefined;
62
+ };
63
+
64
+ /**
65
+ * @constant NOTIFICATION_PROVIDER_TYPES
66
+ * @description The transports a notification route can name.
67
+ *
68
+ * `describe` renders the route for `--list` and validates it; `deliver` sends
69
+ * one rendered notification. A type is one entry here, so adding a transport
70
+ * never means editing the dispatcher.
71
+ * @memberof UnderpostEventNotification
72
+ */
73
+ const NOTIFICATION_PROVIDER_TYPES = {
74
+ mailer: {
75
+ describe: (provider) => {
76
+ const transport = provider?.mailer?.transport || {};
77
+ const host = `${transport.host || ''}`.replace(/^env:.*/, '(env)');
78
+ if (!transport.host) throw new Error('mailer provider has no transport.host');
79
+ if (!provider?.mailer?.sender?.email) throw new Error('mailer provider has no sender.email');
80
+ return `smtp ${host}`;
81
+ },
82
+ deliver: async ({ providerId, provider, recipients, subject, text }) => {
83
+ const mailer = resolveConfSecrets(provider.mailer);
84
+ const port = Number(mailer.transport?.port) || 587;
85
+ const id = `event-notification:${providerId}`;
86
+
87
+ await MailerProvider.load({
88
+ id,
89
+ sender: { email: mailer.sender.email, name: mailer.sender.name || 'Underpost' },
90
+ transport: {
91
+ host: mailer.transport.host,
92
+ port,
93
+ secure: `${mailer.transport?.secure}` === 'true' || port === 465,
94
+ auth: { user: mailer.transport?.auth?.user || '', pass: mailer.transport?.auth?.pass || '' },
95
+ },
96
+ templates: {},
97
+ });
98
+
99
+ // Plain text by design: an operational alert must not depend on a client
100
+ // build being present on the host that dispatches it.
101
+ try {
102
+ const info = await MailerProvider.send({
103
+ id,
104
+ sendOptions: { to: recipients.map((recipient) => recipient.address).join(', '), subject, text },
105
+ });
106
+ return Boolean(info);
107
+ } finally {
108
+ // One delivery per dispatch: an open SMTP socket would outlive the
109
+ // command that sent it and keep the process from exiting.
110
+ MailerProvider.close(id);
111
+ }
112
+ },
113
+ },
114
+ };
115
+
116
+ /**
117
+ * @method eventNotificationRoutes
118
+ * @description Resolves where one event's notifications go.
119
+ *
120
+ * An unresolvable route is returned carrying its reason rather than thrown, so
121
+ * `--list` can show a broken contract before an outage does.
122
+ * @param {string} eventId - Registered event id.
123
+ * @param {object} [conf] - Parsed contract; read from disk when omitted.
124
+ * @returns {Array<{providerId: string, type: string, target: string, recipients: Array<object>, error?: string}>} Routes.
125
+ * @memberof UnderpostEventNotification
126
+ */
127
+ const eventNotificationRoutes = (eventId, conf = readEventConf()) => {
128
+ const providers = conf['notification-providers'] || {};
129
+ const notifications = conf.events?.[eventId]?.notifications || [];
130
+
131
+ if (notifications.length === 0)
132
+ return [
133
+ {
134
+ providerId: '',
135
+ type: '',
136
+ target: '',
137
+ recipients: [],
138
+ error: `no notification is declared for '${eventId}' in ${EVENT_CONF_PATH}`,
139
+ },
140
+ ];
141
+
142
+ return notifications.map((notification) => {
143
+ const providerId = `${notification['notification-provider-id'] || ''}`;
144
+ const provider = providers[providerId];
145
+ const recipients = (notification.payload?.subscribers || []).map(recipientFactory).filter(Boolean);
146
+ const route = { providerId, type: `${provider?.type || ''}`, target: '', recipients };
147
+
148
+ if (!provider)
149
+ return { ...route, error: `notification-provider-id '${providerId}' is not declared in ${EVENT_CONF_PATH}` };
150
+ const type = NOTIFICATION_PROVIDER_TYPES[route.type];
151
+ if (!type) return { ...route, error: `unsupported notification provider type '${route.type}'` };
152
+ if (recipients.length === 0) return { ...route, error: `provider '${providerId}' has no subscriber with an email` };
153
+ try {
154
+ return { ...route, target: type.describe(provider), provider };
155
+ } catch (error) {
156
+ return { ...route, error: `provider '${providerId}': ${error.message}` };
157
+ }
158
+ });
159
+ };
160
+
161
+ /**
162
+ * @method assertNotificationRoutes
163
+ * @description Refuses a contract that cannot deliver.
164
+ *
165
+ * Detection without a route to a human is the failure mode this guards: the
166
+ * remediation runs, nobody learns it ran, and a repeated repair goes unnoticed.
167
+ * @param {Array<object>} routes - Resolved routes, keyed by event id.
168
+ * @returns {Array<object>} The same routes, when every one resolves.
169
+ * @throws {Error} Naming each unresolved route.
170
+ * @memberof UnderpostEventNotification
171
+ */
172
+ const assertNotificationRoutes = (routes = []) => {
173
+ const unresolved = routes.filter((route) => route.error);
174
+ if (unresolved.length > 0)
175
+ throw new Error(
176
+ `[event] notification routes are unresolved:\n${unresolved.map((route) => `- ${route.error}`).join('\n')}`,
177
+ );
178
+ return routes;
179
+ };
180
+
181
+ /**
182
+ * @method deliverEventNotification
183
+ * @description Sends one rendered notification over every route the event declares.
184
+ *
185
+ * Routes are independent subscribers: one failing transport must not silence
186
+ * the rest, so each is attempted and reported separately.
187
+ * @param {object} params
188
+ * @param {string} params.eventId - Dispatched event id.
189
+ * @param {string} params.subject - Rendered subject.
190
+ * @param {string} params.text - Rendered body.
191
+ * @returns {Promise<{ok: boolean, delivered: Array<object>, failed: Array<object>}>} Per-route outcome.
192
+ * @memberof UnderpostEventNotification
193
+ */
194
+ const deliverEventNotification = async ({ eventId, subject, text }) => {
195
+ const routes = eventNotificationRoutes(eventId);
196
+ const delivered = [];
197
+ const failed = [];
198
+
199
+ for (const route of routes) {
200
+ const recipients = route.recipients.map((recipient) => recipient.email);
201
+ if (route.error) {
202
+ failed.push({ providerId: route.providerId, recipients, error: route.error });
203
+ continue;
204
+ }
205
+ try {
206
+ const ok = await NOTIFICATION_PROVIDER_TYPES[route.type].deliver({
207
+ providerId: route.providerId,
208
+ provider: route.provider,
209
+ recipients: route.recipients,
210
+ subject,
211
+ text,
212
+ });
213
+ if (ok) delivered.push({ providerId: route.providerId, recipients });
214
+ else failed.push({ providerId: route.providerId, recipients, error: 'transport rejected the message' });
215
+ } catch (error) {
216
+ failed.push({ providerId: route.providerId, recipients, error: `${error?.message || error}` });
217
+ }
218
+ }
219
+
220
+ for (const route of failed) logger.error('Event notification not delivered', { eventId, ...route });
221
+ if (delivered.length > 0) logger.info('Event notification delivered', { eventId, subject, routes: delivered });
222
+
223
+ return { ok: failed.length === 0 && delivered.length > 0, delivered, failed };
224
+ };
225
+
226
+ /**
227
+ * @method eventSchedule
228
+ * @description When an event's probes run, and how long its condition must hold
229
+ * before an alert fires.
230
+ *
231
+ * Both are declared per event in the contract rather than in the registry: how
232
+ * often a subject is asked and how long it must stay wrong are operational
233
+ * decisions tuned per deployment, and they are the two numbers Prometheus needs
234
+ * to schedule a job and evaluate the rule that job feeds. Reading them from one
235
+ * place is what stops a probe period and its alert window from drifting apart.
236
+ * @param {string} eventId - Registered event id.
237
+ * @param {object} [conf] - Parsed contract; read from disk when omitted.
238
+ * @returns {{probeInterval: string, alertFor: string, threshold: string}} Declared schedule; empty when undeclared.
239
+ * @memberof UnderpostEventNotification
240
+ */
241
+ const eventSchedule = (eventId, conf = readEventConf()) => {
242
+ const event = conf.events?.[eventId] || {};
243
+ return {
244
+ probeInterval: `${event.probeInterval || ''}`.trim(),
245
+ alertFor: `${event.alertFor || ''}`.trim(),
246
+ // A number the rule compares against: it belongs beside the cadence, not in
247
+ // an expression, because tuning it is a deployment decision.
248
+ threshold: `${event.threshold ?? ''}`.trim(),
249
+ };
250
+ };
251
+
252
+ /**
253
+ * @method assertEventSchedules
254
+ * @description Refuses to publish a rule whose cadence the contract does not declare.
255
+ *
256
+ * An undeclared period would silently inherit the global scrape interval and an
257
+ * undeclared window a hardcoded default — the second source of truth these
258
+ * attributes exist to remove.
259
+ * @param {Array<{id: string, schedule: object}>} [definitions] - Resolved definitions.
260
+ * @returns {Array<object>} The same definitions, when every schedule is declared.
261
+ * @throws {Error} Naming each event and the attribute it is missing.
262
+ * @memberof UnderpostEventNotification
263
+ */
264
+ const assertEventSchedules = (definitions = []) => {
265
+ const missing = definitions.flatMap(({ id, alert = {}, schedule = {} }) =>
266
+ ['probeInterval', 'alertFor', ...(`${alert.expr || ''}`.includes(THRESHOLD_TOKEN) ? ['threshold'] : [])]
267
+ .filter((key) => !schedule[key])
268
+ .map((key) => `- ${id}: ${key}`),
269
+ );
270
+ if (missing.length > 0) throw new Error(`[event] undeclared in ${EVENT_CONF_PATH}:\n${missing.join('\n')}`);
271
+ return definitions;
272
+ };
273
+
274
+ export {
275
+ EVENT_CONF_PATH,
276
+ THRESHOLD_TOKEN,
277
+ assertEventSchedules,
278
+ eventSchedule,
279
+ NOTIFICATION_PROVIDER_TYPES,
280
+ assertNotificationRoutes,
281
+ deliverEventNotification,
282
+ eventNotificationRoutes,
283
+ readEventConf,
284
+ };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Module for managing logger control and configuration
3
- * @module src/server/logger.js
3
+ * @module src/server/ops/logger.js
4
4
  * @namespace Logger
5
5
  */
6
6
 
@@ -11,7 +11,7 @@ import morgan from 'morgan';
11
11
  import { colorize, color } from 'json-colorizer';
12
12
  import colors from 'colors';
13
13
  import v8 from 'v8';
14
- import { clearTerminalStringColor, formatBytes } from '../client/components/core/CommonJs.js';
14
+ import { clearTerminalStringColor, formatBytes } from '../../client/components/core/CommonJs.js';
15
15
 
16
16
  colors.enable();
17
17
 
@@ -34,6 +34,128 @@ const levels = {
34
34
  */
35
35
  const level = (logLevel = '') => logLevel || 'info';
36
36
 
37
+ const REDACTED = '[REDACTED]';
38
+ const CONFIG_NAME_SOURCE = '[A-Za-z_][A-Za-z0-9_.-]*';
39
+ const SENSITIVE_VALUE_SOURCE = '(?:"[^"\\r\\n]*"|\'[^\'\\r\\n]*\'|[^\\s;&|]+)';
40
+ const SENSITIVE_WORDS = new Set([
41
+ 'authorization',
42
+ 'cookie',
43
+ 'credential',
44
+ 'pass',
45
+ 'passwd',
46
+ 'password',
47
+ 'secret',
48
+ 'token',
49
+ ]);
50
+ const SENSITIVE_COMPOUNDS = ['apikey', 'privatekey', 'accesskey', 'sessionid', 'mysqlpwd', 'mariadbpwd'];
51
+ /**
52
+ * A value adjacent to a sensitive name, separated by nothing but whitespace, is only treated as
53
+ * the secret when it is shaped like one: long enough, and carrying a digit, a capital, or a
54
+ * separator. Prose reads the same way — `token verification failed` — and redacting the next
55
+ * word of every sentence would cost more than it protects.
56
+ */
57
+ const CREDENTIAL_SHAPED = /^(?=.{12,}$)(?=.*[0-9A-Z_-])[A-Za-z0-9_-]+$/;
58
+ const sensitiveField = (key) => {
59
+ const words = `${key || ''}`
60
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
61
+ .toLowerCase()
62
+ .split(/[^a-z0-9]+/)
63
+ .filter(Boolean);
64
+ const compact = words.join('');
65
+ return (
66
+ words.some((word) => SENSITIVE_WORDS.has(word)) ||
67
+ SENSITIVE_COMPOUNDS.some((compound) => compact.endsWith(compound))
68
+ );
69
+ };
70
+
71
+ /**
72
+ * Redacts a value that follows a sensitive name with nothing but whitespace between them.
73
+ *
74
+ * Service errors report credentials this way — `Invalid api_key 4778…` — so the pair reaches a
75
+ * log through a message rather than through a command or a structured field, which is what every
76
+ * other rule matches on. The candidate is looked ahead rather than consumed: a plain match would
77
+ * take `Invalid api_key` as its own name/value pair and advance past the real one behind it.
78
+ * @param {string} text - Text to scan.
79
+ * @returns {string} The text with adjacent credentials redacted.
80
+ * @memberof Logger
81
+ */
82
+ const redactAdjacentCredentials = (text) => {
83
+ const pairs = new RegExp(`(${CONFIG_NAME_SOURCE})([ \\t]+)(?=([A-Za-z0-9_-]+)(?![\\w-]))`, 'g');
84
+ let out = '';
85
+ let cursor = 0;
86
+ for (const match of text.matchAll(pairs)) {
87
+ const [, key, separator, candidate] = match;
88
+ const valueStart = match.index + key.length + separator.length;
89
+ if (valueStart < cursor) continue;
90
+ if (!sensitiveField(key) || !CREDENTIAL_SHAPED.test(candidate)) continue;
91
+ out += text.slice(cursor, valueStart) + REDACTED;
92
+ cursor = valueStart + candidate.length;
93
+ }
94
+ return cursor === 0 ? text : out + text.slice(cursor);
95
+ };
96
+
97
+ const redactSensitiveText = (value = '') =>
98
+ redactAdjacentCredentials(
99
+ `${value ?? ''}`
100
+ .replace(/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g, REDACTED)
101
+ .replace(
102
+ /\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|glpat-[A-Za-z0-9_-]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)\b/g,
103
+ REDACTED,
104
+ )
105
+ .replace(/([a-z][a-z0-9+.-]*\\?:(?:\\?\/){2})(?:(?:\\.)|[^/\\\s@])+(\\?@)/gi, '$1***$2')
106
+ .replace(/\b(x-access-token\\?:)[^\s"']+?(?=\\?@github\.com\b)/gi, '$1***')
107
+ .replace(
108
+ /((?:"|')?(?:authorization|proxy-authorization)(?:"|')?\s*:\s*)(?:"[^"]*"|'[^']*'|(?:bearer|basic)\s+\S+|\S+)/gi,
109
+ `$1"${REDACTED}"`,
110
+ )
111
+ .replace(
112
+ new RegExp(
113
+ `(\\b(?:host|app|state|secret)\\s+set\\s+)(${CONFIG_NAME_SOURCE})(\\s+)(${SENSITIVE_VALUE_SOURCE})`,
114
+ 'gi',
115
+ ),
116
+ (match, prefix, key, separator) => (sensitiveField(key) ? `${prefix}${key}${separator}${REDACTED}` : match),
117
+ )
118
+ .replace(
119
+ new RegExp(`(\\s--?)(${CONFIG_NAME_SOURCE})(=|\\s+)(${SENSITIVE_VALUE_SOURCE})`, 'gi'),
120
+ (match, prefix, key, separator) => (sensitiveField(key) ? `${prefix}${key}${separator}${REDACTED}` : match),
121
+ )
122
+ .replace(
123
+ new RegExp(`(^|\\s)(-p)(\\s*)(${SENSITIVE_VALUE_SOURCE})`, 'gi'),
124
+ (match, prefix, flag, separator, secret) =>
125
+ secret.startsWith('-') ? match : `${prefix}${flag}${separator}${REDACTED}`,
126
+ )
127
+ .replace(
128
+ new RegExp(`\\b(${CONFIG_NAME_SOURCE})(\\s*=\\s*)(${SENSITIVE_VALUE_SOURCE})`, 'gi'),
129
+ (match, key, separator) => (sensitiveField(key) ? `${key}${separator}${REDACTED}` : match),
130
+ )
131
+ .replace(
132
+ new RegExp(`((?:"|')?)(${CONFIG_NAME_SOURCE})((?:"|')?\\s*:\\s*)(${SENSITIVE_VALUE_SOURCE})`, 'gi'),
133
+ (match, quote, key, separator) => (sensitiveField(key) ? `${quote}${key}${separator}"${REDACTED}"` : match),
134
+ ),
135
+ );
136
+
137
+ const serializeLogValue = (value) => {
138
+ const seen = new WeakSet();
139
+ const serialized = JSON.stringify(
140
+ value,
141
+ (key, current) => {
142
+ if (key && sensitiveField(key)) return REDACTED;
143
+ if (typeof current === 'string') return redactSensitiveText(current);
144
+ if (typeof current === 'bigint') return `${current}`;
145
+ if (typeof current === 'function') return `[Function: ${current.name || 'anonymous'}]`;
146
+ if (current instanceof Error)
147
+ return Object.fromEntries(Object.getOwnPropertyNames(current).map((name) => [name, current[name]]));
148
+ if (typeof current === 'object' && current !== null) {
149
+ if (seen.has(current)) return '[Circular]';
150
+ seen.add(current);
151
+ }
152
+ return current;
153
+ },
154
+ 4,
155
+ );
156
+ return serialized === undefined ? redactSensitiveText(`${value ?? ''}`) : serialized;
157
+ };
158
+
37
159
  // Define different colors for each level.
38
160
  // Colors make the log message more visible,
39
161
  // adding the ability to focus or ignore messages.
@@ -49,7 +171,7 @@ winston.addColors({
49
171
  });
50
172
 
51
173
  // Chose the aspect of your log customizing the log format.
52
- const format = (meta) =>
174
+ const loggerFormatFactory = (meta) =>
53
175
  winston.format.combine(
54
176
  // winston.format.errors({ stack: true }),
55
177
  // Add the message timestamp with the preferred format
@@ -61,25 +183,13 @@ const format = (meta) =>
61
183
  const splatKey = Symbol.for('splat');
62
184
  const splat = info[splatKey];
63
185
  const hasSplat = Array.isArray(splat) && splat.length > 0 && splat[0] !== undefined;
64
- let splatStr = '';
65
- if (hasSplat) {
66
- const seen = new WeakSet();
67
- splatStr = JSON.stringify(
68
- splat[0],
69
- (key, value) => {
70
- if (typeof value === 'function') return `[Function: ${value.name || 'anonymous'}]`;
71
- if (typeof value === 'object' && value !== null) {
72
- if (seen.has(value)) return '[Circular]';
73
- seen.add(value);
74
- }
75
- return value;
76
- },
77
- 4,
78
- );
79
- }
186
+ const splatStr = hasSplat ? serializeLogValue(splat[0]) : '';
187
+ const message = redactSensitiveText(
188
+ info.message instanceof Error ? info.message.stack || info.message.message : info.message,
189
+ );
80
190
  return `${`[${meta}]`.green} ${info.timestamp} ${info.level} ${
81
191
  hasSplat
82
- ? `${clearTerminalStringColor(info.message)}: ${colorize(splatStr, {
192
+ ? `${clearTerminalStringColor(message)}: ${colorize(splatStr, {
83
193
  colors: {
84
194
  StringKey: color.green,
85
195
  StringLiteral: color.magenta,
@@ -88,7 +198,7 @@ const format = (meta) =>
88
198
  NullLiteral: color.white,
89
199
  },
90
200
  })}`
91
- : info.message
201
+ : message
92
202
  }`;
93
203
  }),
94
204
  );
@@ -158,7 +268,7 @@ const loggerFactory = (
158
268
  defaultMeta: meta,
159
269
  level: level(logLevel),
160
270
  levels,
161
- format: format(meta),
271
+ format: loggerFormatFactory(meta),
162
272
  transports,
163
273
  // exceptionHandlers: [new winston.transports.File({ filename: 'exceptions.log' })],
164
274
  // rejectionHandlers: [new winston.transports.File({ filename: 'rejections.log' })],
@@ -226,4 +336,14 @@ const actionInitLog = () =>
226
336
  `,
227
337
  );
228
338
 
229
- export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCII, actionInitLog };
339
+ export {
340
+ REDACTED,
341
+ actionInitLog,
342
+ loggerFactory,
343
+ loggerFormatFactory,
344
+ loggerMiddleware,
345
+ redactSensitiveText,
346
+ serializeLogValue,
347
+ setUpInfo,
348
+ underpostASCII,
349
+ };