@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
@@ -6,7 +6,7 @@
6
6
  # Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
7
7
  # ---------------------------------------------------------------------------
8
8
  FROM rockylinux/rockylinux:9 AS builder
9
- ARG UNDERPOST_VERSION=3.3.0
9
+ ARG UNDERPOST_VERSION=3.3.76
10
10
  # Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
11
11
  # underpost's dependencies require >=24.15.0, so install the official binary.
12
12
  ARG NODE_VERSION=24.15.0
@@ -14,7 +14,7 @@ ENV NODE_ENV=production
14
14
 
15
15
  RUN set -eux; \
16
16
  # `sudo` is required because underpost's build steps shell out to
17
- # `sudo cp`/`sudo rm` (src/server/start.js); the build runs as root so sudo
17
+ # `sudo cp`/`sudo rm` (src/server/runtime/start.js); the build runs as root so sudo
18
18
  # is just a passthrough, but the binary must exist.
19
19
  dnf install -y git openssl tar xz sudo; \
20
20
  arch="$(uname -m)"; \
@@ -26,10 +26,22 @@ RUN set -eux; \
26
26
  curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz" \
27
27
  | tar -xJ -C /usr/local --strip-components=1; \
28
28
  node --version; npm --version; \
29
- npm install -g underpost@${UNDERPOST_VERSION}; \
30
29
  dnf clean all; rm -rf /var/cache/dnf; \
31
30
  npm cache clean --force
32
31
 
32
+
33
+ # The builder's own `underpost clone` calls below run on this same CLI, and the runtime stage
34
+ # inherits it through `COPY --from=builder /usr/local/`.
35
+ COPY underpost-cli.tgz /tmp/underpost-cli.tgz
36
+ RUN set -eux; \
37
+ npm install -g /tmp/underpost-cli.tgz --omit=dev; \
38
+ rm -f /tmp/underpost-cli.tgz; \
39
+ npm cache clean --force; \
40
+ underpost --version; \
41
+ # The staged package must be the pinned release: a drift here would ship a CLI the
42
+ # deployment manifests were not built against.
43
+ underpost --version | grep -Fq "${UNDERPOST_VERSION}"
44
+
33
45
  WORKDIR /home/dd
34
46
 
35
47
  # Comma-separated instance codes to provision (backup dir + optional saga).
@@ -38,7 +50,7 @@ WORKDIR /home/dd
38
50
  # `--build-arg INSTANCE_CODES=...`. Declared as an ARG (not a marker-wrapped
39
51
  # shell string) so the value is clean — a `/** … */` literal in the shell would
40
52
  # glob-expand in the `for` loop below.
41
- ARG INSTANCE_CODES="amethyst-strata-expansion,FOREST"
53
+ ARG INSTANCE_CODES="amethyst-strata-expansion,FOREST,TEST"
42
54
 
43
55
  RUN --mount=type=secret,id=github_username \
44
56
  # --mount=type=secret,id=github_token \
@@ -83,7 +95,7 @@ RUN --mount=type=secret,id=github_username \
83
95
  cd /home/dd/engine; \
84
96
  # --- install deps + env, then replay build-safe itc provisioning ----------
85
97
  npm install; \
86
- node bin env dd-cyberia production; \
98
+ node bin app load --env production --args deploy-id=dd-cyberia; \
87
99
  ( cd /home/dd/engine/hardhat && npm install --include=dev ); \
88
100
  # --- build the client bundle (assets are now in place) --------------------
89
101
  cd /home/dd/engine; \
@@ -136,11 +148,15 @@ COPY --from=builder /usr/local/ /usr/local/
136
148
  RUN dnf install -y libstdc++ git sudo && dnf clean all && rm -rf /var/cache/dnf && \
137
149
  useradd --create-home --home-dir /home/dd --shell /usr/sbin/nologin dd && \
138
150
  # The runtime runs as `dd`, but `underpost start --build` shells out to `sudo cp`/`sudo rm`
139
- # (src/server/start.js). Grant passwordless sudo so those succeed without a TTY/password.
151
+ # (src/server/runtime/start.js). Grant passwordless sudo so those succeed without a TTY/password.
140
152
  printf 'dd ALL=(ALL) NOPASSWD:ALL\n' > /etc/sudoers.d/dd && chmod 0440 /etc/sudoers.d/dd && \
141
- # underpost persists its global env at $(npm root -g)/underpost/.env; the
142
- # non-root runtime user must be able to write it (fixes EACCES on start).
143
- chown -R dd:dd /usr/local/lib/node_modules/underpost
153
+ # underpost persists its global env and container state under
154
+ # `$(npm root -g)/underpost` (getUnderpostRootPath). That path is a STORE directory, not
155
+ # the CLI package tree: the staged package installs under its own package name, and
156
+ # `underpost start --build` re-links the bin at the pulled checkout without moving the
157
+ # store (src/server/runtime/start.js#linkRuntimeCli). Create it here — the non-root
158
+ # runtime user cannot mkdir inside /usr/local itself (EACCES on the first state write).
159
+ mkdir -p "$(npm root -g)/underpost" && chown -R dd:dd "$(npm root -g)/underpost"
144
160
 
145
161
  # Copy ONLY the scrubbed runtime tree — no .git, no token, no caches.
146
162
  COPY --from=builder --chown=dd:dd /home/dd/engine /home/dd/engine
@@ -6,7 +6,7 @@
6
6
  # Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
7
7
  # ---------------------------------------------------------------------------
8
8
  FROM rockylinux/rockylinux:9 AS builder
9
- ARG UNDERPOST_VERSION=3.3.0
9
+ ARG UNDERPOST_VERSION=3.3.76
10
10
  # Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
11
11
  # underpost's dependencies require >=24.15.0, so install the official binary.
12
12
  ARG NODE_VERSION=24.15.0
@@ -14,7 +14,7 @@ ENV NODE_ENV=development
14
14
 
15
15
  RUN set -eux; \
16
16
  # `sudo` is required because underpost's build steps shell out to
17
- # `sudo cp`/`sudo rm` (src/server/start.js); the build runs as root so sudo
17
+ # `sudo cp`/`sudo rm` (src/server/runtime/start.js); the build runs as root so sudo
18
18
  # is just a passthrough, but the binary must exist.
19
19
  dnf install -y git openssl tar xz sudo; \
20
20
  arch="$(uname -m)"; \
@@ -26,10 +26,22 @@ RUN set -eux; \
26
26
  curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz" \
27
27
  | tar -xJ -C /usr/local --strip-components=1; \
28
28
  node --version; npm --version; \
29
- npm install -g underpost@${UNDERPOST_VERSION}; \
30
29
  dnf clean all; rm -rf /var/cache/dnf; \
31
30
  npm cache clean --force
32
31
 
32
+
33
+ # The builder's own `underpost clone` calls below run on this same CLI, and the runtime stage
34
+ # inherits it through `COPY --from=builder /usr/local/`.
35
+ COPY underpost-cli.tgz /tmp/underpost-cli.tgz
36
+ RUN set -eux; \
37
+ npm install -g /tmp/underpost-cli.tgz --omit=dev; \
38
+ rm -f /tmp/underpost-cli.tgz; \
39
+ npm cache clean --force; \
40
+ underpost --version; \
41
+ # The staged package must be the pinned release: a drift here would ship a CLI the
42
+ # deployment manifests were not built against.
43
+ underpost --version | grep -Fq "${UNDERPOST_VERSION}"
44
+
33
45
  WORKDIR /home/dd
34
46
 
35
47
  # Comma-separated instance codes to provision (backup dir + optional saga).
@@ -38,7 +50,7 @@ WORKDIR /home/dd
38
50
  # `--build-arg INSTANCE_CODES=...`. Declared as an ARG (not a marker-wrapped
39
51
  # shell string) so the value is clean — a `/** … */` literal in the shell would
40
52
  # glob-expand in the `for` loop below.
41
- ARG INSTANCE_CODES="amethyst-strata-expansion,FOREST"
53
+ ARG INSTANCE_CODES="amethyst-strata-expansion,FOREST,TEST"
42
54
 
43
55
  RUN --mount=type=secret,id=github_username \
44
56
  # --mount=type=secret,id=github_token \
@@ -83,7 +95,7 @@ RUN --mount=type=secret,id=github_username \
83
95
  cd /home/dd/engine; \
84
96
  # --- install deps + env, then replay build-safe itc provisioning ----------
85
97
  npm install; \
86
- node bin env dd-cyberia development; \
98
+ node bin app load --env development --args deploy-id=dd-cyberia; \
87
99
  ( cd /home/dd/engine/hardhat && npm install --include=dev ); \
88
100
  # --- build the client bundle (assets are now in place) --------------------
89
101
  cd /home/dd/engine; \
@@ -136,11 +148,15 @@ COPY --from=builder /usr/local/ /usr/local/
136
148
  RUN dnf install -y libstdc++ git sudo && dnf clean all && rm -rf /var/cache/dnf && \
137
149
  useradd --create-home --home-dir /home/dd --shell /usr/sbin/nologin dd && \
138
150
  # The runtime runs as `dd`, but `underpost start --build` shells out to `sudo cp`/`sudo rm`
139
- # (src/server/start.js). Grant passwordless sudo so those succeed without a TTY/password.
151
+ # (src/server/runtime/start.js). Grant passwordless sudo so those succeed without a TTY/password.
140
152
  printf 'dd ALL=(ALL) NOPASSWD:ALL\n' > /etc/sudoers.d/dd && chmod 0440 /etc/sudoers.d/dd && \
141
- # underpost persists its global env at $(npm root -g)/underpost/.env; the
142
- # non-root runtime user must be able to write it (fixes EACCES on start).
143
- chown -R dd:dd /usr/local/lib/node_modules/underpost
153
+ # underpost persists its global env and container state under
154
+ # `$(npm root -g)/underpost` (getUnderpostRootPath). That path is a STORE directory, not
155
+ # the CLI package tree: the staged package installs under its own package name, and
156
+ # `underpost start --build` re-links the bin at the pulled checkout without moving the
157
+ # store (src/server/runtime/start.js#linkRuntimeCli). Create it here — the non-root
158
+ # runtime user cannot mkdir inside /usr/local itself (EACCES on the first state write).
159
+ mkdir -p "$(npm root -g)/underpost" && chown -R dd:dd "$(npm root -g)/underpost"
144
160
 
145
161
  # Copy ONLY the scrubbed runtime tree — no .git, no token, no caches.
146
162
  COPY --from=builder --chown=dd:dd /home/dd/engine /home/dd/engine
@@ -6,7 +6,7 @@
6
6
  # Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
7
7
  # ---------------------------------------------------------------------------
8
8
  FROM rockylinux/rockylinux:9 AS builder
9
- ARG UNDERPOST_VERSION=3.3.0
9
+ ARG UNDERPOST_VERSION=3.3.76
10
10
  # Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
11
11
  # underpost's dependencies require >=24.15.0, so install the official binary.
12
12
  ARG NODE_VERSION=24.15.0
@@ -14,7 +14,7 @@ ENV NODE_ENV=development
14
14
 
15
15
  RUN set -eux; \
16
16
  # `sudo` is required because underpost's build steps shell out to
17
- # `sudo cp`/`sudo rm` (src/server/start.js); the build runs as root so sudo
17
+ # `sudo cp`/`sudo rm` (src/server/runtime/start.js); the build runs as root so sudo
18
18
  # is just a passthrough, but the binary must exist.
19
19
  dnf install -y git openssl tar xz sudo; \
20
20
  arch="$(uname -m)"; \
@@ -71,8 +71,8 @@ RUN --mount=type=secret,id=github_token \
71
71
  \
72
72
  # --- install deps + env, then replay build-safe itc provisioning ----------
73
73
  npm install; \
74
- node bin env dd-cyberia development; \
75
- node bin fs --pull --recursive --deploy-id dd-cyberia --storage-file-path './engine-private/conf/dd-cyberia/storage.engine-cyberia.json'; \
74
+ node bin app load --env development --args deploy-id=dd-cyberia; \
75
+ node bin fs --pull --tracked --deploy-id dd-cyberia --storage-id engine-cyberia; \
76
76
  ( cd /home/dd/engine/hardhat && npm install --include=dev ); \
77
77
  ( cd /home/dd/engine && underpost clone underpostnet/cyberia-server ); \
78
78
  \
@@ -140,7 +140,7 @@ COPY --from=builder /usr/local/ /usr/local/
140
140
  RUN dnf install -y libstdc++ git sudo && dnf clean all && rm -rf /var/cache/dnf && \
141
141
  useradd --create-home --home-dir /home/dd --shell /usr/sbin/nologin dd && \
142
142
  # The runtime runs as `dd`, but `underpost start --build` shells out to `sudo cp`/`sudo rm`
143
- # (src/server/start.js). Grant passwordless sudo so those succeed without a TTY/password.
143
+ # (src/server/runtime/start.js). Grant passwordless sudo so those succeed without a TTY/password.
144
144
  printf 'dd ALL=(ALL) NOPASSWD:ALL\n' > /etc/sudoers.d/dd && chmod 0440 /etc/sudoers.d/dd && \
145
145
  # underpost persists its global env at $(npm root -g)/underpost/.env; the
146
146
  # non-root runtime user must be able to write it (fixes EACCES on start).
@@ -43,25 +43,37 @@ VALKEY_PORT=6379
43
43
  # cyberia-server-* -> stable engine gateway for HTTP and the raw engine runtime
44
44
  # for gRPC. The public engine-cyberia name belongs to nginx, avoiding ambiguous
45
45
  # Docker DNS while keeping one stable HTTP endpoint for every module.
46
- ENGINE_API_BASE_URL=http://engine-cyberia
47
- ENGINE_GRPC_ADDRESS=engine-cyberia-runtime:50051
46
+ CYBERIA_DATA_SERVER_URL=http://engine-cyberia
47
+ CYBERIA_DATA_SERVER_GRPC=engine-cyberia-runtime:50051
48
48
 
49
49
  # Client-visible Content Authority origin, forwarded to browser/Raylib clients
50
50
  # for every engine-cyberia content/asset/metadata request. Host-reachable
51
51
  # (Docker publishes the raw engine runtime on host :4005). Unlike the internal
52
- # ENGINE_API_BASE_URL, this value is consumed outside the Compose network:
52
+ # CYBERIA_DATA_SERVER_URL, this value is consumed outside the Compose network:
53
53
  # the two responsibilities must never overwrite each other.
54
54
  ENGINE_PUBLIC_URL=http://localhost:4005
55
55
  ENGINE_GRPC_RELOAD_INTERVAL_SEC=300
56
56
 
57
- # --- Browser-facing client runtime config (injected by docker-driver.py) -----
57
+ # Shared secret between the engine and every game server. It guards the server
58
+ # registry report (server -> engine) and the hot-reload trigger (engine ->
59
+ # server). Unset disables both: a server then stays out of the public list.
60
+ CYBERIA_SERVER_API_KEY=change_me_dev_server_api_key
61
+
62
+ # Public origin of the server gateway. Each server reports this origin plus its
63
+ # own sub-path, which is the URL a client dials.
64
+ CYBERIA_SERVER_PUBLIC_ORIGIN=http://localhost:8081
65
+
66
+ # --- Browser-facing client runtime config (injected by wasm-driver.py) -----
58
67
  # The single WASM bundle resolves its instance from the URL sub-path and builds
59
68
  # its endpoints from these origins. HTTP client/API traffic uses nginx on :80;
60
69
  # WebSocket traffic uses the dedicated multi-path server gateway on :8081.
61
70
  # http://localhost/ -> default, ws://localhost:8081/ws
62
71
  # http://localhost/FOREST -> FOREST, ws://localhost:8081/FOREST/ws
63
72
  CYBERIA_WS_ORIGIN=ws://localhost:8081
64
- CYBERIA_ENGINE_API_ORIGIN=http://localhost
73
+ # The browser's own route to the Data Server, through nginx on :80. Distinct from the internal
74
+ # CYBERIA_DATA_SERVER_URL above: both name a Data Server origin, but from opposite sides of the
75
+ # Compose network, and one file cannot hold two values under one name.
76
+ CYBERIA_CLIENT_DATA_SERVER_URL=http://localhost
65
77
  CYBERIA_DEFAULT_INSTANCE=amethyst-strata-expansion
66
78
 
67
79
  # cyberia-server logging. This is the dev stack, so default to DEBUG. Set
@@ -135,7 +135,7 @@ services:
135
135
  # server starts but rejects connections until seeded). Serves REST/WS on 4005
136
136
  # and the engine gRPC data service on 50051.
137
137
  engine-cyberia-runtime:
138
- image: ${ENGINE_CYBERIA_IMAGE:-underpost/engine-cyberia-dev}:${ENGINE_CYBERIA_TAG:-v3.3.0}
138
+ image: ${ENGINE_CYBERIA_IMAGE:-underpost/engine-cyberia-dev}:${ENGINE_CYBERIA_TAG:-v3.3.76}
139
139
  container_name: dd-cyberia-engine
140
140
  command:
141
141
  - /bin/sh
@@ -190,14 +190,16 @@ services:
190
190
  # gateway on host port 8081, so one port can route every instance path.
191
191
 
192
192
  cyberia-server-runtime:
193
- image: ${CYBERIA_SERVER_IMAGE:-underpost/cyberia-server-dev}:${CYBERIA_SERVER_TAG:-v3.3.0}
193
+ image: ${CYBERIA_SERVER_IMAGE:-underpost/cyberia-server-dev}:${CYBERIA_SERVER_TAG:-v3.3.76}
194
194
  container_name: dd-cyberia-server
195
195
  environment:
196
196
  INSTANCE_CODE: amethyst-strata-expansion
197
197
  CYBERIA_BASE_PATH: /
198
- ENGINE_API_BASE_URL: ${ENGINE_API_BASE_URL:-http://engine-cyberia}
198
+ CYBERIA_PUBLIC_URL: ${CYBERIA_SERVER_PUBLIC_ORIGIN:-http://localhost:8081}
199
+ CYBERIA_SERVER_API_KEY: ${CYBERIA_SERVER_API_KEY:-}
200
+ CYBERIA_DATA_SERVER_URL: ${CYBERIA_DATA_SERVER_URL:-http://engine-cyberia}
199
201
  ENGINE_PUBLIC_URL: ${ENGINE_PUBLIC_URL:-http://localhost:4005}
200
- ENGINE_GRPC_ADDRESS: ${ENGINE_GRPC_ADDRESS:-engine-cyberia-runtime:50051}
202
+ CYBERIA_DATA_SERVER_GRPC: ${CYBERIA_DATA_SERVER_GRPC:-engine-cyberia-runtime:50051}
201
203
  ENGINE_GRPC_RELOAD_INTERVAL_SEC: ${ENGINE_GRPC_RELOAD_INTERVAL_SEC:-300}
202
204
  STATIC_DIR: ${CYBERIA_SERVER_STATIC_DIR:-/home/dd/engine/cyberia-server/public}
203
205
  APP_ENV: ${CYBERIA_SERVER_APP_ENV:-development}
@@ -226,14 +228,16 @@ services:
226
228
  restart: unless-stopped
227
229
 
228
230
  cyberia-server-forest:
229
- image: ${CYBERIA_SERVER_IMAGE:-underpost/cyberia-server-dev}:${CYBERIA_SERVER_TAG:-v3.3.0}
231
+ image: ${CYBERIA_SERVER_IMAGE:-underpost/cyberia-server-dev}:${CYBERIA_SERVER_TAG:-v3.3.76}
230
232
  container_name: dd-cyberia-server-forest
231
233
  environment:
232
234
  INSTANCE_CODE: FOREST
233
235
  CYBERIA_BASE_PATH: /FOREST
234
- ENGINE_API_BASE_URL: ${ENGINE_API_BASE_URL:-http://engine-cyberia}
236
+ CYBERIA_PUBLIC_URL: ${CYBERIA_SERVER_PUBLIC_ORIGIN:-http://localhost:8081}/FOREST
237
+ CYBERIA_SERVER_API_KEY: ${CYBERIA_SERVER_API_KEY:-}
238
+ CYBERIA_DATA_SERVER_URL: ${CYBERIA_DATA_SERVER_URL:-http://engine-cyberia}
235
239
  ENGINE_PUBLIC_URL: ${ENGINE_PUBLIC_URL:-http://localhost:4005}
236
- ENGINE_GRPC_ADDRESS: ${ENGINE_GRPC_ADDRESS:-engine-cyberia-runtime:50051}
240
+ CYBERIA_DATA_SERVER_GRPC: ${CYBERIA_DATA_SERVER_GRPC:-engine-cyberia-runtime:50051}
237
241
  ENGINE_GRPC_RELOAD_INTERVAL_SEC: ${ENGINE_GRPC_RELOAD_INTERVAL_SEC:-300}
238
242
  STATIC_DIR: ${CYBERIA_SERVER_STATIC_DIR:-/home/dd/engine/cyberia-server/public}
239
243
  APP_ENV: ${CYBERIA_SERVER_APP_ENV:-development}
@@ -262,14 +266,16 @@ services:
262
266
  restart: unless-stopped
263
267
 
264
268
  cyberia-server-test:
265
- image: ${CYBERIA_SERVER_IMAGE:-underpost/cyberia-server-dev}:${CYBERIA_SERVER_TAG:-v3.3.0}
269
+ image: ${CYBERIA_SERVER_IMAGE:-underpost/cyberia-server-dev}:${CYBERIA_SERVER_TAG:-v3.3.76}
266
270
  container_name: dd-cyberia-server-test
267
271
  environment:
268
272
  INSTANCE_CODE: TEST
269
273
  CYBERIA_BASE_PATH: /TEST
270
- ENGINE_API_BASE_URL: ${ENGINE_API_BASE_URL:-http://engine-cyberia}
274
+ CYBERIA_PUBLIC_URL: ${CYBERIA_SERVER_PUBLIC_ORIGIN:-http://localhost:8081}/TEST
275
+ CYBERIA_SERVER_API_KEY: ${CYBERIA_SERVER_API_KEY:-}
276
+ CYBERIA_DATA_SERVER_URL: ${CYBERIA_DATA_SERVER_URL:-http://engine-cyberia}
271
277
  ENGINE_PUBLIC_URL: ${ENGINE_PUBLIC_URL:-http://localhost:4005}
272
- ENGINE_GRPC_ADDRESS: ${ENGINE_GRPC_ADDRESS:-engine-cyberia-runtime:50051}
278
+ CYBERIA_DATA_SERVER_GRPC: ${CYBERIA_DATA_SERVER_GRPC:-engine-cyberia-runtime:50051}
273
279
  ENGINE_GRPC_RELOAD_INTERVAL_SEC: ${ENGINE_GRPC_RELOAD_INTERVAL_SEC:-300}
274
280
  STATIC_DIR: ${CYBERIA_SERVER_STATIC_DIR:-/home/dd/engine/cyberia-server/public}
275
281
  APP_ENV: ${CYBERIA_SERVER_APP_ENV:-development}
@@ -299,7 +305,7 @@ services:
299
305
 
300
306
  # === Tier 4: presentation, one per variant ===============================
301
307
  # One WASM bundle serves every variant; the instance is resolved from the URL
302
- # sub-path (docker-driver injects CYBERIA_BASE_PATH / _WS_ORIGIN /
308
+ # sub-path (wasm-driver injects CYBERIA_BASE_PATH / _WS_ORIGIN /
303
309
  # _ENGINE_API_ORIGIN / _DEFAULT_INSTANCE). Each client waits ONLY for its own
304
310
  # server, so the three
305
311
  # server->client pipelines advance independently (in parallel) once the shared
@@ -309,7 +315,7 @@ services:
309
315
  # cyberia-server-test -> cyberia-client-test
310
316
 
311
317
  cyberia-client-runtime:
312
- image: ${CYBERIA_CLIENT_IMAGE:-underpost/cyberia-client-dev}:${CYBERIA_CLIENT_TAG:-v3.3.0}
318
+ image: ${CYBERIA_CLIENT_IMAGE:-underpost/cyberia-client-dev}:${CYBERIA_CLIENT_TAG:-v3.3.76}
313
319
  container_name: dd-cyberia-client
314
320
  environment:
315
321
  CYBERIA_PORT: '8081'
@@ -317,7 +323,7 @@ services:
317
323
  CYBERIA_BASE_PATH: /
318
324
  CYBERIA_DEFAULT_INSTANCE: ${CYBERIA_DEFAULT_INSTANCE:-amethyst-strata-expansion}
319
325
  CYBERIA_WS_ORIGIN: ${CYBERIA_WS_ORIGIN:-ws://localhost:8081}
320
- CYBERIA_ENGINE_API_ORIGIN: ${CYBERIA_ENGINE_API_ORIGIN:-http://localhost}
326
+ CYBERIA_DATA_SERVER_URL: ${CYBERIA_CLIENT_DATA_SERVER_URL:-http://localhost}
321
327
  networks:
322
328
  - dd-cyberia-internal
323
329
  expose:
@@ -334,7 +340,7 @@ services:
334
340
  restart: unless-stopped
335
341
 
336
342
  cyberia-client-forest:
337
- image: ${CYBERIA_CLIENT_IMAGE:-underpost/cyberia-client-dev}:${CYBERIA_CLIENT_TAG:-v3.3.0}
343
+ image: ${CYBERIA_CLIENT_IMAGE:-underpost/cyberia-client-dev}:${CYBERIA_CLIENT_TAG:-v3.3.76}
338
344
  container_name: dd-cyberia-client-forest
339
345
  environment:
340
346
  CYBERIA_PORT: '8081'
@@ -342,7 +348,7 @@ services:
342
348
  CYBERIA_BASE_PATH: /FOREST
343
349
  CYBERIA_DEFAULT_INSTANCE: ${CYBERIA_DEFAULT_INSTANCE:-amethyst-strata-expansion}
344
350
  CYBERIA_WS_ORIGIN: ${CYBERIA_WS_ORIGIN:-ws://localhost:8081}
345
- CYBERIA_ENGINE_API_ORIGIN: ${CYBERIA_ENGINE_API_ORIGIN:-http://localhost}
351
+ CYBERIA_DATA_SERVER_URL: ${CYBERIA_CLIENT_DATA_SERVER_URL:-http://localhost}
346
352
  networks:
347
353
  - dd-cyberia-internal
348
354
  expose:
@@ -359,7 +365,7 @@ services:
359
365
  restart: unless-stopped
360
366
 
361
367
  cyberia-client-test:
362
- image: ${CYBERIA_CLIENT_IMAGE:-underpost/cyberia-client-dev}:${CYBERIA_CLIENT_TAG:-v3.3.0}
368
+ image: ${CYBERIA_CLIENT_IMAGE:-underpost/cyberia-client-dev}:${CYBERIA_CLIENT_TAG:-v3.3.76}
363
369
  container_name: dd-cyberia-client-test
364
370
  environment:
365
371
  CYBERIA_PORT: '8081'
@@ -367,7 +373,7 @@ services:
367
373
  CYBERIA_BASE_PATH: /TEST
368
374
  CYBERIA_DEFAULT_INSTANCE: ${CYBERIA_DEFAULT_INSTANCE:-amethyst-strata-expansion}
369
375
  CYBERIA_WS_ORIGIN: ${CYBERIA_WS_ORIGIN:-ws://localhost:8081}
370
- CYBERIA_ENGINE_API_ORIGIN: ${CYBERIA_ENGINE_API_ORIGIN:-http://localhost}
376
+ CYBERIA_DATA_SERVER_URL: ${CYBERIA_CLIENT_DATA_SERVER_URL:-http://localhost}
371
377
  networks:
372
378
  - dd-cyberia-internal
373
379
  expose:
@@ -12,18 +12,19 @@ import swaggerUi from 'swagger-ui-express';
12
12
  import compression from 'compression';
13
13
  import { createServer } from 'http';
14
14
 
15
- import { loggerFactory, loggerMiddleware } from '../../server/logger.js';
15
+ import { loggerFactory, loggerMiddleware } from '../../server/ops/logger.js';
16
16
  import { getCapVariableName, newInstance } from '../../client/components/core/CommonJs.js';
17
17
  import { MailerProvider } from '../../mailer/MailerProvider.js';
18
18
  import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
19
- import { createPeerServer } from '../../server/peer.js';
20
- import { createValkeyConnection } from '../../server/valkey.js';
21
- import { applySecurity, authMiddlewareFactory } from '../../server/auth.js';
19
+ import { createPeerServer } from '../../server/network/peer.js';
20
+ import { createValkeyConnection } from '../../db/valkey/Valkey.js';
21
+ import { applySecurity, authMiddlewareFactory } from '../../server/security/auth.js';
22
22
  import { ssrMiddlewareFactory } from '../../client-builder/ssr.js';
23
23
  import { buildSwaggerUiOptions } from '../../client-builder/client-build-docs.js';
24
24
 
25
- import { shellExec } from '../../server/process.js';
26
- import { devProxyHostFactory, isDevProxyContext, isTlsDevProxy } from '../../server/conf.js';
25
+ import { shellExec } from '../../server/runtime/process.js';
26
+ import { devProxyHostFactory, isDevProxyContext, isTlsDevProxy } from '../../server/runtime/conf.js';
27
+ import { metricsPathFactory } from '../../server/ops/monitoring.js';
27
28
 
28
29
  import Underpost from '../../index.js';
29
30
 
@@ -113,8 +114,9 @@ class ExpressService {
113
114
  return next();
114
115
  });
115
116
 
116
- // Metrics endpoint
117
- app.get(`${path === '/' ? '' : path}/metrics`, async (req, res) => {
117
+ // Metrics endpoint. The route is shared with the Prometheus scrape config
118
+ // so a target can never point at a path this server does not serve.
119
+ app.get(metricsPathFactory(path), async (req, res) => {
118
120
  res.set('Content-Type', promRegister.contentType);
119
121
  return res.end(await promRegister.metrics());
120
122
  });
@@ -163,19 +165,22 @@ class ExpressService {
163
165
  // Create HTTP server for regular instances (required for WebSockets)
164
166
  const server = createServer({}, app);
165
167
 
166
- if (!apiBaseHost) {
167
- // Swagger path definition
168
- const swaggerJsonPath = `./public/${host}${path === '/' ? path : `${path}/`}swagger-output.json`;
169
- const swaggerPath = `${path === '/' ? `/api-docs` : `${path}/api-docs`}`;
170
-
171
- // Flag swagger requests before security middleware
172
- if (fs.existsSync(swaggerJsonPath)) {
173
- app.use(swaggerPath, (req, res, next) => {
174
- res.locals.isSwagger = true;
175
- next();
176
- });
177
- }
168
+ // Swagger path definition. The UI is served by every instance that renders the
169
+ // client, so a split client/API deployment keeps `api-docs` same-origin with the
170
+ // page that frames it.
171
+ const swaggerJsonPath = `./public/${host}${path === '/' ? path : `${path}/`}swagger-output.json`;
172
+ const swaggerPath = `${path === '/' ? `/api-docs` : `${path}/api-docs`}`;
173
+ const swaggerEnabled = fs.existsSync(swaggerJsonPath);
174
+
175
+ // Flag swagger requests before security middleware
176
+ if (swaggerEnabled) {
177
+ app.use(swaggerPath, (req, res, next) => {
178
+ res.locals.isSwagger = true;
179
+ next();
180
+ });
181
+ }
178
182
 
183
+ if (!apiBaseHost) {
179
184
  // Security and CORS — must run before swagger-ui so CSP headers are included in swagger responses
180
185
  if (process.env.NODE_ENV === 'development' && useLocalSsl)
181
186
  origins = origins.map((origin) => origin.replace('http', 'https'));
@@ -184,13 +189,6 @@ class ExpressService {
184
189
  origin: origins,
185
190
  });
186
191
 
187
- // Swagger UI setup (after security middleware so responses carry correct CSP headers)
188
- if (fs.existsSync(swaggerJsonPath)) {
189
- const swaggerDoc = JSON.parse(fs.readFileSync(swaggerJsonPath, 'utf8'));
190
- const swaggerUiOptions = await buildSwaggerUiOptions();
191
- app.use(swaggerPath, swaggerUi.serve, swaggerUi.setup(swaggerDoc, swaggerUiOptions));
192
- }
193
-
194
192
  // Database and Valkey connections
195
193
  if (db && apis) await DataBaseProviderService.load({ apis, host, path, db });
196
194
 
@@ -261,6 +259,13 @@ class ExpressService {
261
259
  }
262
260
  }
263
261
 
262
+ // Swagger UI setup (after security middleware so responses carry correct CSP headers)
263
+ if (swaggerEnabled) {
264
+ const swaggerDoc = JSON.parse(fs.readFileSync(swaggerJsonPath, 'utf8'));
265
+ const swaggerUiOptions = await buildSwaggerUiOptions();
266
+ app.use(swaggerPath, swaggerUi.serve, swaggerUi.setup(swaggerDoc, swaggerUiOptions));
267
+ }
268
+
264
269
  // SSR middleware loading
265
270
  const ssr = await ssrMiddlewareFactory({ app, directory, rootHostPath, path });
266
271
  for (const [_, ssrMiddleware] of Object.entries(ssr)) app.use(ssrMiddleware);
@@ -6,8 +6,9 @@
6
6
  */
7
7
 
8
8
  import fs from 'fs-extra';
9
- import { getRootDirectory, shellCd, shellExec } from '../../server/process.js';
10
- import { loggerFactory } from '../../server/logger.js';
9
+ import { getRootDirectory, shellCd, shellExec } from '../../server/runtime/process.js';
10
+ import { loggerFactory } from '../../server/ops/logger.js';
11
+ import Underpost from '../../index.js';
11
12
 
12
13
  const logger = loggerFactory(import.meta);
13
14
 
@@ -71,12 +72,8 @@ class LamppService {
71
72
  * @memberof LamppService
72
73
  */
73
74
  async initService(options = { daemon: false }) {
74
- let cmd;
75
-
76
- // 1. Write the current virtual host router configuration
77
75
  fs.writeFileSync(`/opt/lampp/etc/extra/httpd-vhosts.conf`, this.router || '', 'utf8');
78
76
 
79
- // 2. Ensure the vhosts file is included in the main httpd.conf
80
77
  const httpdConfPath = `/opt/lampp/etc/httpd.conf`;
81
78
  fs.writeFileSync(
82
79
  httpdConfPath,
@@ -86,12 +83,9 @@ class LamppService {
86
83
  'utf8',
87
84
  );
88
85
 
89
- // 3. Stop the service before making port changes
90
- cmd = `sudo /opt/lampp/lampp stop`;
91
- shellExec(cmd);
86
+ shellExec(`sudo /opt/lampp/lampp stop`);
92
87
 
93
- // 4. Comment out default port Listen directives (80 and 443) to prevent conflicts
94
- // Modify httpd.conf (port 80)
88
+ // Every vhost declares its own Listen, so the stock 80/443 directives would double-bind.
95
89
  if (!fs.readFileSync(httpdConfPath, 'utf8').match(/# Listen 80/))
96
90
  fs.writeFileSync(
97
91
  httpdConfPath,
@@ -99,7 +93,6 @@ class LamppService {
99
93
  'utf8',
100
94
  );
101
95
 
102
- // Modify httpd-ssl.conf (port 443)
103
96
  const httpdSslConfPath = `/opt/lampp/etc/extra/httpd-ssl.conf`;
104
97
  if (fs.existsSync(httpdSslConfPath) && !fs.readFileSync(httpdSslConfPath, 'utf8').match(/# Listen 443/))
105
98
  fs.writeFileSync(
@@ -108,7 +101,8 @@ class LamppService {
108
101
  'utf8',
109
102
  );
110
103
 
111
- // 5. Modify the lampp startup script to bypass port checking for 80 and 443
104
+ // The startup script aborts when 80/443 are already held by the ingress proxy; short-circuit
105
+ // its probes so the service still comes up behind one.
112
106
  const lamppScriptPath = `/opt/lampp/lampp`;
113
107
  if (!fs.readFileSync(lamppScriptPath, 'utf8').match(/testport 443 && false/))
114
108
  fs.writeFileSync(
@@ -123,9 +117,7 @@ class LamppService {
123
117
  'utf8',
124
118
  );
125
119
 
126
- // 6. Start the service
127
- cmd = `sudo /opt/lampp/lampp start`;
128
- shellExec(cmd);
120
+ shellExec(`sudo /opt/lampp/lampp start`);
129
121
  }
130
122
 
131
123
  /**
@@ -217,13 +209,15 @@ class LamppService {
217
209
  * @param {string} options.path - The base path for error documents (e.g., '/app').
218
210
  * @param {string} [options.directory] - Optional absolute path to the document root.
219
211
  * @param {string} [options.rootHostPath] - Relative path from the root directory to the document root, used if `directory` is not provided.
212
+ * @param {string} [options.repository] - Repository backing the document root. Each conf route
213
+ * declares its own, so one host serves as many repositories as it has routes.
220
214
  * @param {boolean} [options.redirect] - If true, enables RewriteEngine for redirection.
221
215
  * @param {string} [options.redirectTarget] - The target URL for redirection.
222
216
  * @param {boolean} [options.resetRouter] - If true, clears the existing router configuration before appending the new one.
223
217
  * @returns {{disabled: boolean}} An object indicating if the service is disabled.
224
218
  * @memberof LamppService
225
219
  */
226
- createApp({ port, host, path, directory, rootHostPath, redirect, redirectTarget, resetRouter }) {
220
+ createApp({ port, host, path, directory, rootHostPath, repository, redirect, redirectTarget, resetRouter }) {
227
221
  if (!this.enabled()) return { disabled: true };
228
222
 
229
223
  if (!this.ports.includes(port)) this.ports.push(port);
@@ -231,7 +225,17 @@ class LamppService {
231
225
 
232
226
  const documentRoot = directory ? directory : `${getRootDirectory()}${rootHostPath}`;
233
227
 
234
- // Append the new VirtualHost configuration
228
+ if (repository) {
229
+ const { accessible } = Underpost.repo.provisionSiteRoot({ host, siteRoot: documentRoot, repository });
230
+ // The checkout keeps its `.git` so the backup pipeline can commit and push it back; the
231
+ // vhost below denies it over HTTP.
232
+ if (accessible) Underpost.repo.initLocalRepo({ path: documentRoot, origin: repository });
233
+ // The vhost is still emitted, so the host answers rather than vanishing from the router —
234
+ // but Apache cannot stat a DocumentRoot that was never created and turns every request into
235
+ // a blanket 403. Named here, because that 403 carries nothing pointing back at this step.
236
+ else logger.error(`${host}: ${documentRoot} not provisioned — this vhost will answer 403 until it is`);
237
+ }
238
+
235
239
  this.appendRouter(`
236
240
  Listen ${port}
237
241
 
@@ -305,55 +309,3 @@ Listen ${port}
305
309
  const Lampp = new LamppService();
306
310
 
307
311
  export { Lampp };
308
-
309
- // -- helper info --
310
-
311
- // ERR too many redirects:
312
- // Check: SELECT * FROM database.wp_options where option_name = 'siteurl' or option_name = 'home';
313
- // Check: wp-config.php
314
- // if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
315
- // $_SERVER['HTTPS'] = 'on';
316
- // }
317
- // For plugins:
318
- // define( 'FS_METHOD', 'direct' );
319
-
320
- // ErrorDocument 404 /custom_404.html
321
- // ErrorDocument 500 /custom_50x.html
322
- // ErrorDocument 502 /custom_50x.html
323
- // ErrorDocument 503 /custom_50x.html
324
- // ErrorDocument 504 /custom_50x.html
325
-
326
- // Respond When Error Pages are Directly Requested
327
-
328
- // <Files "custom_404.html">
329
- // <If "-z %{ENV:REDIRECT_STATUS}">
330
- // RedirectMatch 404 ^/custom_404.html$
331
- // </If>
332
- // </Files>
333
-
334
- // <Files "custom_50x.html">
335
- // <If "-z %{ENV:REDIRECT_STATUS}">
336
- // RedirectMatch 404 ^/custom_50x.html$
337
- // </If>
338
- // </Files>
339
-
340
- // Add www or https with htaccess rewrite
341
-
342
- // Options +FollowSymLinks
343
- // RewriteEngine On
344
- // RewriteCond %{HTTP_HOST} ^example.com [NC]
345
- // RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
346
-
347
- // Redirect http to https with htaccess rewrite
348
-
349
- // RewriteEngine On
350
- // RewriteCond %{SERVER_PORT} 80
351
- // RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
352
-
353
- // Redirect to HTTPS with www subdomain
354
-
355
- // RewriteEngine On
356
- // RewriteCond %{HTTPS} off [OR]
357
- // RewriteCond %{HTTP_HOST} ^www\. [NC]
358
- // RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
359
- // RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
@@ -9,7 +9,7 @@
9
9
 
10
10
  import fs from 'fs-extra';
11
11
  import path from 'path';
12
- import { loggerFactory } from '../../server/logger.js';
12
+ import { loggerFactory } from '../../server/ops/logger.js';
13
13
 
14
14
  const logger = loggerFactory(import.meta);
15
15