cyberia 3.1.3 → 3.2.9

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 (377) hide show
  1. package/.env.example +0 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +10 -8
  3. package/.github/workflows/engine-cyberia.ci.yml +12 -29
  4. package/.github/workflows/ghpkg.ci.yml +4 -4
  5. package/.github/workflows/npmpkg.ci.yml +28 -11
  6. package/.github/workflows/publish.ci.yml +21 -2
  7. package/.github/workflows/pwa-microservices-template-page.cd.yml +4 -5
  8. package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
  9. package/.github/workflows/release.cd.yml +14 -10
  10. package/CHANGELOG.md +783 -1
  11. package/CLI-HELP.md +95 -18
  12. package/Dockerfile +0 -2
  13. package/README.md +290 -220
  14. package/bin/build.js +24 -7
  15. package/bin/cyberia.js +2838 -252
  16. package/bin/deploy.js +747 -125
  17. package/bin/file.js +9 -0
  18. package/bin/index.js +2838 -252
  19. package/bin/vs.js +1 -1
  20. package/conf.js +99 -65
  21. package/deployment.yaml +18 -164
  22. package/hardhat/hardhat.config.js +13 -13
  23. package/hardhat/ignition/modules/ObjectLayerToken.js +1 -1
  24. package/hardhat/package-lock.json +2559 -5864
  25. package/hardhat/package.json +14 -23
  26. package/hardhat/scripts/deployObjectLayerToken.js +1 -1
  27. package/hardhat/test/ObjectLayerToken.js +4 -2
  28. package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
  29. package/hardhat/types/ethers-contracts/common.ts +92 -0
  30. package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
  31. package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
  32. package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
  33. package/hardhat/types/ethers-contracts/index.ts +6 -0
  34. package/jsconfig.json +1 -1
  35. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +6 -5
  36. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +6 -5
  37. package/manifests/deployment/dd-cyberia-development/deployment.yaml +18 -164
  38. package/manifests/deployment/dd-cyberia-development/proxy.yaml +7 -79
  39. package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
  40. package/manifests/deployment/dd-test-development/deployment.yaml +112 -28
  41. package/manifests/deployment/dd-test-development/proxy.yaml +46 -1
  42. package/manifests/deployment/playwright/deployment.yaml +1 -1
  43. package/nodemon.json +1 -1
  44. package/package.json +39 -24
  45. package/proxy.yaml +7 -79
  46. package/scripts/k3s-node-setup.sh +2 -2
  47. package/scripts/nat-iptables.sh +103 -18
  48. package/scripts/rhel-grpc-setup.sh +56 -0
  49. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +58 -14
  50. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +23 -14
  51. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
  52. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +148 -20
  53. package/src/api/core/core.controller.js +10 -10
  54. package/src/api/core/core.service.js +10 -10
  55. package/src/api/crypto/crypto.controller.js +8 -8
  56. package/src/api/crypto/crypto.service.js +8 -8
  57. package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
  58. package/src/api/cyberia-action/cyberia-action.model.js +87 -0
  59. package/src/api/cyberia-action/cyberia-action.router.js +27 -0
  60. package/src/api/cyberia-action/cyberia-action.service.js +42 -0
  61. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
  62. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
  63. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
  64. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
  65. package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
  66. package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
  67. package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
  68. package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
  69. package/src/api/cyberia-instance/cyberia-fallback-world.js +178 -0
  70. package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
  71. package/src/api/cyberia-instance/cyberia-instance.model.js +87 -0
  72. package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
  73. package/src/api/cyberia-instance/cyberia-instance.service.js +156 -0
  74. package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
  75. package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
  76. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
  77. package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +574 -0
  78. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +231 -0
  79. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
  80. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
  81. package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
  82. package/src/api/cyberia-map/cyberia-map.model.js +30 -0
  83. package/src/api/cyberia-map/cyberia-map.router.js +40 -0
  84. package/src/api/cyberia-map/cyberia-map.service.js +74 -0
  85. package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
  86. package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
  87. package/src/api/cyberia-quest/cyberia-quest.router.js +27 -0
  88. package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
  89. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
  90. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
  91. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +27 -0
  92. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
  93. package/src/api/default/default.controller.js +10 -10
  94. package/src/api/default/default.service.js +10 -10
  95. package/src/api/document/document.controller.js +12 -12
  96. package/src/api/document/document.model.js +10 -16
  97. package/src/api/file/file.controller.js +8 -8
  98. package/src/api/file/file.model.js +10 -10
  99. package/src/api/file/file.ref.json +18 -0
  100. package/src/api/file/file.service.js +36 -36
  101. package/src/api/instance/instance.controller.js +10 -10
  102. package/src/api/instance/instance.model.js +4 -10
  103. package/src/api/instance/instance.service.js +10 -10
  104. package/src/api/ipfs/ipfs.controller.js +15 -36
  105. package/src/api/ipfs/ipfs.model.js +47 -47
  106. package/src/api/ipfs/ipfs.router.js +8 -13
  107. package/src/api/ipfs/ipfs.service.js +67 -129
  108. package/src/api/object-layer/object-layer.controller.js +12 -12
  109. package/src/api/object-layer/object-layer.model.js +4 -17
  110. package/src/api/object-layer/object-layer.router.js +30 -0
  111. package/src/api/object-layer/object-layer.service.js +126 -43
  112. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
  113. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
  114. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +18 -14
  115. package/src/api/test/test.controller.js +8 -8
  116. package/src/api/test/test.service.js +8 -8
  117. package/src/api/user/guest.service.js +99 -0
  118. package/src/api/user/user.controller.js +6 -6
  119. package/src/api/user/user.model.js +8 -13
  120. package/src/api/user/user.service.js +11 -27
  121. package/src/cli/cluster.js +68 -21
  122. package/src/cli/db.js +753 -825
  123. package/src/cli/deploy.js +215 -125
  124. package/src/cli/env.js +29 -0
  125. package/src/cli/fs.js +82 -8
  126. package/src/cli/image.js +43 -1
  127. package/src/cli/index.js +74 -3
  128. package/src/cli/kubectl.js +211 -0
  129. package/src/cli/release.js +340 -0
  130. package/src/cli/repository.js +475 -74
  131. package/src/cli/run.js +582 -43
  132. package/src/cli/secrets.js +73 -0
  133. package/src/cli/ssh.js +1 -1
  134. package/src/cli/static.js +43 -115
  135. package/src/cli/test.js +3 -3
  136. package/src/client/Cryptokoyn.index.js +18 -22
  137. package/src/client/CyberiaPortal.index.js +19 -24
  138. package/src/client/Default.index.js +21 -34
  139. package/src/client/Itemledger.index.js +20 -27
  140. package/src/client/Underpost.index.js +19 -24
  141. package/src/client/components/core/404.js +4 -4
  142. package/src/client/components/core/500.js +4 -4
  143. package/src/client/components/core/Account.js +73 -60
  144. package/src/client/components/core/AgGrid.js +23 -33
  145. package/src/client/components/core/Alert.js +12 -13
  146. package/src/client/components/core/AppStore.js +69 -0
  147. package/src/client/components/core/Auth.js +35 -37
  148. package/src/client/components/core/Badge.js +7 -13
  149. package/src/client/components/core/BtnIcon.js +15 -17
  150. package/src/client/components/core/CalendarCore.js +43 -64
  151. package/src/client/components/core/Chat.js +13 -15
  152. package/src/client/components/core/ClientEvents.js +87 -0
  153. package/src/client/components/core/ColorPaletteElement.js +309 -0
  154. package/src/client/components/core/Content.js +17 -14
  155. package/src/client/components/core/Css.js +15 -71
  156. package/src/client/components/core/CssCore.js +12 -16
  157. package/src/client/components/core/D3Chart.js +4 -4
  158. package/src/client/components/core/Docs.js +64 -91
  159. package/src/client/components/core/DropDown.js +194 -96
  160. package/src/client/components/core/EventBus.js +92 -0
  161. package/src/client/components/core/EventsUI.js +14 -17
  162. package/src/client/components/core/FileExplorer.js +96 -228
  163. package/src/client/components/core/FullScreen.js +47 -75
  164. package/src/client/components/core/Input.js +24 -69
  165. package/src/client/components/core/Keyboard.js +26 -19
  166. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  167. package/src/client/components/core/LoadingAnimation.js +25 -31
  168. package/src/client/components/core/LogIn.js +43 -43
  169. package/src/client/components/core/LogOut.js +25 -16
  170. package/src/client/components/core/Modal.js +462 -179
  171. package/src/client/components/core/NotificationManager.js +14 -18
  172. package/src/client/components/core/Panel.js +54 -51
  173. package/src/client/components/core/PanelForm.js +44 -144
  174. package/src/client/components/core/Polyhedron.js +110 -214
  175. package/src/client/components/core/PublicProfile.js +39 -32
  176. package/src/client/components/core/Recover.js +48 -44
  177. package/src/client/components/core/Responsive.js +88 -32
  178. package/src/client/components/core/RichText.js +9 -18
  179. package/src/client/components/core/Router.js +24 -3
  180. package/src/client/components/core/SearchBox.js +37 -37
  181. package/src/client/components/core/SignUp.js +39 -30
  182. package/src/client/components/core/SocketIo.js +112 -30
  183. package/src/client/components/core/SocketIoHandler.js +75 -0
  184. package/src/client/components/core/Stream.js +143 -95
  185. package/src/client/components/core/ToggleSwitch.js +8 -20
  186. package/src/client/components/core/ToolTip.js +5 -17
  187. package/src/client/components/core/Translate.js +56 -59
  188. package/src/client/components/core/Validator.js +26 -16
  189. package/src/client/components/core/Wallet.js +15 -26
  190. package/src/client/components/core/Webhook.js +40 -7
  191. package/src/client/components/core/Worker.js +163 -27
  192. package/src/client/components/core/windowGetDimensions.js +7 -7
  193. package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +59 -59
  194. package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
  195. package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
  196. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +9 -7
  197. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +8 -6
  198. package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
  199. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
  200. package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
  201. package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
  202. package/src/client/components/cyberia/InstanceEngineCyberia.js +781 -0
  203. package/src/client/components/cyberia/MapEngineCyberia.js +1836 -2
  204. package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
  205. package/src/client/components/cyberia/ObjectLayerEngineModal.js +1220 -99
  206. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +252 -316
  207. package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +136 -103
  208. package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
  209. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +462 -32
  210. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
  211. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +9 -7
  212. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +8 -6
  213. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
  214. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
  215. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
  216. package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
  217. package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
  218. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -4
  219. package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +91 -91
  220. package/src/client/components/default/AppStoreDefault.js +5 -0
  221. package/src/client/components/default/CssDefault.js +12 -12
  222. package/src/client/components/default/LogInDefault.js +9 -7
  223. package/src/client/components/default/LogOutDefault.js +8 -6
  224. package/src/client/components/default/RouterDefault.js +47 -0
  225. package/src/client/components/default/SettingsDefault.js +4 -4
  226. package/src/client/components/default/SignUpDefault.js +6 -4
  227. package/src/client/components/default/SocketIoDefault.js +3 -51
  228. package/src/client/components/default/TranslateDefault.js +3 -3
  229. package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +59 -59
  230. package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
  231. package/src/client/components/itemledger/CssItemledger.js +15 -15
  232. package/src/client/components/itemledger/LogInItemledger.js +9 -7
  233. package/src/client/components/itemledger/LogOutItemledger.js +8 -6
  234. package/src/client/components/itemledger/RouterItemledger.js +38 -0
  235. package/src/client/components/itemledger/SettingsItemledger.js +4 -4
  236. package/src/client/components/itemledger/SignUpItemledger.js +6 -4
  237. package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
  238. package/src/client/components/itemledger/TranslateItemledger.js +3 -3
  239. package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +92 -92
  240. package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
  241. package/src/client/components/underpost/CssUnderpost.js +14 -14
  242. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
  243. package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
  244. package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
  245. package/src/client/components/underpost/LogInUnderpost.js +9 -7
  246. package/src/client/components/underpost/LogOutUnderpost.js +8 -6
  247. package/src/client/components/underpost/RouterUnderpost.js +45 -0
  248. package/src/client/components/underpost/SettingsUnderpost.js +4 -4
  249. package/src/client/components/underpost/SignUpUnderpost.js +6 -4
  250. package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
  251. package/src/client/components/underpost/TranslateUnderpost.js +4 -4
  252. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
  253. package/src/client/public/cyberia-docs/ARCHITECTURE.md +443 -0
  254. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +417 -0
  255. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +313 -0
  256. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +260 -0
  257. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
  258. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
  259. package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
  260. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
  261. package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
  262. package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
  263. package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
  264. package/src/client/services/core/core.service.js +35 -55
  265. package/src/client/services/crypto/crypto.service.js +8 -13
  266. package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
  267. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +99 -0
  268. package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
  269. package/src/client/services/cyberia-entity/cyberia-entity.service.js +99 -0
  270. package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
  271. package/src/client/services/cyberia-instance/cyberia-instance.service.js +116 -0
  272. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +99 -0
  273. package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
  274. package/src/client/services/cyberia-map/cyberia-map.service.js +120 -0
  275. package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
  276. package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
  277. package/src/client/services/default/default.management.js +159 -267
  278. package/src/client/services/default/default.service.js +10 -16
  279. package/src/client/services/document/document.service.js +14 -19
  280. package/src/client/services/file/file.service.js +8 -13
  281. package/src/client/services/instance/instance.management.js +6 -6
  282. package/src/client/services/instance/instance.service.js +10 -15
  283. package/src/client/services/ipfs/ipfs.service.js +14 -40
  284. package/src/client/services/object-layer/object-layer.management.js +14 -14
  285. package/src/client/services/object-layer/object-layer.service.js +39 -24
  286. package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
  287. package/src/client/services/test/test.service.js +8 -13
  288. package/src/client/services/user/guest.service.js +86 -0
  289. package/src/client/services/user/user.management.js +6 -6
  290. package/src/client/services/user/user.service.js +14 -20
  291. package/src/client/ssr/body/404.js +3 -3
  292. package/src/client/ssr/body/500.js +3 -3
  293. package/src/client/ssr/body/CacheControl.js +5 -2
  294. package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
  295. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
  296. package/src/client/ssr/head/PwaItemledger.js +197 -60
  297. package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
  298. package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
  299. package/src/client/ssr/offline/Maintenance.js +12 -11
  300. package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
  301. package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
  302. package/src/client/ssr/pages/Test.js +2 -2
  303. package/src/client/sw/core.sw.js +212 -0
  304. package/src/grpc/cyberia/grpc-server.js +642 -0
  305. package/src/index.js +24 -1
  306. package/src/runtime/cyberia-client/Dockerfile +80 -0
  307. package/src/runtime/cyberia-server/Dockerfile +37 -0
  308. package/src/runtime/express/Dockerfile +5 -1
  309. package/src/runtime/express/Express.js +18 -1
  310. package/src/runtime/lampp/Dockerfile +17 -5
  311. package/src/runtime/lampp/Lampp.js +27 -4
  312. package/src/runtime/wp/Dockerfile +62 -0
  313. package/src/runtime/wp/Wp.js +639 -0
  314. package/src/server/atlas-sprite-sheet-generator.js +4 -2
  315. package/src/server/auth.js +24 -1
  316. package/src/server/backup.js +37 -9
  317. package/src/server/client-build-docs.js +52 -46
  318. package/src/server/client-build.js +356 -82
  319. package/src/server/client-formatted.js +140 -57
  320. package/src/server/conf.js +29 -13
  321. package/src/server/cron.js +25 -23
  322. package/src/server/data-query.js +32 -20
  323. package/src/server/dns.js +24 -1
  324. package/src/server/ipfs-client.js +253 -89
  325. package/src/server/object-layer.js +150 -114
  326. package/src/server/peer.js +8 -0
  327. package/src/server/process.js +13 -27
  328. package/src/server/runtime.js +25 -1
  329. package/src/server/semantic-layer-generator-floor.js +319 -0
  330. package/src/server/semantic-layer-generator-resource.js +259 -0
  331. package/src/server/semantic-layer-generator-skin.js +1164 -0
  332. package/src/server/semantic-layer-generator.js +211 -542
  333. package/src/server/shape-generator.js +108 -0
  334. package/src/server/start.js +19 -5
  335. package/src/server/valkey.js +141 -235
  336. package/src/ws/IoInterface.js +1 -10
  337. package/src/ws/IoServer.js +14 -33
  338. package/src/ws/core/channels/core.ws.chat.js +65 -20
  339. package/src/ws/core/channels/core.ws.mailer.js +113 -32
  340. package/src/ws/core/channels/core.ws.stream.js +90 -31
  341. package/src/ws/core/core.ws.connection.js +12 -33
  342. package/src/ws/core/core.ws.emit.js +10 -26
  343. package/src/ws/core/core.ws.server.js +25 -58
  344. package/src/ws/default/channels/default.ws.main.js +53 -12
  345. package/src/ws/default/default.ws.connection.js +26 -13
  346. package/src/ws/default/default.ws.server.js +30 -12
  347. package/tsconfig.docs.json +15 -0
  348. package/typedoc.dd-cyberia.json +29 -0
  349. package/typedoc.json +29 -0
  350. package/WHITE-PAPER.md +0 -1540
  351. package/hardhat/README.md +0 -531
  352. package/hardhat/WHITE-PAPER.md +0 -1540
  353. package/jsdoc.dd-cyberia.json +0 -59
  354. package/jsdoc.json +0 -59
  355. package/src/api/object-layer/README.md +0 -347
  356. package/src/client/components/core/ColorPalette.js +0 -5267
  357. package/src/client/components/core/JoyStick.js +0 -80
  358. package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
  359. package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
  360. package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
  361. package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
  362. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -58
  363. package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
  364. package/src/client/components/default/ElementsDefault.js +0 -38
  365. package/src/client/components/default/RoutesDefault.js +0 -49
  366. package/src/client/components/itemledger/CommonItemledger.js +0 -29
  367. package/src/client/components/itemledger/ElementsItemledger.js +0 -38
  368. package/src/client/components/itemledger/RoutesItemledger.js +0 -40
  369. package/src/client/components/underpost/CommonUnderpost.js +0 -29
  370. package/src/client/components/underpost/ElementsUnderpost.js +0 -38
  371. package/src/client/components/underpost/RoutesUnderpost.js +0 -47
  372. package/src/client/sw/default.sw.js +0 -127
  373. package/src/client/sw/template.sw.js +0 -84
  374. package/src/ws/core/management/core.ws.chat.js +0 -8
  375. package/src/ws/core/management/core.ws.mailer.js +0 -16
  376. package/src/ws/core/management/core.ws.stream.js +0 -8
  377. package/src/ws/default/management/default.ws.main.js +0 -8
@@ -0,0 +1,642 @@
1
+ /**
2
+ * gRPC server for the Cyberia Engine data pipeline.
3
+ *
4
+ * Runs alongside Express on a separate port (default 50051).
5
+ * Provides read-only RPCs for the Go game server to fetch
6
+ * ObjectLayers, Instances, and Maps from MongoDB.
7
+ *
8
+ * @module src/grpc/cyberia/grpc-server.js
9
+ */
10
+
11
+ import * as grpc from '@grpc/grpc-js';
12
+ import * as protoLoader from '@grpc/proto-loader';
13
+ import crypto from 'crypto';
14
+ import path from 'path';
15
+ import { fileURLToPath } from 'url';
16
+ import { DataBaseProvider } from '../../db/DataBaseProvider.js';
17
+ import { loggerFactory } from '../../server/logger.js';
18
+ import {
19
+ CYBERIA_INSTANCE_CONF_DEFAULTS as FALLBACK_CONFIG_DEFAULTS,
20
+ ENTITY_TYPE_DEFAULTS,
21
+ STATUS_ICONS,
22
+ } from '../../api/cyberia-instance-conf/cyberia-instance-conf.defaults.js';
23
+ import { generateFallbackWorld } from '../../api/cyberia-instance/cyberia-fallback-world.js';
24
+
25
+ const logger = loggerFactory(import.meta);
26
+
27
+ const __filename = fileURLToPath(import.meta.url);
28
+ const __dirname = path.dirname(__filename);
29
+
30
+ const PROTO_PATH = path.resolve(__dirname, '../../../cyberia-server/proto/cyberia.proto');
31
+
32
+ const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
33
+ keepCase: false,
34
+ longs: Number,
35
+ enums: String,
36
+ defaults: true,
37
+ oneofs: true,
38
+ });
39
+
40
+ const proto = grpc.loadPackageDefinition(packageDefinition).cyberia;
41
+
42
+ // ═══════════════════════════════════════════════════════════════════
43
+ // Helpers
44
+ // ═══════════════════════════════════════════════════════════════════
45
+
46
+ function getModels(dbKey) {
47
+ const bucket = DataBaseProvider.instance[dbKey];
48
+ if (!bucket || !bucket.mongoose || !bucket.mongoose.models) {
49
+ throw new Error(`DataBaseProvider not loaded for key "${dbKey}"`);
50
+ }
51
+ return bucket.mongoose.models;
52
+ }
53
+
54
+ function countSharedItemIds(source = [], target = []) {
55
+ if (!Array.isArray(source) || source.length === 0 || !Array.isArray(target) || target.length === 0) {
56
+ return 0;
57
+ }
58
+ const targetSet = new Set(target.filter(Boolean));
59
+ let count = 0;
60
+ for (const itemId of source) {
61
+ if (targetSet.has(itemId)) {
62
+ count += 1;
63
+ }
64
+ }
65
+ return count;
66
+ }
67
+
68
+ function normalizeEntityDefault(entityDefault = {}, canonical = {}) {
69
+ const defaultObjectLayers = entityDefault.defaultObjectLayers ?? canonical.defaultObjectLayers ?? [];
70
+ return {
71
+ entityType: entityDefault.entityType ?? canonical.entityType ?? '',
72
+ liveItemIds: [...(entityDefault.liveItemIds ?? canonical.liveItemIds ?? [])],
73
+ deadItemIds: [...(entityDefault.deadItemIds ?? canonical.deadItemIds ?? [])],
74
+ dropItemIds: [...(entityDefault.dropItemIds ?? canonical.dropItemIds ?? [])],
75
+ colorKey: entityDefault.colorKey ?? canonical.colorKey ?? '',
76
+ defaultObjectLayers: defaultObjectLayers.map((ol) => ({
77
+ itemId: ol.itemId || '',
78
+ active: !!ol.active,
79
+ quantity: ol.quantity || 0,
80
+ })),
81
+ };
82
+ }
83
+
84
+ function selectCanonicalEntityDefaultIndex(entityDefault, canonicalDefaults, usedIndexes) {
85
+ const pickBestIndex = (candidateIndexes) => {
86
+ let firstSameTypeIndex = -1;
87
+ let bestLiveOverlapIndex = -1;
88
+ let bestLiveOverlap = 0;
89
+ let bestLiveItemCount = Number.POSITIVE_INFINITY;
90
+
91
+ for (const index of candidateIndexes) {
92
+ const canonical = canonicalDefaults[index];
93
+ if (canonical.entityType !== entityDefault.entityType) {
94
+ continue;
95
+ }
96
+ if (firstSameTypeIndex === -1) {
97
+ firstSameTypeIndex = index;
98
+ }
99
+ if (entityDefault.colorKey && canonical.colorKey === entityDefault.colorKey) {
100
+ return index;
101
+ }
102
+
103
+ const liveOverlap = countSharedItemIds(entityDefault.liveItemIds, canonical.liveItemIds);
104
+ if (
105
+ liveOverlap > 0 &&
106
+ (bestLiveOverlapIndex === -1 ||
107
+ liveOverlap > bestLiveOverlap ||
108
+ (liveOverlap === bestLiveOverlap && (canonical.liveItemIds?.length ?? 0) < bestLiveItemCount))
109
+ ) {
110
+ bestLiveOverlapIndex = index;
111
+ bestLiveOverlap = liveOverlap;
112
+ bestLiveItemCount = canonical.liveItemIds?.length ?? 0;
113
+ }
114
+ }
115
+
116
+ if (bestLiveOverlapIndex !== -1) {
117
+ return bestLiveOverlapIndex;
118
+ }
119
+ return firstSameTypeIndex;
120
+ };
121
+
122
+ const unusedCandidateIndexes = canonicalDefaults.map((_, index) => index).filter((index) => !usedIndexes.has(index));
123
+
124
+ const preferredIndex = pickBestIndex(unusedCandidateIndexes);
125
+ if (preferredIndex !== -1) {
126
+ return preferredIndex;
127
+ }
128
+ return pickBestIndex(canonicalDefaults.map((_, index) => index));
129
+ }
130
+
131
+ function mergeEntityDefaults(entityDefaults = []) {
132
+ const mergedDefaults = ENTITY_TYPE_DEFAULTS.map((canonical) => normalizeEntityDefault(canonical, canonical));
133
+ const usedCanonicalIndexes = new Set();
134
+
135
+ for (const entityDefault of entityDefaults) {
136
+ const canonicalIndex = selectCanonicalEntityDefaultIndex(entityDefault, ENTITY_TYPE_DEFAULTS, usedCanonicalIndexes);
137
+ if (canonicalIndex === -1) {
138
+ mergedDefaults.push(normalizeEntityDefault(entityDefault));
139
+ continue;
140
+ }
141
+
142
+ mergedDefaults[canonicalIndex] = normalizeEntityDefault(entityDefault, ENTITY_TYPE_DEFAULTS[canonicalIndex]);
143
+ usedCanonicalIndexes.add(canonicalIndex);
144
+ }
145
+
146
+ return mergedDefaults;
147
+ }
148
+
149
+ // ── Mongoose doc → protobuf message converters ───────────────────
150
+
151
+ function toObjectLayerMsg(doc) {
152
+ const d = doc.data || {};
153
+ const item = d.item || {};
154
+ const stats = d.stats || {};
155
+ const ledger = d.ledger || {};
156
+ const render = d.render || {};
157
+ return {
158
+ mongoId: String(doc._id),
159
+ stats: {
160
+ effect: stats.effect || 0,
161
+ resistance: stats.resistance || 0,
162
+ agility: stats.agility || 0,
163
+ range: stats.range || 0,
164
+ intelligence: stats.intelligence || 0,
165
+ utility: stats.utility || 0,
166
+ },
167
+ item: {
168
+ id: item.id || '',
169
+ type: item.type || '',
170
+ description: item.description || '',
171
+ activable: !!item.activable,
172
+ },
173
+ ledger: {
174
+ type: ledger.type || 'OFF_CHAIN',
175
+ address: ledger.address || '',
176
+ tokenId: ledger.tokenId || '',
177
+ },
178
+ render: {
179
+ cid: render.cid || '',
180
+ metadataCid: render.metadataCid || '',
181
+ },
182
+ sha256: doc.sha256 || '',
183
+ cid: doc.cid || '',
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Parse a CSS rgba() colour string into {r, g, b, a} integer components.
189
+ * Returns {r:0, g:0, b:0, a:0} (transparent) when the string is absent or malformed.
190
+ */
191
+ function parseRgba(str) {
192
+ if (!str) return { r: 0, g: 0, b: 0, a: 0 };
193
+ const m = str.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/);
194
+ if (!m) return { r: 0, g: 0, b: 0, a: 0 };
195
+ // CSS alpha is 0-1 (float); proto uses 0-255 (int).
196
+ const cssAlpha = m[4] !== undefined ? parseFloat(m[4]) : 1;
197
+ return { r: Number(m[1]), g: Number(m[2]), b: Number(m[3]), a: Math.round(cssAlpha * 255) };
198
+ }
199
+
200
+ function toEntityMsg(ent) {
201
+ const rgba = parseRgba(ent.color);
202
+ return {
203
+ entityType: ent.entityType || 'floor',
204
+ initCellX: ent.initCellX || 0,
205
+ initCellY: ent.initCellY || 0,
206
+ dimX: ent.dimX || 1,
207
+ dimY: ent.dimY || 1,
208
+ color: ent.color || '',
209
+ objectLayerItemIds: ent.objectLayerItemIds || [],
210
+ spawnRadius: ent.spawnRadius || 0,
211
+ aggroRange: ent.aggroRange || 0,
212
+ maxLife: ent.maxLife || 0,
213
+ lifeRegen: ent.lifeRegen || 0,
214
+ portalSubtype: ent.portalSubtype || '',
215
+ colorR: rgba.r,
216
+ colorG: rgba.g,
217
+ colorB: rgba.b,
218
+ colorA: rgba.a,
219
+ };
220
+ }
221
+
222
+ function toMapMsg(doc) {
223
+ return {
224
+ mongoId: String(doc._id),
225
+ code: doc.code || '',
226
+ name: doc.name || '',
227
+ gridX: doc.gridX || 16,
228
+ gridY: doc.gridY || 16,
229
+ cellWidth: doc.cellWidth || 32,
230
+ cellHeight: doc.cellHeight || 32,
231
+ entities: (doc.entities || []).map(toEntityMsg),
232
+ };
233
+ }
234
+
235
+ function toInstanceMsg(doc) {
236
+ return {
237
+ mongoId: String(doc._id),
238
+ code: doc.code || '',
239
+ name: doc.name || '',
240
+ description: doc.description || '',
241
+ tags: doc.tags || [],
242
+ mapCodes: doc.cyberiaMapCodes || [],
243
+ portals: (doc.portals || []).map((p) => ({
244
+ sourceMapCode: p.sourceMapCode || '',
245
+ sourceCellX: p.sourceCellX || 0,
246
+ sourceCellY: p.sourceCellY || 0,
247
+ targetMapCode: p.targetMapCode || '',
248
+ targetCellX: p.targetCellX || 0,
249
+ targetCellY: p.targetCellY || 0,
250
+ portalMode: p.portalMode || 'inter-portal',
251
+ })),
252
+ topologyMode: doc.topologyMode || 'hybrid',
253
+ seed: doc.seed || '',
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Converts a CyberiaInstanceConf Mongoose document (or plain object) into
259
+ * a complete InstanceConfig proto message.
260
+ * Any field that is null/undefined in `gc` falls back to FALLBACK_CONFIG_DEFAULTS,
261
+ * so partial DB documents always produce a fully playable config.
262
+ */
263
+ function toInstanceConfig(gc) {
264
+ const fb = FALLBACK_CONFIG_DEFAULTS;
265
+ if (!gc) return buildFallbackConfig();
266
+
267
+ // Per-key merge: start with canonical defaults, overlay any DB-defined colours.
268
+ const dbColorMap = new Map((gc.colors || []).map((c) => [c.key, c]));
269
+ const colors = fb.colors.map((c) => {
270
+ const ov = dbColorMap.get(c.key);
271
+ return ov ? { key: c.key, r: ov.r ?? c.r, g: ov.g ?? c.g, b: ov.b ?? c.b, a: ov.a ?? c.a } : { ...c };
272
+ });
273
+ // Append any DB colours whose keys are absent from the canonical defaults.
274
+ for (const [key, c] of dbColorMap) {
275
+ if (!colors.some((fc) => fc.key === key)) {
276
+ colors.push({ key, r: c.r ?? 0, g: c.g ?? 0, b: c.b ?? 0, a: c.a ?? 255 });
277
+ }
278
+ }
279
+
280
+ // Merge entity defaults while preserving duplicate builds (for example,
281
+ // multiple resource or portal variants sharing the same entityType).
282
+ const gcDefaults = gc.entityDefaults && gc.entityDefaults.length > 0 ? gc.entityDefaults : [];
283
+ const entityDefaults = mergeEntityDefaults(gcDefaults);
284
+
285
+ return {
286
+ cellSize: gc.cellSize ?? fb.cellSize,
287
+ fps: gc.fps ?? fb.fps,
288
+ interpolationMs: gc.interpolationMs ?? fb.interpolationMs,
289
+ defaultObjWidth: gc.defaultObjWidth ?? fb.defaultObjWidth,
290
+ defaultObjHeight: gc.defaultObjHeight ?? fb.defaultObjHeight,
291
+ cameraSmoothing: gc.cameraSmoothing ?? fb.cameraSmoothing,
292
+ cameraZoom: gc.cameraZoom ?? fb.cameraZoom,
293
+ defaultWidthScreenFactor: gc.defaultWidthScreenFactor ?? fb.defaultWidthScreenFactor,
294
+ defaultHeightScreenFactor: gc.defaultHeightScreenFactor ?? fb.defaultHeightScreenFactor,
295
+ devUi: gc.devUi ?? fb.devUi,
296
+ colors,
297
+ aoiRadius: gc.aoiRadius ?? fb.aoiRadius,
298
+ portalHoldTimeMs: gc.portalHoldTimeMs ?? fb.portalHoldTimeMs,
299
+ portalSpawnRadius: gc.portalSpawnRadius ?? fb.portalSpawnRadius,
300
+ entityBaseSpeed: gc.entityBaseSpeed ?? fb.entityBaseSpeed,
301
+ entityBaseMaxLife: gc.entityBaseMaxLife ?? fb.entityBaseMaxLife,
302
+ entityBaseActionCooldownMs: gc.entityBaseActionCooldownMs ?? fb.entityBaseActionCooldownMs,
303
+ entityBaseMinActionCooldownMs: gc.entityBaseMinActionCooldownMs ?? fb.entityBaseMinActionCooldownMs,
304
+ botAggroRange: gc.botAggroRange ?? fb.botAggroRange,
305
+ defaultPlayerWidth: gc.defaultPlayerWidth ?? fb.defaultPlayerWidth,
306
+ defaultPlayerHeight: gc.defaultPlayerHeight ?? fb.defaultPlayerHeight,
307
+ playerBaseLifeRegenMin: gc.playerBaseLifeRegenMin ?? fb.playerBaseLifeRegenMin,
308
+ playerBaseLifeRegenMax: gc.playerBaseLifeRegenMax ?? fb.playerBaseLifeRegenMax,
309
+ sumStatsLimit: gc.sumStatsLimit ?? fb.sumStatsLimit,
310
+ maxActiveLayers: gc.maxActiveLayers ?? fb.maxActiveLayers,
311
+ initialLifeFraction: gc.initialLifeFraction ?? fb.initialLifeFraction,
312
+ respawnDurationMs: gc.respawnDurationMs ?? fb.respawnDurationMs,
313
+ collisionLifeLoss: gc.collisionLifeLoss ?? fb.collisionLifeLoss,
314
+ // Economy — Fountain & Sink (nested, mirrors EconomyRules proto message).
315
+ economyRules: {
316
+ botSpawnCoins: gc.economyRules?.botSpawnCoins ?? fb.economyRules.botSpawnCoins,
317
+ playerSpawnCoins: gc.economyRules?.playerSpawnCoins ?? fb.economyRules.playerSpawnCoins,
318
+ coinKillPercentVsBot: gc.economyRules?.coinKillPercentVsBot ?? fb.economyRules.coinKillPercentVsBot,
319
+ coinKillPercentVsPlayer: gc.economyRules?.coinKillPercentVsPlayer ?? fb.economyRules.coinKillPercentVsPlayer,
320
+ coinKillMinAmount: gc.economyRules?.coinKillMinAmount ?? fb.economyRules.coinKillMinAmount,
321
+ respawnCostPercent: gc.economyRules?.respawnCostPercent ?? fb.economyRules.respawnCostPercent,
322
+ portalFee: gc.economyRules?.portalFee ?? fb.economyRules.portalFee,
323
+ craftingFeePercent: gc.economyRules?.craftingFeePercent ?? fb.economyRules.craftingFeePercent,
324
+ },
325
+ lifeRegenChance: gc.lifeRegenChance ?? fb.lifeRegenChance,
326
+ maxChance: gc.maxChance ?? fb.maxChance,
327
+ entityDefaults,
328
+ skillConfig: (gc.skillConfig && gc.skillConfig.length > 0 ? gc.skillConfig : fb.skillConfig).map((sc) => ({
329
+ triggerItemId: sc.triggerItemId || '',
330
+ skills: (sc.skills || []).map((sk) => ({
331
+ logicEventId: sk.logicEventId || '',
332
+ name: sk.name || '',
333
+ description: sk.description || '',
334
+ summonedEntityItemId: sk.summonedEntityItemId || '',
335
+ })),
336
+ })),
337
+ skillRules: {
338
+ projectileSpawnChance: gc.skillRules?.projectileSpawnChance ?? fb.skillRules.projectileSpawnChance,
339
+ projectileLifetimeMs: gc.skillRules?.projectileLifetimeMs ?? fb.skillRules.projectileLifetimeMs,
340
+ projectileWidth: gc.skillRules?.projectileWidth ?? fb.skillRules.projectileWidth,
341
+ projectileHeight: gc.skillRules?.projectileHeight ?? fb.skillRules.projectileHeight,
342
+ projectileSpeedMultiplier: gc.skillRules?.projectileSpeedMultiplier ?? fb.skillRules.projectileSpeedMultiplier,
343
+ doppelgangerSpawnChance: gc.skillRules?.doppelgangerSpawnChance ?? fb.skillRules.doppelgangerSpawnChance,
344
+ doppelgangerLifetimeMs: gc.skillRules?.doppelgangerLifetimeMs ?? fb.skillRules.doppelgangerLifetimeMs,
345
+ doppelgangerSpawnRadius: gc.skillRules?.doppelgangerSpawnRadius ?? fb.skillRules.doppelgangerSpawnRadius,
346
+ doppelgangerInitialLifeFraction:
347
+ gc.skillRules?.doppelgangerInitialLifeFraction ?? fb.skillRules.doppelgangerInitialLifeFraction,
348
+ },
349
+ // Equipment rules — governs activation constraints (nested, mirrors EquipmentRules proto message).
350
+ equipmentRules: {
351
+ activeItemTypes: gc.equipmentRules?.activeItemTypes ?? fb.equipmentRules.activeItemTypes,
352
+ onePerType: gc.equipmentRules?.onePerType ?? fb.equipmentRules.onePerType,
353
+ requireSkin: gc.equipmentRules?.requireSkin ?? fb.equipmentRules.requireSkin,
354
+ },
355
+ // Status icon mapping — u8 ID → icon filename stem + border colour.
356
+ // Border colours come from the frozen STATUS_ICONS constant (canonical
357
+ // source of truth). DB entries may override iconId but borderColor is
358
+ // always canonical — the DB schema defaults are generic grey, not the
359
+ // actual per-status colours.
360
+ statusIcons: STATUS_ICONS.map((canon) => {
361
+ const dbEntry = (gc.statusIcons || []).find((s) => s.id === canon.id);
362
+ const bc = canon.borderColor || {};
363
+ return {
364
+ id: canon.id,
365
+ iconId: (dbEntry && dbEntry.iconId) || canon.iconId || '',
366
+ borderColorR: bc.r ?? 100,
367
+ borderColorG: bc.g ?? 100,
368
+ borderColorB: bc.b ?? 100,
369
+ borderColorA: bc.a ?? 200,
370
+ };
371
+ }),
372
+ };
373
+ }
374
+
375
+ /**
376
+ * Builds a minimal InstanceConfig with playable defaults.
377
+ * Derived from CYBERIA_INSTANCE_CONF_DEFAULTS (shared with the Mongoose model).
378
+ * Used when the requested instance does not exist in the database.
379
+ */
380
+ function buildFallbackConfig() {
381
+ return JSON.parse(JSON.stringify(FALLBACK_CONFIG_DEFAULTS));
382
+ }
383
+
384
+ // ═══════════════════════════════════════════════════════════════════
385
+ // RPC handler factory
386
+ // ═══════════════════════════════════════════════════════════════════
387
+
388
+ function buildHandlers(dbKey) {
389
+ return {
390
+ async ping(_call, callback) {
391
+ callback(null, { serverTimeMs: Date.now() });
392
+ },
393
+
394
+ // Server-streaming: streams all ObjectLayers
395
+ async getObjectLayerBatch(call) {
396
+ try {
397
+ const models = getModels(dbKey);
398
+ const filter = {};
399
+ if (call.request.itemTypeFilter) {
400
+ filter['data.item.type'] = call.request.itemTypeFilter;
401
+ }
402
+ const cursor = models.ObjectLayer.find(filter).lean().cursor();
403
+ for await (const doc of cursor) {
404
+ call.write(toObjectLayerMsg(doc));
405
+ }
406
+ call.end();
407
+ } catch (err) {
408
+ logger.error('getObjectLayerBatch:', err);
409
+ call.destroy(new Error(err.message));
410
+ }
411
+ },
412
+
413
+ async getObjectLayer(call, callback) {
414
+ try {
415
+ const models = getModels(dbKey);
416
+ const doc = await models.ObjectLayer.findOne({ 'data.item.id': call.request.itemId }).lean();
417
+ if (!doc)
418
+ return callback({ code: grpc.status.NOT_FOUND, message: `ObjectLayer "${call.request.itemId}" not found` });
419
+ callback(null, toObjectLayerMsg(doc));
420
+ } catch (err) {
421
+ logger.error('getObjectLayer:', err);
422
+ callback({ code: grpc.status.INTERNAL, message: err.message });
423
+ }
424
+ },
425
+
426
+ async getMapData(call, callback) {
427
+ try {
428
+ const models = getModels(dbKey);
429
+ const { mapCode, instanceCode } = call.request;
430
+ const doc = await models.CyberiaMap.findOne({ code: mapCode }).lean();
431
+ if (!doc) return callback({ code: grpc.status.NOT_FOUND, message: `Map "${mapCode}" not found` });
432
+
433
+ // Track which instance is serving each mapCode in real time.
434
+ // instanceCode is provided by the Go server in every GetMapData request.
435
+ if (instanceCode) {
436
+ models.GlobalMapCodeRegistry.findOneAndUpdate(
437
+ { mapCode },
438
+ { instanceCode, status: 'active' },
439
+ { upsert: true, returnDocument: 'after', timestamps: true },
440
+ ).catch((err) => logger.warn('getMapData registry update failed:', err.message));
441
+ }
442
+
443
+ callback(null, { map: toMapMsg(doc) });
444
+ } catch (err) {
445
+ logger.error('getMapData:', err);
446
+ callback({ code: grpc.status.INTERNAL, message: err.message });
447
+ }
448
+ },
449
+
450
+ async getFullInstance(call, callback) {
451
+ try {
452
+ const models = getModels(dbKey);
453
+ // Normalise empty instanceCode to the canonical fallback name.
454
+ const instanceCode = call.request.instanceCode || 'default';
455
+ const inst = await models.CyberiaInstance.findOne({ code: instanceCode }).populate('conf').lean();
456
+
457
+ // ── Fallback: instance not found → return a multi-map procedural world ──
458
+ if (!inst) {
459
+ logger.info(`Instance "${instanceCode}" not found — returning fallback world.`);
460
+ const world = generateFallbackWorld();
461
+ const fallbackConf = buildFallbackConfig();
462
+
463
+ // Collect all objectLayerItemIds from the generated maps so the
464
+ // Go server can resolve atlases at startup.
465
+ const fallbackItemIds = new Set();
466
+ for (const m of world.maps) {
467
+ for (const e of m.entities || []) {
468
+ for (const id of e.objectLayerItemIds || []) fallbackItemIds.add(id);
469
+ }
470
+ }
471
+ // Also include system OL items from entity defaults.
472
+ for (const d of fallbackConf.entityDefaults || []) {
473
+ for (const id of d.liveItemIds || []) fallbackItemIds.add(id);
474
+ for (const id of d.deadItemIds || []) fallbackItemIds.add(id);
475
+ for (const id of d.dropItemIds || []) fallbackItemIds.add(id);
476
+ for (const ol of d.defaultObjectLayers || []) {
477
+ if (ol.itemId) fallbackItemIds.add(ol.itemId);
478
+ }
479
+ }
480
+
481
+ const fallbackOlDocs = fallbackItemIds.size
482
+ ? await models.ObjectLayer.find({ 'data.item.id': { $in: [...fallbackItemIds] } }).lean()
483
+ : [];
484
+
485
+ callback(null, {
486
+ instance: toInstanceMsg({
487
+ _id: '',
488
+ code: 'fallback',
489
+ name: 'Fallback Instance',
490
+ description: 'Auto-generated procedural world (not persisted)',
491
+ tags: ['fallback', 'procedural'],
492
+ cyberiaMapCodes: world.instance.cyberiaMapCodes,
493
+ portals: world.portals,
494
+ topologyMode: 'procedural',
495
+ seed: instanceCode,
496
+ }),
497
+ maps: world.maps.map((m) => ({
498
+ mongoId: '',
499
+ code: m.code,
500
+ name: m.name,
501
+ gridX: m.gridX,
502
+ gridY: m.gridY,
503
+ cellWidth: m.cellWidth,
504
+ cellHeight: m.cellHeight,
505
+ entities: (m.entities || []).map(toEntityMsg),
506
+ })),
507
+ objectLayers: fallbackOlDocs.map(toObjectLayerMsg),
508
+ config: toInstanceConfig(fallbackConf),
509
+ version: 'fallback',
510
+ });
511
+ return;
512
+ }
513
+
514
+ // ── Instance found — load maps + entity OLs + config default OLs ──────
515
+ // `populate('conf')` returns null when the ObjectId ref is missing or
516
+ // orphaned (e.g. after a --conf import that preserved a stale _id).
517
+ // Fall back to a direct instanceCode lookup so aoiRadius and all other
518
+ // tuning fields are always read from the database, never silently
519
+ // replaced by FALLBACK_CONFIG_DEFAULTS.
520
+ let conf = inst.conf;
521
+ if (!conf) {
522
+ conf = await models.CyberiaInstanceConf.findOne({ instanceCode }).lean();
523
+ if (conf) {
524
+ logger.warn(
525
+ `getFullInstance: conf ref missing on instance "${instanceCode}" — resolved by instanceCode lookup`,
526
+ );
527
+ }
528
+ }
529
+ conf = conf || {};
530
+ const mapCodes = inst.cyberiaMapCodes || [];
531
+ const mapDocs = mapCodes.length ? await models.CyberiaMap.find({ code: { $in: mapCodes } }).lean() : [];
532
+
533
+ // Collect all item IDs referenced by map entities.
534
+ const itemIds = new Set();
535
+ for (const m of mapDocs) {
536
+ for (const e of m.entities || []) {
537
+ for (const id of e.objectLayerItemIds || []) itemIds.add(id);
538
+ }
539
+ }
540
+
541
+ // Include system OL items from BOTH canonical ENTITY_TYPE_DEFAULTS AND
542
+ // the DB conf so the Go server always caches all default atlases even if
543
+ // the DB doc has incomplete entityDefaults.
544
+ for (const d of [...ENTITY_TYPE_DEFAULTS, ...(conf.entityDefaults || [])]) {
545
+ for (const id of d.liveItemIds || []) itemIds.add(id);
546
+ for (const id of d.deadItemIds || []) itemIds.add(id);
547
+ for (const id of d.dropItemIds || []) itemIds.add(id);
548
+ for (const ol of d.defaultObjectLayers || []) {
549
+ if (ol.itemId) itemIds.add(ol.itemId);
550
+ }
551
+ }
552
+
553
+ const olDocs = itemIds.size
554
+ ? await models.ObjectLayer.find({ 'data.item.id': { $in: [...itemIds] } }).lean()
555
+ : [];
556
+
557
+ // Opaque version string from updatedAt timestamps — the Go server
558
+ // compares this to skip full world rebuilds when nothing changed.
559
+ const versionParts = [String(inst.updatedAt || inst._id)];
560
+ for (const m of mapDocs) versionParts.push(String(m.updatedAt || m._id));
561
+ if (conf.updatedAt) versionParts.push(String(conf.updatedAt));
562
+ const version = crypto.createHash('sha256').update(versionParts.join('|')).digest('hex');
563
+
564
+ callback(null, {
565
+ instance: toInstanceMsg(inst),
566
+ maps: mapDocs.map(toMapMsg),
567
+ objectLayers: olDocs.map(toObjectLayerMsg),
568
+ config: toInstanceConfig(conf),
569
+ version,
570
+ });
571
+ } catch (err) {
572
+ logger.error('getFullInstance:', err);
573
+ callback({ code: grpc.status.INTERNAL, message: err.message });
574
+ }
575
+ },
576
+
577
+ async getObjectLayerManifest(_call, callback) {
578
+ try {
579
+ const models = getModels(dbKey);
580
+ const docs = await models.ObjectLayer.find({}, { 'data.item.id': 1, sha256: 1 }).lean();
581
+ callback(null, {
582
+ entries: docs.map((d) => ({ itemId: d.data?.item?.id || '', sha256: d.sha256 || '' })),
583
+ });
584
+ } catch (err) {
585
+ logger.error('getObjectLayerManifest:', err);
586
+ callback({ code: grpc.status.INTERNAL, message: err.message });
587
+ }
588
+ },
589
+ };
590
+ }
591
+
592
+ // ═══════════════════════════════════════════════════════════════════
593
+ // Server lifecycle
594
+ // ═══════════════════════════════════════════════════════════════════
595
+
596
+ class GrpcServer {
597
+ static _server = null;
598
+
599
+ /**
600
+ * @param {Object} opts
601
+ * @param {string} opts.host - DataBaseProvider host key
602
+ * @param {string} opts.path - DataBaseProvider path key
603
+ * @param {number} [opts.port=50051]
604
+ */
605
+ static async start({ host, path: dbPath, port = 50051 } = {}) {
606
+ const dbKey = `${host}${dbPath}`;
607
+ const server = new grpc.Server({
608
+ 'grpc.max_send_message_length': 64 * 1024 * 1024,
609
+ 'grpc.max_receive_message_length': 16 * 1024 * 1024,
610
+ });
611
+
612
+ server.addService(proto.CyberiaDataService.service, buildHandlers(dbKey));
613
+
614
+ // gRPC runs over Kubernetes internal network (ClusterIP) — always insecure
615
+ const creds = grpc.ServerCredentials.createInsecure();
616
+
617
+ return new Promise((resolve, reject) => {
618
+ server.bindAsync(`0.0.0.0:${port}`, creds, (err) => {
619
+ if (err) {
620
+ logger.error('gRPC bind failed:', err);
621
+ return reject(err);
622
+ }
623
+ GrpcServer._server = server;
624
+ logger.info(`gRPC server listening on 0.0.0.0:${port}`);
625
+ resolve(server);
626
+ });
627
+ });
628
+ }
629
+
630
+ static async stop() {
631
+ if (!GrpcServer._server) return;
632
+ return new Promise((resolve) => {
633
+ GrpcServer._server.tryShutdown(() => {
634
+ GrpcServer._server = null;
635
+ logger.info('gRPC server stopped');
636
+ resolve();
637
+ });
638
+ });
639
+ }
640
+ }
641
+
642
+ export { GrpcServer };