@underpostnet/cyberia 3.2.90 → 3.3.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +16 -0
  3. package/.github/workflows/coverall.cyberia.ci.yml +107 -0
  4. package/.github/workflows/cyberia-client.cd.yml +6 -18
  5. package/.github/workflows/cyberia-server.cd.yml +6 -18
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +6 -78
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +42 -21
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +2 -9
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +47 -0
  22. package/CHANGELOG.md +581 -2417
  23. package/CLI-HELP.md +416 -127
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +4 -4
  27. package/README.md +21 -1
  28. package/bin/build.js +70 -43
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +372 -135
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +372 -135
  33. package/compose.env +16 -0
  34. package/conf.js +93 -4
  35. package/deploy/cyberia-client/deploy.sh +47 -0
  36. package/deploy/cyberia-client/package.sh +18 -0
  37. package/deploy/cyberia-client/state.sh +14 -0
  38. package/deploy/cyberia-server/deploy.sh +47 -0
  39. package/deploy/cyberia-server/package.sh +18 -0
  40. package/deploy/cyberia-server/state.sh +14 -0
  41. package/deploy/dd-cyberia/deploy.sh +22 -0
  42. package/deploy/dd-cyberia/init.sh +55 -0
  43. package/deploy/dd-cyberia/package.sh +17 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +116 -0
  46. package/deploy/lib/github-actions-logging.sh +594 -0
  47. package/deploy/lib/host.sh +185 -0
  48. package/deploy/lib/state.sh +62 -0
  49. package/deploy/pwa-microservices-template/deploy.sh +45 -0
  50. package/deploy/release/deploy.sh +32 -0
  51. package/deployment.yaml +7 -2
  52. package/docker-compose.yml +31 -37
  53. package/examples/static-page/README.md +19 -19
  54. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  55. package/hardhat/hardhat.config.js +1 -6
  56. package/hardhat/package-lock.json +104 -43
  57. package/hardhat/package.json +3 -3
  58. package/manifests/alertmanager/deployment.yaml +81 -0
  59. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  60. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
  61. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
  62. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  63. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  64. package/manifests/grafana/deployment.yaml +26 -7
  65. package/manifests/grafana/kustomization.yaml +1 -0
  66. package/manifests/grafana/service.yaml +6 -1
  67. package/manifests/mariadb/pv.yaml +1 -0
  68. package/manifests/mongodb/statefulset.yaml +9 -2
  69. package/manifests/mysql/pv-pvc.yaml +14 -1
  70. package/manifests/postgresql/pv.yaml +12 -1
  71. package/manifests/postgresql/pvc.yaml +1 -0
  72. package/manifests/prometheus/deployment.yaml +18 -22
  73. package/package.json +83 -10
  74. package/scripts/audit-selinux.sh +64 -0
  75. package/scripts/event-monitor.sh +56 -0
  76. package/scripts/gpu-diag.sh +0 -0
  77. package/scripts/ip-info.sh +0 -0
  78. package/scripts/k3s-node-setup.sh +30 -14
  79. package/scripts/kubeadm-node-setup.sh +40 -31
  80. package/scripts/lxd-vm-setup.sh +0 -0
  81. package/scripts/maas-nat-firewalld.sh +0 -0
  82. package/scripts/maas-setup.sh +8 -8
  83. package/scripts/nat-iptables.sh +2 -0
  84. package/scripts/rhel-grpc-setup.sh +0 -0
  85. package/scripts/rocky-kickstart.sh +25 -9
  86. package/scripts/selinux-normalize.sh +907 -0
  87. package/scripts/shutdown-machine.sh +843 -0
  88. package/scripts/test-monitor.sh +3 -3
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +1 -1
  99. package/src/api/cyberia-action/cyberia-action.service.js +2 -2
  100. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
  101. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
  102. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
  103. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  104. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  105. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  106. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  107. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  108. package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
  109. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
  110. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
  111. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
  112. package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
  113. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
  114. package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
  115. package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
  116. package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
  117. package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
  118. package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
  119. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  120. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
  121. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  122. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
  123. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  124. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  125. package/src/api/cyberia-map/cyberia-map.service.js +2 -2
  126. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  127. package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
  128. package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
  129. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  130. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  131. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  132. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  133. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  134. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  135. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -29
  136. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  137. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  138. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  139. package/src/api/default/default.controller.js +1 -1
  140. package/src/api/default/default.router.js +1 -1
  141. package/src/api/default/default.service.js +2 -2
  142. package/src/api/document/document.controller.js +1 -1
  143. package/src/api/document/document.router.js +1 -1
  144. package/src/api/document/document.service.js +2 -2
  145. package/src/api/file/file.controller.js +1 -1
  146. package/src/api/file/file.router.js +1 -1
  147. package/src/api/file/file.service.js +2 -2
  148. package/src/api/instance/instance.controller.js +1 -1
  149. package/src/api/instance/instance.router.js +1 -1
  150. package/src/api/instance/instance.service.js +2 -2
  151. package/src/api/ipfs/ipfs.controller.js +1 -1
  152. package/src/api/ipfs/ipfs.router.js +2 -2
  153. package/src/api/ipfs/ipfs.service.js +2 -2
  154. package/src/api/object-layer/object-layer.controller.js +1 -1
  155. package/src/api/object-layer/object-layer.model.js +204 -3
  156. package/src/api/object-layer/object-layer.router.js +2 -2
  157. package/src/api/object-layer/object-layer.service.js +4 -17
  158. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  159. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  160. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  161. package/src/api/test/test.controller.js +1 -1
  162. package/src/api/test/test.service.js +1 -1
  163. package/src/api/user/guest.service.js +3 -3
  164. package/src/api/user/user.controller.js +1 -1
  165. package/src/api/user/user.router.js +2 -2
  166. package/src/api/user/user.service.js +4 -4
  167. package/src/api.js +5 -9
  168. package/src/cli/app.js +391 -0
  169. package/src/cli/baremetal.js +30 -36
  170. package/src/cli/client.js +306 -0
  171. package/src/cli/cloud-init.js +3 -3
  172. package/src/cli/cluster.js +242 -135
  173. package/src/cli/db.js +126 -67
  174. package/src/cli/deploy.js +158 -60
  175. package/src/cli/docker-compose.js +5 -5
  176. package/src/cli/domains.js +184 -0
  177. package/src/cli/dotenv-store.js +143 -0
  178. package/src/cli/event.js +2281 -0
  179. package/src/cli/fs.js +3 -3
  180. package/src/cli/host.js +672 -0
  181. package/src/cli/image.js +4 -7
  182. package/src/cli/index.js +426 -134
  183. package/src/cli/ipfs.js +34 -30
  184. package/src/cli/kickstart.js +1 -1
  185. package/src/cli/kubectl.js +218 -41
  186. package/src/cli/lxd.js +3 -3
  187. package/src/cli/monitor.js +1359 -26
  188. package/src/cli/package.js +90 -0
  189. package/src/cli/release.js +73 -34
  190. package/src/cli/repository.js +564 -367
  191. package/src/cli/run.js +362 -654
  192. package/src/cli/secrets.js +2158 -964
  193. package/src/cli/ssh.js +651 -331
  194. package/src/cli/state.js +394 -0
  195. package/src/cli/static.js +2 -2
  196. package/src/cli/system.js +26 -13
  197. package/src/cli/test.js +199 -125
  198. package/src/cli/vultr.js +623 -0
  199. package/src/cli/wireguard.js +2930 -0
  200. package/src/client/components/core/CalendarCore.js +53 -96
  201. package/src/client/components/core/Docs.js +258 -211
  202. package/src/client/components/core/FileExplorer.js +0 -21
  203. package/src/client/components/core/PanelForm.js +4 -4
  204. package/src/client/components/core/Repository.js +56 -0
  205. package/src/client/components/core/Translate.js +7 -0
  206. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  207. package/src/client/components/core/Wallet.js +0 -11
  208. package/src/client/components/core/Worker.js +7 -1
  209. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  210. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
  211. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
  212. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
  213. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  214. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
  215. package/src/client/components/default/AppShellDefault.js +1 -1
  216. package/src/client/components/default/SettingsDefault.js +2 -2
  217. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  218. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  219. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  220. package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
  221. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
  222. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
  223. package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
  224. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  225. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  226. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  227. package/src/client/public/default/android-chrome-144x144.png +0 -0
  228. package/src/client/public/default/android-chrome-192x192.png +0 -0
  229. package/src/client/public/default/android-chrome-256x256.png +0 -0
  230. package/src/client/public/default/android-chrome-36x36.png +0 -0
  231. package/src/client/public/default/android-chrome-384x384.png +0 -0
  232. package/src/client/public/default/android-chrome-48x48.png +0 -0
  233. package/src/client/public/default/android-chrome-512x512.png +0 -0
  234. package/src/client/public/default/android-chrome-72x72.png +0 -0
  235. package/src/client/public/default/android-chrome-96x96.png +0 -0
  236. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  237. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  238. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  239. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  240. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  241. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  242. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  243. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  244. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  245. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  246. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  247. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  248. package/src/client/public/default/apple-touch-icon.png +0 -0
  249. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  250. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  251. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  252. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  253. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  254. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  255. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  256. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  257. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  258. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  259. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  260. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  261. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  262. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  263. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  264. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  265. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  266. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  267. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  268. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  269. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  270. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  271. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  272. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  273. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  274. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  275. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  276. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  277. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  278. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  279. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  280. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  281. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  282. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  283. package/src/client/public/default/assets/background/white.jpg +0 -0
  284. package/src/client/public/default/browserconfig.xml +1 -1
  285. package/src/client/public/default/favicon-16x16.png +0 -0
  286. package/src/client/public/default/favicon-32x32.png +0 -0
  287. package/src/client/public/default/favicon-48x48.png +0 -0
  288. package/src/client/public/default/favicon.ico +0 -0
  289. package/src/client/public/default/manifest.webmanifest +5 -5
  290. package/src/client/public/default/mstile-144x144.png +0 -0
  291. package/src/client/public/default/mstile-150x150.png +0 -0
  292. package/src/client/public/default/mstile-310x150.png +0 -0
  293. package/src/client/public/default/mstile-310x310.png +0 -0
  294. package/src/client/public/default/mstile-70x70.png +0 -0
  295. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  296. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  297. package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
  298. package/src/client/services/object-layer/object-layer.management.js +4 -4
  299. package/src/client/ssr/RootDocument.js +1 -1
  300. package/src/client/ssr/body/404.js +1 -1
  301. package/src/client/ssr/body/500.js +1 -1
  302. package/src/client/ssr/body/CacheControl.js +1 -1
  303. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  304. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  305. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  306. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  307. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  308. package/src/client/ssr/head/Css.js +1 -1
  309. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  310. package/src/client/ssr/head/DefaultScripts.js +1 -1
  311. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  312. package/src/client/ssr/head/Microdata.js +1 -1
  313. package/src/client/ssr/head/Production.js +1 -1
  314. package/src/client/ssr/head/Pwa.js +1 -1
  315. package/src/client/ssr/head/PwaItemledger.js +1 -1
  316. package/src/client/ssr/head/Seo.js +1 -1
  317. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  318. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  319. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  320. package/src/client/ssr/views/Cyberia404.js +7 -5
  321. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  322. package/src/client/ssr/views/Maintenance.js +1 -1
  323. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  324. package/src/client/ssr/views/Test.js +1 -1
  325. package/src/client/sw/core.sw.js +20 -14
  326. package/src/client-builder/client-build-docs.js +61 -46
  327. package/src/client-builder/client-build-live.js +2 -2
  328. package/src/client-builder/client-build.js +58 -44
  329. package/src/client-builder/client-dev-server.js +3 -3
  330. package/src/client-builder/client-icons.js +2 -2
  331. package/src/client-builder/ssr.js +3 -3
  332. package/src/client.build.js +3 -6
  333. package/src/client.dev.js +3 -6
  334. package/src/db/DataBaseProvider.js +186 -3
  335. package/src/db/mariadb/MariaDB.js +3 -2
  336. package/src/db/mongo/MongoBootstrap.js +273 -101
  337. package/src/db/mongo/MongooseDB.js +11 -8
  338. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  339. package/src/grpc/cyberia/grpc-server.js +1 -1
  340. package/src/index.js +103 -23
  341. package/src/mailer/EmailRender.js +2 -2
  342. package/src/mailer/MailerInterceptor.js +87 -0
  343. package/src/mailer/MailerProvider.js +50 -6
  344. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
  345. package/src/projects/cyberia/besu-genesis-generator.js +3 -3
  346. package/src/projects/cyberia/catalog-cyberia.js +54 -6
  347. package/src/projects/cyberia/gemini-client.js +1 -1
  348. package/src/projects/cyberia/generate-saga.js +15 -24
  349. package/src/projects/cyberia/hot-reload-trigger.js +1 -1
  350. package/src/projects/cyberia/instance-data.js +22 -3
  351. package/src/projects/cyberia/ipfs-client.js +4 -4
  352. package/src/projects/cyberia/map-preview-generator.js +1 -1
  353. package/src/projects/cyberia/object-layer.js +12 -22
  354. package/src/projects/cyberia/semantic-layer-generator.js +1 -1
  355. package/src/projects/underpost/catalog-underpost.js +13 -2
  356. package/src/proxy.js +4 -7
  357. package/src/runtime/cyberia-client/Dockerfile +9 -4
  358. package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
  359. package/src/runtime/cyberia-server/Dockerfile +9 -4
  360. package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
  361. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  362. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  363. package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
  364. package/src/runtime/engine-cyberia/compose.env +16 -0
  365. package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
  366. package/src/runtime/express/Express.js +32 -27
  367. package/src/runtime/lampp/Lampp.js +22 -70
  368. package/src/runtime/nginx/Nginx.js +1 -1
  369. package/src/runtime/wp/Wp.js +16 -48
  370. package/src/server/{catalog.js → build/catalog.js} +15 -5
  371. package/src/server/build/coverage.js +117 -0
  372. package/src/server/build/execution.js +402 -0
  373. package/src/server/build/package.js +465 -0
  374. package/src/server/build/testing.js +528 -0
  375. package/src/server/{dns.js → network/dns.js} +241 -14
  376. package/src/server/network/forward-proxy.js +541 -0
  377. package/src/server/{middlewares.js → network/middlewares.js} +59 -4
  378. package/src/server/network/node-capability.js +98 -0
  379. package/src/server/{peer.js → network/peer.js} +3 -3
  380. package/src/server/{proxy.js → network/proxy.js} +7 -13
  381. package/src/server/network/router.js +356 -0
  382. package/src/server/{tls.js → network/tls.js} +2 -2
  383. package/src/server/network/underpost-compression.js +186 -0
  384. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
  385. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
  386. package/src/server/{cri.js → ops/cri.js} +2 -2
  387. package/src/server/ops/cron.js +949 -0
  388. package/src/server/ops/event-notification.js +284 -0
  389. package/src/server/{logger.js → ops/logger.js} +108 -23
  390. package/src/server/ops/monitoring.js +1724 -0
  391. package/src/server/ops/systemd.js +259 -0
  392. package/src/server/{conf.js → runtime/conf.js} +521 -520
  393. package/src/server/runtime/config-scope.js +215 -0
  394. package/src/server/runtime/environment.js +149 -0
  395. package/src/server/{process.js → runtime/process.js} +153 -13
  396. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  397. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  398. package/src/server/{start.js → runtime/start.js} +128 -39
  399. package/src/server/{auth.js → security/auth.js} +7 -8
  400. package/src/server/security/container-storage.js +382 -0
  401. package/src/server/{crypto.js → security/crypto.js} +1 -1
  402. package/src/server/security/selinux.js +185 -0
  403. package/src/server/{backup.js → storage/backup.js} +17 -8
  404. package/src/server/{data-query.js → storage/data-query.js} +1 -1
  405. package/src/server/{downloader.js → storage/downloader.js} +2 -2
  406. package/src/server/storage/repository.js +68 -0
  407. package/src/server.js +4 -7
  408. package/src/ws/IoInterface.js +1 -1
  409. package/src/ws/IoServer.js +1 -1
  410. package/src/ws/core/core.ws.connection.js +1 -1
  411. package/src/ws/core/core.ws.emit.js +1 -1
  412. package/src/ws/core/core.ws.server.js +1 -1
  413. package/src/ws/default/default.ws.connection.js +1 -1
  414. package/src/ws/default/default.ws.emit.js +1 -1
  415. package/src/ws/default/default.ws.server.js +1 -1
  416. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  417. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  418. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  419. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  420. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
  421. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
  422. package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
  423. package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
  424. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  425. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  426. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  427. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  428. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  429. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  430. package/test/integration/infra/1-security/selinux.test.js +69 -0
  431. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  432. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  433. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  434. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  435. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  436. package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
  437. package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
  438. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  439. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  440. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  441. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  442. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  443. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  444. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +47 -6
  445. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -4
  446. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  447. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  448. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  449. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  450. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  451. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  452. package/test/support/shell-harness.js +73 -0
  453. package/test/unit/build-template.test.js +97 -0
  454. package/test/unit/build-workflow-offline.test.js +132 -0
  455. package/test/unit/catalog.test.js +71 -0
  456. package/test/unit/client-build-docs.test.js +334 -0
  457. package/test/unit/conf-loading.test.js +303 -0
  458. package/test/unit/conf-resolution.test.js +979 -0
  459. package/test/unit/coverage-artifact.test.js +130 -0
  460. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  461. package/test/unit/deploy-env-resolution.test.js +38 -0
  462. package/test/unit/deploy-log-table.test.js +447 -0
  463. package/test/unit/execution-profiles.test.js +219 -0
  464. package/test/unit/fleet-sync-source.test.js +149 -0
  465. package/test/unit/logger-redaction.test.js +112 -0
  466. package/test/unit/package.test.js +403 -0
  467. package/test/unit/prepare-host.test.js +299 -0
  468. package/test/unit/process-environment.test.js +18 -0
  469. package/test/unit/propagation-message.test.js +78 -0
  470. package/test/unit/redeploy-plan.test.js +24 -0
  471. package/test/unit/release-bump.test.js +474 -0
  472. package/test/unit/ssh-output-redaction.test.js +28 -0
  473. package/test/unit/start-options.test.js +46 -0
  474. package/test/unit/test-tiers.test.js +193 -0
  475. package/vitest.config.js +58 -0
  476. package/.nycrc +0 -9
  477. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  478. package/manifests/mongodb/pv-pvc.yaml +0 -59
  479. package/scripts/link-local-underpost-cli.sh +0 -6
  480. package/src/api/user/user.build.js +0 -16
  481. package/src/cli/env.js +0 -177
  482. package/src/client/components/core/Blockchain.js +0 -41
  483. package/src/client/components/core/Blog.js +0 -9
  484. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  485. package/src/client/public/default/assets/background/dark.jpg +0 -0
  486. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  487. package/src/client/public/default/assets/background/white0.jpg +0 -0
  488. package/src/client/public/doc/favicon.ico +0 -0
  489. package/src/client/public/doc/sitemap +0 -148
  490. package/src/server/cron.js +0 -476
@@ -0,0 +1,368 @@
1
+ /**
2
+ * Fallback World Engine — editor for the procedural fallback world's default items.
3
+ *
4
+ * The fallback world (src/api/cyberia-instance/cyberia-fallback-world.js) is
5
+ * generated in memory and never persisted, so it has no CyberiaInstance document
6
+ * to edit. This view is the trimmed-down counterpart of InstanceEngineCyberia:
7
+ * only the default-items section plus a reload trigger.
8
+ *
9
+ * The composed item set is staged on the engine process and shipped with the
10
+ * reload trigger — it is deliberately volatile (see cyberia-fallback-default-items.js),
11
+ * so an engine restart returns the world to pure code defaults.
12
+ */
13
+
14
+ import { BtnIcon } from '../core/BtnIcon.js';
15
+ import { Input } from '../core/Input.js';
16
+ import { htmls, s } from '../core/VanillaJs.js';
17
+ import { commonModeratorGuard } from '../core/CommonJs.js';
18
+ import { NotificationManager } from '../core/NotificationManager.js';
19
+ import { DropDown } from '../core/DropDown.js';
20
+ import { CyberiaInstanceService } from '../../services/cyberia-instance/cyberia-instance.service.js';
21
+ import { ObjectLayerService } from '../../services/object-layer/object-layer.service.js';
22
+ import { DefaultCyberiaItems } from './SharedDefaultsCyberia.js';
23
+
24
+ const dropdownValueKey = (value = '') => String(value).trim().replaceAll(' ', '-');
25
+ const createDropdownOption = (value, onClick = () => {}, display = value, data = value) => ({
26
+ value,
27
+ display,
28
+ data,
29
+ onClick,
30
+ });
31
+
32
+ class FallbackWorldEngineCyberia {
33
+ static itemIdsDropdownId = 'fallback-world-engine-item-ids-dropdown';
34
+ static itemInventoryListId = 'fallback-world-engine-item-inventory-list';
35
+ // itemId → defaultPlayerInventory flag for the currently selected item ids.
36
+ static itemInventoryFlags = {};
37
+ // Ids the code defaults already ship in an entity's defaultObjectLayers.
38
+ // Selecting one and leaving it unchecked REMOVES it from those defaults, so
39
+ // the list flags them instead of letting a player lose their starting kit.
40
+ static entityDefaultItemIds = [];
41
+
42
+ // Current selection, read from the dropdown's `oncheckvalues` (always live —
43
+ // it is updated before `_renderSelectedBadges` runs, unlike `.value` which
44
+ // lags by one in the option-click path).
45
+ static getSelectedItemIds() {
46
+ const token = DropDown.Tokens[FallbackWorldEngineCyberia.itemIdsDropdownId];
47
+ if (!token) return [];
48
+ const fromChecks = Object.values(token.oncheckvalues || {})
49
+ .map((v) => v.data)
50
+ .filter(Boolean);
51
+ if (fromChecks.length > 0) return fromChecks;
52
+ return Array.isArray(token.value) ? token.value.filter(Boolean) : [];
53
+ }
54
+
55
+ /** Payload shape shared with CyberiaInstance.itemIds. */
56
+ static getItemIdsPayload() {
57
+ return FallbackWorldEngineCyberia.getSelectedItemIds().map((id) => ({
58
+ id,
59
+ defaultPlayerInventory: !!FallbackWorldEngineCyberia.itemInventoryFlags[id],
60
+ }));
61
+ }
62
+
63
+ // Render the per-item "Default Player Inventory" toggles for every selected
64
+ // item id. Kept in sync with the dropdown via a MutationObserver on its badge
65
+ // container (see render()).
66
+ static renderItemInventoryList(containerId = FallbackWorldEngineCyberia.itemInventoryListId) {
67
+ const container = s(`.${containerId}`);
68
+ if (!container) return;
69
+
70
+ const selected = FallbackWorldEngineCyberia.getSelectedItemIds();
71
+
72
+ // Drop flags for items no longer selected so the payload never carries them.
73
+ for (const key of Object.keys(FallbackWorldEngineCyberia.itemInventoryFlags)) {
74
+ if (!selected.includes(key)) delete FallbackWorldEngineCyberia.itemInventoryFlags[key];
75
+ }
76
+
77
+ if (selected.length === 0) {
78
+ htmls(
79
+ `.${containerId}`,
80
+ html`<div style="color:#888;font-size:12px;">
81
+ No item IDs selected — the fallback world runs on pure code defaults.
82
+ </div>`,
83
+ );
84
+ return;
85
+ }
86
+
87
+ let listHtml = '';
88
+ for (const itemId of selected) {
89
+ const isChecked = !!FallbackWorldEngineCyberia.itemInventoryFlags[itemId];
90
+ const checked = isChecked ? 'checked' : '';
91
+ const strips = !isChecked && FallbackWorldEngineCyberia.entityDefaultItemIds.includes(itemId);
92
+ listHtml += html`<div class="fl" style="border-bottom:1px solid #444;padding:4px 0;align-items:center;">
93
+ <div class="in fll" style="flex:1;font-size:12px;font-family:monospace;">
94
+ ${itemId}
95
+ ${strips
96
+ ? html`<span
97
+ style="color:#d90;font-size:11px;font-family:initial;margin-left:6px;"
98
+ title="This id is part of the code entity defaults. Left unchecked, it is removed from them."
99
+ ><i class="fa-solid fa-triangle-exclamation"></i> removes from entity defaults</span
100
+ >`
101
+ : ''}
102
+ </div>
103
+ <div class="in fll" style="display:flex;align-items:center;justify-content:flex-end;">
104
+ <label style="font-size:11px;cursor:pointer;display:flex;align-items:center;gap:5px;">
105
+ <input
106
+ type="checkbox"
107
+ class="fallback-world-engine-item-inv-checkbox"
108
+ data-item-id="${itemId}"
109
+ ${checked}
110
+ style="cursor:pointer;"
111
+ />
112
+ Default Player Inventory
113
+ </label>
114
+ </div>
115
+ </div>`;
116
+ }
117
+ htmls(`.${containerId}`, listHtml);
118
+
119
+ container.querySelectorAll('.fallback-world-engine-item-inv-checkbox').forEach((cb) => {
120
+ cb.onchange = () => {
121
+ FallbackWorldEngineCyberia.itemInventoryFlags[cb.dataset.itemId] = cb.checked;
122
+ };
123
+ });
124
+ }
125
+
126
+ static syncItemIdsDropdownSelection(itemIds = []) {
127
+ const dropdownId = FallbackWorldEngineCyberia.itemIdsDropdownId;
128
+ if (!DropDown.Tokens[dropdownId]) return;
129
+
130
+ // Accept both the `[{ id, defaultPlayerInventory }]` shape and a plain
131
+ // string[], matching what the fallback-world endpoint may return.
132
+ const normalized = (itemIds || [])
133
+ .map((entry) => (typeof entry === 'string' ? { id: entry, defaultPlayerInventory: false } : entry))
134
+ .filter((entry) => entry && entry.id);
135
+
136
+ DropDown.Tokens[dropdownId].value = [];
137
+ if (s(`.${dropdownId}`)) s(`.${dropdownId}`).value = [];
138
+ DropDown.Tokens[dropdownId].oncheckvalues = {};
139
+ htmls(`.dropdown-current-${dropdownId}`, '');
140
+ htmls(`.${dropdownId}-render-container`, '');
141
+
142
+ FallbackWorldEngineCyberia.itemInventoryFlags = {};
143
+ const ids = [];
144
+ for (const entry of normalized) {
145
+ const key = dropdownValueKey(entry.id);
146
+ DropDown.Tokens[dropdownId].oncheckvalues[key] = {
147
+ data: entry.id,
148
+ display: entry.id,
149
+ value: entry.id,
150
+ };
151
+ FallbackWorldEngineCyberia.itemInventoryFlags[entry.id] = !!entry.defaultPlayerInventory;
152
+ ids.push(entry.id);
153
+ }
154
+ DropDown.Tokens[dropdownId].value = [...ids];
155
+ if (s(`.${dropdownId}`)) s(`.${dropdownId}`).value = [...ids];
156
+ DropDown.Tokens[dropdownId]._renderSelectedBadges?.();
157
+ FallbackWorldEngineCyberia.renderItemInventoryList();
158
+ }
159
+
160
+ static async buildItemIdsDropdown() {
161
+ return await DropDown.instance({
162
+ id: FallbackWorldEngineCyberia.itemIdsDropdownId,
163
+ label: html`Object Layer Item IDs`,
164
+ data: [],
165
+ type: 'checkbox',
166
+ containerClass: 'inl',
167
+ excludeSelected: true,
168
+ serviceProvider: async (q) => {
169
+ const result = await ObjectLayerService.searchItemIds({ q });
170
+ if (result.status === 'success' && result.data?.itemIds) {
171
+ return result.data.itemIds.map((itemId) => createDropdownOption(itemId));
172
+ }
173
+ return [];
174
+ },
175
+ });
176
+ }
177
+
178
+ static async render(options = {}) {
179
+ const { appStore } = options;
180
+ const role = appStore?.Data?.user?.main?.model?.user?.role || 'guest';
181
+ const canMutate = commonModeratorGuard(role);
182
+ const idHotReloadUrl = 'fallback-world-engine-input-hot-reload-url';
183
+ const idItemIdsDropdown = FallbackWorldEngineCyberia.itemIdsDropdownId;
184
+ const idItemInventoryList = FallbackWorldEngineCyberia.itemInventoryListId;
185
+
186
+ setTimeout(async () => {
187
+ // Keep the per-item "Default Player Inventory" toggles in sync with the
188
+ // item-ids dropdown. Every add/remove/clear re-renders the dropdown badge
189
+ // container, so observing it is a reliable change hook (the dropdown
190
+ // exposes no onChange callback).
191
+ const itemBadgeContainer = s(`.dropdown-current-${idItemIdsDropdown}`);
192
+ if (itemBadgeContainer) {
193
+ const itemInventoryObserver = new MutationObserver(() => {
194
+ FallbackWorldEngineCyberia.renderItemInventoryList();
195
+ });
196
+ itemInventoryObserver.observe(itemBadgeContainer, { childList: true, subtree: true });
197
+ }
198
+
199
+ // Load whatever this engine process currently serves, so reopening the
200
+ // view shows the live set rather than an empty form.
201
+ try {
202
+ const result = await CyberiaInstanceService.getFallbackDefaultItems();
203
+ if (result?.status === 'success') {
204
+ FallbackWorldEngineCyberia.entityDefaultItemIds = result.data?.entityDefaultItemIds || [];
205
+ FallbackWorldEngineCyberia.syncItemIdsDropdownSelection(result.data?.itemIds || []);
206
+ }
207
+ } catch (error) {
208
+ NotificationManager.Push({ html: error.message, status: 'error' });
209
+ }
210
+ FallbackWorldEngineCyberia.renderItemInventoryList();
211
+
212
+ if (s(`.btn-fallback-world-engine-load-defaults`))
213
+ s(`.btn-fallback-world-engine-load-defaults`).onclick = () => {
214
+ // Seed from the canonical registry so an operator starts from the
215
+ // same list `import-default-items` creates ObjectLayers for. Ids the
216
+ // entity defaults already ship start checked: selecting them
217
+ // unchecked would strip them from those defaults, which is never what
218
+ // "load the defaults" is asking for.
219
+ const flags = Object.fromEntries(
220
+ FallbackWorldEngineCyberia.getItemIdsPayload().map((e) => [e.id, e.defaultPlayerInventory]),
221
+ );
222
+ FallbackWorldEngineCyberia.syncItemIdsDropdownSelection(
223
+ DefaultCyberiaItems.map((entry) => ({
224
+ id: entry.item.id,
225
+ defaultPlayerInventory:
226
+ flags[entry.item.id] ?? FallbackWorldEngineCyberia.entityDefaultItemIds.includes(entry.item.id),
227
+ })),
228
+ );
229
+ };
230
+
231
+ if (s(`.btn-fallback-world-engine-clear`))
232
+ s(`.btn-fallback-world-engine-clear`).onclick = () => {
233
+ FallbackWorldEngineCyberia.syncItemIdsDropdownSelection([]);
234
+ };
235
+
236
+ if (s(`.btn-fallback-world-engine-toggle-hot-reload`))
237
+ s(`.btn-fallback-world-engine-toggle-hot-reload`).onclick = () => {
238
+ const body = s(`.fallback-world-engine-hot-reload-body`);
239
+ const caret = s(`.fallback-world-engine-hot-reload-caret`);
240
+ if (body) body.classList.toggle('hide');
241
+ if (caret) {
242
+ caret.classList.toggle('fa-caret-right');
243
+ caret.classList.toggle('fa-caret-down');
244
+ }
245
+ };
246
+
247
+ const triggerHotReload = async (mode) => {
248
+ const buttons = [
249
+ s(`.btn-fallback-world-engine-hot-reload`),
250
+ s(`.btn-fallback-world-engine-hot-reload-incremental`),
251
+ ];
252
+ const statusSelector = `.fallback-world-engine-hot-reload-status`;
253
+ const serverUrl = s(`.${idHotReloadUrl}`)?.value?.trim();
254
+ if (!serverUrl) {
255
+ NotificationManager.Push({ html: 'Set the cyberia-server URL first.', status: 'warning' });
256
+ return;
257
+ }
258
+
259
+ for (const btn of buttons) if (btn) btn.disabled = true;
260
+ if (s(statusSelector))
261
+ htmls(statusSelector, html`<span style="color:#888;">Triggering ${mode} hot reload…</span>`);
262
+ try {
263
+ const result = await CyberiaInstanceService.fallbackHotReload({
264
+ body: { serverUrl, mode, itemIds: FallbackWorldEngineCyberia.getItemIdsPayload() },
265
+ });
266
+ if (result.status === 'error') {
267
+ NotificationManager.Push({ html: result.message, status: 'error' });
268
+ if (s(statusSelector)) htmls(statusSelector, html`<span style="color:#d66;">${result.message}</span>`);
269
+ return;
270
+ }
271
+ const { transport, durationMs, message, grpcError, itemIds } = result.data || {};
272
+ NotificationManager.Push({ html: `Hot reload via ${transport}: ${message}`, status: 'success' });
273
+ if (s(statusSelector))
274
+ htmls(
275
+ statusSelector,
276
+ html`<span style="color:#6b6;">
277
+ via <b>${transport}</b> · ${durationMs}ms · ${(itemIds || []).length} default item(s) staged ·
278
+ ${message} </span
279
+ >${grpcError ? html`<div style="color:#a80;">gRPC unavailable: ${grpcError}</div>` : ''}`,
280
+ );
281
+ } catch (error) {
282
+ NotificationManager.Push({ html: error.message, status: 'error' });
283
+ if (s(statusSelector)) htmls(statusSelector, html`<span style="color:#d66;">${error.message}</span>`);
284
+ } finally {
285
+ for (const btn of buttons) if (btn) btn.disabled = false;
286
+ }
287
+ };
288
+
289
+ if (s(`.btn-fallback-world-engine-hot-reload`))
290
+ s(`.btn-fallback-world-engine-hot-reload`).onclick = () => triggerHotReload('full');
291
+ if (s(`.btn-fallback-world-engine-hot-reload-incremental`))
292
+ s(`.btn-fallback-world-engine-hot-reload-incremental`).onclick = () => triggerHotReload('incremental');
293
+ });
294
+
295
+ return html`
296
+ <div class="in fallback-world-engine-container">
297
+ <div class="in section-mp" style="color:#888;font-size:12px;">
298
+ The fallback world is generated in memory and never persisted, so it has no instance document to edit. Items
299
+ selected here are staged on this engine process and applied when a cyberia-server reloads. They are volatile:
300
+ an engine restart returns the world to its code defaults.
301
+ </div>
302
+
303
+ <div class="in section-mp" style="margin-top: 10px;">
304
+ <div class="in input-label" style="font-size:14px;margin-bottom:5px;">Default Items</div>
305
+ ${await FallbackWorldEngineCyberia.buildItemIdsDropdown()}
306
+ </div>
307
+ <div class="in section-mp" style="margin-top: 5px;">
308
+ <div class="in input-label" style="font-size:13px;margin-bottom:5px;">Default Player Inventory</div>
309
+ <div class="in" style="color:#888;font-size:12px;margin-bottom:6px;">
310
+ Every selected id is resolved to an atlas at boot. Ids checked here are seeded into each new player's
311
+ inventory (inactive, never auto-equipped); unchecked ids are explicitly removed from the player's default
312
+ layers.
313
+ </div>
314
+ <div class="in ${idItemInventoryList}" style="max-height:200px;overflow-y:auto;"></div>
315
+ ${canMutate
316
+ ? html`<div class="in" style="display:flex;gap:5px;flex-wrap:wrap;margin-top:10px;">
317
+ ${await BtnIcon.instance({
318
+ class: 'wfa btn-fallback-world-engine-load-defaults',
319
+ label: html`<i class="fa-solid fa-list-check"></i> Load Canonical Defaults`,
320
+ })}
321
+ ${await BtnIcon.instance({
322
+ class: 'wfa btn-fallback-world-engine-clear',
323
+ label: html`<i class="fa-solid fa-eraser"></i> Clear Selection`,
324
+ })}
325
+ </div>`
326
+ : ''}
327
+ </div>
328
+
329
+ ${canMutate
330
+ ? html`<div class="in section-mp" style="margin-top: 10px;">
331
+ ${await BtnIcon.instance({
332
+ class: 'wfa btn-fallback-world-engine-toggle-hot-reload',
333
+ label: html`<i class="fa-solid fa-caret-right fallback-world-engine-hot-reload-caret"></i> Hot Reload`,
334
+ })}
335
+ <div class="in fallback-world-engine-hot-reload-body hide">
336
+ <div class="in" style="color:#888;font-size:12px;margin:5px 0;">
337
+ Stages the items above on this engine, then rebuilds the world of a running cyberia-server so it
338
+ re-fetches them. Tries the gRPC control service first and falls back to the REST endpoint. For a
339
+ multi-instance deployment, append the variant sub-path so the trigger reaches the right world (e.g.
340
+ <code>https://server.cyberiaonline.com/TEST</code>); the default world uses the bare origin.
341
+ </div>
342
+ ${await Input.instance({
343
+ id: idHotReloadUrl,
344
+ label: html`<i class="fa-solid fa-server"></i> Cyberia Server URL`,
345
+ containerClass: 'in',
346
+ placeholder: 'https://server.cyberiaonline.com/TEST',
347
+ type: 'text',
348
+ })}
349
+ <div class="in" style="display:flex;gap:5px;flex-wrap:wrap;margin-top:5px;">
350
+ ${await BtnIcon.instance({
351
+ class: 'wfa btn-fallback-world-engine-hot-reload',
352
+ label: html`<i class="fa-solid fa-rotate"></i> Trigger Hot Reload`,
353
+ })}
354
+ ${await BtnIcon.instance({
355
+ class: 'wfa btn-fallback-world-engine-hot-reload-incremental',
356
+ label: html`<i class="fa-solid fa-layer-group"></i> Incremental (assets only)`,
357
+ })}
358
+ </div>
359
+ <div class="in fallback-world-engine-hot-reload-status" style="margin-top:5px;font-size:12px;"></div>
360
+ </div>
361
+ </div>`
362
+ : ''}
363
+ </div>
364
+ `;
365
+ }
366
+ }
367
+
368
+ export { FallbackWorldEngineCyberia };
@@ -3,6 +3,7 @@ import { BtnIcon } from '../core/BtnIcon.js';
3
3
  import { getId, newInstance, random } from '../core/CommonJs.js';
4
4
  import { Css, ThemeEvents, Themes, darkTheme } from '../core/Css.js';
5
5
  import { Docs } from '../core/Docs.js';
6
+ import { githubUrl } from '../core/Repository.js';
6
7
  import { EventsUI } from '../core/EventsUI.js';
7
8
  import { LogIn } from '../core/LogIn.js';
8
9
  import { LogOut } from '../core/LogOut.js';
@@ -34,6 +35,7 @@ import { InstanceEngineCyberia } from '../cyberia/InstanceEngineCyberia.js';
34
35
  import { InstanceSelectionView } from '../cyberia/InstanceSelectionView.js';
35
36
  import { ActionEngineCyberia } from '../cyberia/ActionEngineCyberia.js';
36
37
  import { EntityEngineCyberia } from '../cyberia/EntityEngineCyberia.js';
38
+ import { FallbackWorldEngineCyberia } from '../cyberia/FallbackWorldEngineCyberia.js';
37
39
 
38
40
  class AppShellCyberiaPortal {
39
41
  static Data = {};
@@ -288,6 +290,18 @@ class AppShellCyberiaPortal {
288
290
  handleContainerClass: 'handle-btn-container',
289
291
  tooltipHtml: await Badge.instance(buildBadgeToolTipMenuOption('cyberia-entity-engine')),
290
292
  })}
293
+ ${await BtnIcon.instance({
294
+ class: 'in wfa main-btn-menu main-btn-fallback-world-engine',
295
+ useMenuBtn: true,
296
+ label: renderMenuLabel({
297
+ icon: html`<img class="inl cyberia-menu-icon" src="${getProxyPath()}assets/ui-icons/engine.png" />`,
298
+ text: html`<span class="menu-label-text">${Translate.instance('fallback-world-engine')}</span>`,
299
+ }),
300
+ attrs: `data-id="fallback-world-engine"`,
301
+ tabHref: `${getProxyPath()}fallback-world-engine`,
302
+ handleContainerClass: 'handle-btn-container',
303
+ tooltipHtml: await Badge.instance(buildBadgeToolTipMenuOption('fallback-world-engine')),
304
+ })}
291
305
  </div>
292
306
  `,
293
307
  // htmlMainBody: async () => {
@@ -554,7 +568,7 @@ class AppShellCyberiaPortal {
554
568
  html`<img class="inl cyberia-menu-icon" src="${getProxyPath()}assets/ui-icons/arrow-right.png" />`,
555
569
  coverageUrl: () => `${getProxyPath()}docs/hardhat-coverage`,
556
570
  demoUrl: () => `https://client.cyberiaonline.com/`,
557
- lastReleaseUrl: () => `https://github.com/underpostnet/engine-cyberia.git`,
571
+ lastReleaseUrl: () => githubUrl('engine-cyberia'),
558
572
  }),
559
573
  handleType: 'bar',
560
574
  observer: true,
@@ -762,6 +776,26 @@ class AppShellCyberiaPortal {
762
776
  });
763
777
  });
764
778
 
779
+ EventsUI.onClick(`.main-btn-fallback-world-engine`, async () => {
780
+ const { barConfig } = await Themes[Css.currentTheme]();
781
+ await Modal.instance({
782
+ id: 'modal-fallback-world-engine',
783
+ route: 'fallback-world-engine',
784
+ barConfig,
785
+ title: renderViewTitle({
786
+ icon: html`<img class="inl cyberia-menu-icon-modal" src="${getProxyPath()}assets/ui-icons/engine.png" />`,
787
+ text: `<span class='inl cyberia-text-title-modal'>${Translate.instance('fallback-world-engine')}</span>`,
788
+ }),
789
+ html: async () => await FallbackWorldEngineCyberia.render({ appStore: AppStoreCyberiaPortal }),
790
+ handleType: 'bar',
791
+ maximize: true,
792
+ mode: 'view',
793
+ slideMenu: 'modal-menu',
794
+ RouterInstance,
795
+ observer: true,
796
+ });
797
+ });
798
+
765
799
  s(`.main-btn-admin`).onclick = () => {
766
800
  const { protocol, hostname } = window.location;
767
801
  return (location.href = `${protocol}//${hostname}/admin${['', 0][random(0, 1)]}`);
@@ -56,6 +56,10 @@ class RouterCyberiaPortal {
56
56
  title: 'cyberia-entity-engine',
57
57
  render: () => s(`.main-btn-cyberia-entity-engine`).click(),
58
58
  },
59
+ '/fallback-world-engine': {
60
+ title: 'fallback-world-engine',
61
+ render: () => s(`.main-btn-fallback-world-engine`).click(),
62
+ },
59
63
  '/instance-selection': {
60
64
  title: 'instance-selection',
61
65
  render: () => s(`.main-btn-instance-selection`).click(),
@@ -1,11 +1,11 @@
1
1
  import { Css } from '../core/Css.js';
2
- import { FullScreen } from '../core/FullScreen.js';
2
+ import { ViewModeController } from '../core/ViewModeController.js';
3
3
  import { Translate } from '../core/Translate.js';
4
4
  import { Worker } from '../core/Worker.js';
5
5
 
6
6
  class SettingsCyberiaPortal {
7
7
  static async instance() {
8
- let render = await FullScreen.RenderSetting();
8
+ let render = await ViewModeController.RenderSetting();
9
9
  render += await Css.RenderSetting();
10
10
  render += await Translate.RenderSetting();
11
11
  render += await Worker.RenderSetting();
@@ -30,6 +30,10 @@ class TranslateCyberiaPortal {
30
30
  en: 'Cyberia Entity Engine',
31
31
  es: 'Cyberia Entity Engine',
32
32
  };
33
+ Translate.Data['fallback-world-engine'] = {
34
+ en: 'Fallback World Engine',
35
+ es: 'Fallback World Engine',
36
+ };
33
37
  Translate.Data['instance-selection'] = {
34
38
  en: 'Select World',
35
39
  es: 'Seleccionar Mundo',
@@ -239,7 +239,7 @@ class AppShellDefault {
239
239
  `,
240
240
  );
241
241
  } else {
242
- const backgroundImage = `${getProxyPath()}assets/background/white0-min.jpg`;
242
+ const backgroundImage = `${getProxyPath()}assets/background/white.jpg`;
243
243
  htmls(
244
244
  `.style-ssr-background-image`,
245
245
  css`
@@ -1,11 +1,11 @@
1
1
  import { Css } from '../core/Css.js';
2
- import { FullScreen } from '../core/FullScreen.js';
2
+ import { ViewModeController } from '../core/ViewModeController.js';
3
3
  import { Translate } from '../core/Translate.js';
4
4
  import { Worker } from '../core/Worker.js';
5
5
 
6
6
  class SettingsDefault {
7
7
  static async instance() {
8
- let render = await FullScreen.RenderSetting();
8
+ let render = await ViewModeController.RenderSetting();
9
9
  render += await Css.RenderSetting();
10
10
  render += await Translate.RenderSetting();
11
11
  render += await Worker.RenderSetting();
@@ -1,11 +1,11 @@
1
1
  import { Css } from '../core/Css.js';
2
- import { FullScreen } from '../core/FullScreen.js';
2
+ import { ViewModeController } from '../core/ViewModeController.js';
3
3
  import { Translate } from '../core/Translate.js';
4
4
  import { Worker } from '../core/Worker.js';
5
5
 
6
6
  class SettingsItemledger {
7
7
  static async instance() {
8
- let render = await FullScreen.RenderSetting();
8
+ let render = await ViewModeController.RenderSetting();
9
9
  render += await Css.RenderSetting();
10
10
  render += await Translate.RenderSetting();
11
11
  render += await Worker.RenderSetting();
@@ -18,6 +18,7 @@ import { CyberpunkBloggerUnderpost } from './CyberpunkBloggerUnderpost.js';
18
18
  import { Badge } from '../core/Badge.js';
19
19
  import { SettingsUnderpost } from './SettingsUnderpost.js';
20
20
  import { Recover } from '../core/Recover.js';
21
+ import { githubUrl, repositoryIdentity } from '../core/Repository.js';
21
22
  import { PanelForm } from '../core/PanelForm.js';
22
23
  import { SearchBox } from '../core/SearchBox.js';
23
24
  import { DocumentSearchProvider } from './DocumentSearchProvider.js';
@@ -214,7 +215,7 @@ class AppShellUnderpost {
214
215
  text: html`<span class="menu-label-text">${Translate.instance('github')}</span>`,
215
216
  }),
216
217
  attrs: `data-id="github"`,
217
- tabHref: `https://github.com/underpostnet/`,
218
+ tabHref: githubUrl(),
218
219
  handleContainerClass: 'handle-btn-container',
219
220
  tooltipHtml: await Badge.instance(buildBadgeToolTipMenuOption('github')),
220
221
  })}
@@ -683,7 +684,7 @@ class AppShellUnderpost {
683
684
  });
684
685
 
685
686
  EventsUI.onClick(`.main-btn-github`, async () => {
686
- location.href = `https://github.com/underpostnet/pwa-microservices-template/`;
687
+ location.href = githubUrl(repositoryIdentity().template);
687
688
  });
688
689
  }
689
690
  }
@@ -1,11 +1,11 @@
1
1
  import { Css } from '../core/Css.js';
2
- import { FullScreen } from '../core/FullScreen.js';
2
+ import { ViewModeController } from '../core/ViewModeController.js';
3
3
  import { Translate } from '../core/Translate.js';
4
4
  import { Worker } from '../core/Worker.js';
5
5
 
6
6
  class SettingsUnderpost {
7
7
  static async instance() {
8
- let render = await FullScreen.RenderSetting();
8
+ let render = await ViewModeController.RenderSetting();
9
9
  render += await Css.RenderSetting();
10
10
  render += await Translate.RenderSetting();
11
11
  render += await Worker.RenderSetting();
@@ -193,7 +193,7 @@ The render frame runs at vsync. Inside one render frame, `cyberia-client` perfor
193
193
 
194
194
  1. Poll any pending optional client-hints fetch.
195
195
  2. Capture raw input → build typed input command (`kind`, `clientTick`, `sequence`, payload) → apply to prediction → send on the wire.
196
- 3. Reconcile against the latest snapshot: drop input commands `lastAckedSequence`, rewind self to authoritative position, replay unacked commands.
196
+ 3. Reconcile against the latest snapshot: difference the authoritative position against the position this client predicted for that same tick, shift the prediction trail by that error, and — once `moveAck` covers the newest command — adopt the server's own `targetPos` and route as the walk destination.
197
197
  4. Fixed-timestep simulation: while accumulator ≥ `tickDuration`, advance prediction one tick.
198
198
  5. Interpolation: compute remote-entity view positions at `renderTick`.
199
199
  6. Render. Read view models; never mutate world state.
@@ -236,7 +236,20 @@ WS frame (binary) → decode → typed InputCommand{kind, clientTick, sequen
236
236
  authoritative world state
237
237
  ```
238
238
 
239
- `InputCommand.Sequence` is monotonic per client. The server tracks the highest applied sequence per player; `phaseReplication` writes it into every snapshot header. The client drops acknowledged input commands from its prediction replay buffer using this value.
239
+ `InputCommand.Sequence` is monotonic per client. Every snapshot carries two acknowledgements of it, and they are not interchangeable:
240
+
241
+ | Field | Meaning | Client use |
242
+ | --------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------- |
243
+ | `ack` | Highest sequence **received** for this player. | Retires commands from the prediction buffer. |
244
+ | `moveAck` | Highest `PlayerAction` sequence that **re-planned movement**. | Gates adoption of the authoritative `targetPos` / `path`. |
245
+
246
+ **Movement re-plans once per player per tick, and nothing else throttles it.** Handlers record the tap's destination; `phaseInput` runs one A* per player after the queue is drained. Taps that land in the same tick describe the same instant, so only the newest is planned — the rest were superseded before they could mean anything. That coalescing is the only bound on pathfinder cost.
247
+
248
+ This is why the two acknowledgements diverge: a superseded tap is acked on arrival and never planned, so `self.path` and `self.targetPos` can still describe an earlier command. A client that adopted the route on `ack` alone would turn back toward the abandoned target — worst during rapid changes of direction, where it reads as input lag and as a walk that sets off the wrong way.
249
+
250
+ Skills are not coalesced: they fire on every accepted tap, so the uplink carries every tap and the inbound rate limiter (`DefaultMessageRate`, 30/s) is what bounds the stream.
251
+
252
+ The client predicts every tap immediately and never waits on a cadence. `self.actionCooldownMs` is the skill-trigger period only; keyboard steering paces its *refresh* by it, while a change of heading emits at once.
240
253
 
241
254
  ---
242
255
 
@@ -271,7 +284,8 @@ Every Cyberia document uses the same terms. Aliases are not permitted.
271
284
  | **tick rate** | Simulation Hz on `cyberia-server`. |
272
285
  | **snapshot** | AOI-filtered world view at one tick for one player. |
273
286
  | **prediction** | Optimistic local apply of input commands to the predicted self entity. |
274
- | **reconciliation** | Drop acknowledged inputs, rewind self to authoritative position, replay unacked inputs. |
287
+ | **reconciliation** | Correct prediction by the error measured at one tick: authoritative position minus the position predicted for that tick. Input is a destination, not a per-tick impulse, so the client keeps walking toward the `targetPos` that `moveAck` confirms, rather than replaying a command log. |
288
+ | **move coalescing** | One movement re-plan per player per tick, from the newest tap of that tick. The only bound on pathfinder cost, and the reason `moveAck` trails `ack`. |
275
289
  | **display smoothing** | Per-render-frame exponential lerp from the discrete predicted self position to a continuous on-screen position. Decouples the visible main player from sim-tick boundaries. |
276
290
  | **interpolation** | Render-time smoothing of remote entities, sampled from snapshot history. |
277
291
  | **authoritative server** | `cyberia-server`. Sole authority on world state. |