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
@@ -36,7 +36,7 @@ const logger = loggerFactory(import.meta);
36
36
  * @namespace CyberiaObjectLayerService.ObjectLayerService
37
37
  * @memberof CyberiaObjectLayerService
38
38
  */
39
- const ObjectLayerService = {
39
+ class ObjectLayerService {
40
40
  /**
41
41
  * POST handler for creating object layers and uploading frame images.
42
42
  *
@@ -59,7 +59,7 @@ const ObjectLayerService = {
59
59
  * @returns {Promise<Object>} The created object layer document or frame upload result.
60
60
  * @throws {Error} If file validation fails or required parameters are missing.
61
61
  */
62
- post: async (req, res, options) => {
62
+ static post = async (req, res, options) => {
63
63
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
64
64
 
65
65
  if (req.path.startsWith('/frame-image')) {
@@ -182,33 +182,70 @@ const ObjectLayerService = {
182
182
  return objectLayer;
183
183
  }
184
184
 
185
- // create object layer from body
185
+ // create object layer from body – cut-over consistency: stage all CIDs before writing to DB
186
186
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
187
187
  const ObjectLayerRenderFrames =
188
188
  DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
189
- let newObjectLayer = await new ObjectLayer(req.body).save();
190
189
 
191
- // Generate atlas sprite sheet – this sets data.render.cid and saves
190
+ const bodyData = { ...req.body };
191
+ if (!bodyData.data) bodyData.data = {};
192
+ if (!bodyData.data.render) bodyData.data.render = {};
193
+ bodyData.data.render.cid = '';
194
+ bodyData.data.render.metadataCid = '';
195
+
196
+ // If has render frames, generate atlas + CIDs BEFORE creating the ObjectLayer
197
+ if (bodyData.objectLayerRenderFramesId) {
198
+ const renderFramesDoc = await ObjectLayerRenderFrames.findById(bodyData.objectLayerRenderFramesId);
199
+ if (renderFramesDoc) {
200
+ try {
201
+ const stagingOL = {
202
+ data: bodyData.data,
203
+ objectLayerRenderFramesId: renderFramesDoc,
204
+ };
205
+ const result = await AtlasSpriteSheetService.generate(
206
+ { objectLayer: stagingOL, auth: req.auth },
207
+ res,
208
+ options,
209
+ { skipObjectLayerSave: true },
210
+ );
211
+ bodyData.data.render.cid = result.atlasCid;
212
+ bodyData.data.render.metadataCid = result.atlasMetadataCid;
213
+ bodyData.atlasSpriteSheetId = result.atlasDoc._id;
214
+ } catch (atlasError) {
215
+ logger.error('Failed to auto-generate atlas for new ObjectLayer:', atlasError);
216
+ }
217
+ }
218
+ }
219
+
220
+ // Compute final SHA-256 with all CIDs
221
+ bodyData.sha256 = ObjectLayerEngine.computeSha256(bodyData.data);
222
+
223
+ // Pin data JSON to IPFS
192
224
  try {
193
- await AtlasSpriteSheetService.generate({ params: { id: newObjectLayer._id }, auth: req.auth }, res, options);
194
- } catch (atlasError) {
195
- logger.error('Failed to auto-generate atlas for new ObjectLayer:', atlasError);
225
+ const itemId = bodyData.data.item.id;
226
+ const mfsPath = `/object-layer/${itemId}/${itemId}_data.json`;
227
+ const ipfsResult = await IpfsClient.addJsonToIpfs(bodyData.data, `${itemId}_data.json`, mfsPath);
228
+ if (ipfsResult) {
229
+ bodyData.cid = ipfsResult.cid;
230
+ await createPinRecord({ cid: ipfsResult.cid, resourceType: 'object-layer-data', mfsPath, options });
231
+ }
232
+ } catch (ipfsError) {
233
+ logger.warn('Failed to pin data JSON to IPFS:', ipfsError.message);
196
234
  }
197
235
 
198
- // Re-read so data.render.cid is up-to-date, then recompute SHA-256 & IPFS CID
199
- newObjectLayer = await ObjectLayer.findById(newObjectLayer._id).populate('objectLayerRenderFramesId');
200
- if (newObjectLayer) {
201
- newObjectLayer = await ObjectLayerEngine.computeAndSaveFinalSha256({
202
- objectLayer: newObjectLayer,
203
- ipfsClient: IpfsClient,
204
- createPinRecord,
205
- userId: req.auth && req.auth.user ? req.auth.user._id : undefined,
206
- options,
207
- });
236
+ // Atomic create/replace ObjectLayer is fully populated with all CIDs
237
+ let newObjectLayer;
238
+ const existingByItemId = await ObjectLayer.findOne({ 'data.item.id': bodyData.data.item.id });
239
+ if (existingByItemId) {
240
+ newObjectLayer = await ObjectLayer.findByIdAndUpdate(existingByItemId._id, bodyData, {
241
+ returnDocument: 'after',
242
+ }).populate('objectLayerRenderFramesId');
243
+ } else {
244
+ newObjectLayer = await (await new ObjectLayer(bodyData).save()).populate('objectLayerRenderFramesId');
208
245
  }
209
246
 
210
247
  return newObjectLayer;
211
- },
248
+ };
212
249
 
213
250
  /**
214
251
  * GET handler for retrieving object layers.
@@ -231,10 +268,26 @@ const ObjectLayerService = {
231
268
  * @returns {Promise<Object>} The requested object layer data, list, or frame counts.
232
269
  * @throws {Error} If the requested object layer is not found.
233
270
  */
234
- get: async (req, res, options) => {
271
+ static get = async (req, res, options) => {
235
272
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
236
273
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
237
274
 
275
+ // GET /search-item-ids?q=<partial> - Fast partial match search on data.item.id
276
+ if (req.path.startsWith('/search-item-ids')) {
277
+ const q = (req.query.q || '').trim();
278
+ if (!q) return { itemIds: [] };
279
+ // Escape regex special characters for safe partial matching
280
+ const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
281
+ const results = await ObjectLayer.find(
282
+ { 'data.item.id': { $regex: escaped, $options: 'i' } },
283
+ { 'data.item.id': 1, _id: 0 },
284
+ )
285
+ .limit(20)
286
+ .lean();
287
+ const itemIds = [...new Set(results.map((r) => r.data.item.id))];
288
+ return { itemIds };
289
+ }
290
+
238
291
  // GET /frame-counts/:id - Get frame counts for each direction using numeric codes
239
292
  if (req.path.startsWith('/frame-counts/')) {
240
293
  const objectLayer = await ObjectLayer.findById(req.params.id)
@@ -379,7 +432,7 @@ const ObjectLayerService = {
379
432
  ObjectLayer.countDocuments(query), // { userId: req.auth.user._id }
380
433
  ]);
381
434
  return { data, total, page, totalPages: Math.ceil(total / limit) };
382
- },
435
+ };
383
436
 
384
437
  /**
385
438
  * Generates a WebP animation from PNG frame images for a specific direction of an object layer.
@@ -396,7 +449,7 @@ const ObjectLayerService = {
396
449
  * @returns {Promise<Buffer>} The generated WebP animation as a Buffer.
397
450
  * @throws {Error} If required parameters are missing, frames directory is not found, or img2webp fails.
398
451
  */
399
- generateWebp: async (req, res, options) => {
452
+ static generateWebp = async (req, res, options) => {
400
453
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
401
454
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
402
455
 
@@ -507,7 +560,7 @@ const ObjectLayerService = {
507
560
 
508
561
  throw error;
509
562
  }
510
- },
563
+ };
511
564
 
512
565
  /**
513
566
  * PUT handler for updating object layers, their frame images, and metadata.
@@ -531,7 +584,7 @@ const ObjectLayerService = {
531
584
  * @returns {Promise<Object>} The updated object layer document or frame upload result.
532
585
  * @throws {Error} If file validation fails, object layer is not found, or required parameters are missing.
533
586
  */
534
- put: async (req, res, options) => {
587
+ static put = async (req, res, options) => {
535
588
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
536
589
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
537
590
 
@@ -667,32 +720,62 @@ const ObjectLayerService = {
667
720
  return objectLayer;
668
721
  }
669
722
 
670
- // PUT /:id - Standard update
671
- let updatedObjectLayer = await ObjectLayer.findByIdAndUpdate(req.params.id, req.body, { returnDocument: 'after' });
723
+ // PUT /:id - Standard update with cut-over consistency
724
+ const existingOL = await ObjectLayer.findById(req.params.id).populate('objectLayerRenderFramesId');
725
+ if (!existingOL) {
726
+ throw new Error('ObjectLayer not found');
727
+ }
728
+
729
+ // Apply body updates to staging data in memory
730
+ const updateData = { ...req.body };
731
+ const stagingData = updateData.data || existingOL.data.toObject();
732
+ if (!stagingData.render) stagingData.render = {};
672
733
 
673
- if (updatedObjectLayer) {
674
- // Generate atlas sprite sheet – this sets data.render.cid and saves
734
+ // Use existing render frames if available
735
+ const renderFramesData = existingOL.objectLayerRenderFramesId;
736
+ if (renderFramesData) {
675
737
  try {
676
- await AtlasSpriteSheetService.generate({ params: { id: req.params.id }, auth: req.auth }, res, options);
738
+ const stagingOL = {
739
+ data: stagingData,
740
+ objectLayerRenderFramesId: renderFramesData,
741
+ };
742
+ const result = await AtlasSpriteSheetService.generate(
743
+ { objectLayer: stagingOL, auth: req.auth },
744
+ res,
745
+ options,
746
+ { skipObjectLayerSave: true },
747
+ );
748
+ stagingData.render.cid = result.atlasCid;
749
+ stagingData.render.metadataCid = result.atlasMetadataCid;
750
+ updateData.atlasSpriteSheetId = result.atlasDoc._id;
677
751
  } catch (atlasError) {
678
752
  logger.error('Failed to auto-update atlas for ObjectLayer:', atlasError);
679
753
  }
754
+ }
680
755
 
681
- // Re-read so data.render.cid is up-to-date, then recompute SHA-256 & IPFS CID
682
- updatedObjectLayer = await ObjectLayer.findById(req.params.id).populate('objectLayerRenderFramesId');
683
- if (updatedObjectLayer) {
684
- updatedObjectLayer = await ObjectLayerEngine.computeAndSaveFinalSha256({
685
- objectLayer: updatedObjectLayer,
686
- ipfsClient: IpfsClient,
687
- createPinRecord,
688
- userId: req.auth && req.auth.user ? req.auth.user._id : undefined,
689
- options,
690
- });
756
+ updateData.data = stagingData;
757
+ updateData.sha256 = ObjectLayerEngine.computeSha256(stagingData);
758
+
759
+ // Pin data JSON to IPFS
760
+ try {
761
+ const itemId = stagingData.item.id;
762
+ const mfsPath = `/object-layer/${itemId}/${itemId}_data.json`;
763
+ const ipfsResult = await IpfsClient.addJsonToIpfs(stagingData, `${itemId}_data.json`, mfsPath);
764
+ if (ipfsResult) {
765
+ updateData.cid = ipfsResult.cid;
766
+ await createPinRecord({ cid: ipfsResult.cid, resourceType: 'object-layer-data', mfsPath, options });
691
767
  }
768
+ } catch (ipfsError) {
769
+ logger.warn('Failed to pin data JSON to IPFS:', ipfsError.message);
692
770
  }
693
771
 
772
+ // Atomic update with all CIDs populated
773
+ let updatedObjectLayer = await ObjectLayer.findByIdAndUpdate(req.params.id, updateData, {
774
+ returnDocument: 'after',
775
+ }).populate('objectLayerRenderFramesId');
776
+
694
777
  return updatedObjectLayer;
695
- },
778
+ };
696
779
 
697
780
  /**
698
781
  * DELETE handler for removing object layers and all associated resources.
@@ -718,7 +801,7 @@ const ObjectLayerService = {
718
801
  * @returns {Promise<Object>} The deleted object layer document or bulk delete count.
719
802
  * @throws {Error} If the object layer is not found.
720
803
  */
721
- delete: async (req, res, options) => {
804
+ static delete = async (req, res, options) => {
722
805
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
723
806
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
724
807
  const ObjectLayerRenderFrames =
@@ -807,7 +890,7 @@ const ObjectLayerService = {
807
890
  }
808
891
  return { deletedCount: allObjectLayers.length };
809
892
  }
810
- },
811
- };
893
+ };
894
+ }
812
895
 
813
896
  export { ObjectLayerService };
@@ -3,8 +3,8 @@ import { ObjectLayerRenderFramesService } from './object-layer-render-frames.ser
3
3
 
4
4
  const logger = loggerFactory(import.meta);
5
5
 
6
- const ObjectLayerRenderFramesController = {
7
- post: async (req, res, options) => {
6
+ class ObjectLayerRenderFramesController {
7
+ static post = async (req, res, options) => {
8
8
  try {
9
9
  const result = await ObjectLayerRenderFramesService.post(req, res, options);
10
10
  return res.status(200).json({
@@ -18,8 +18,8 @@ const ObjectLayerRenderFramesController = {
18
18
  message: error.message,
19
19
  });
20
20
  }
21
- },
22
- get: async (req, res, options) => {
21
+ };
22
+ static get = async (req, res, options) => {
23
23
  try {
24
24
  const { page, limit } = req.query;
25
25
  const result = await ObjectLayerRenderFramesService.get(
@@ -38,8 +38,8 @@ const ObjectLayerRenderFramesController = {
38
38
  message: error.message,
39
39
  });
40
40
  }
41
- },
42
- put: async (req, res, options) => {
41
+ };
42
+ static put = async (req, res, options) => {
43
43
  try {
44
44
  const result = await ObjectLayerRenderFramesService.put(req, res, options);
45
45
  return res.status(200).json({
@@ -53,8 +53,8 @@ const ObjectLayerRenderFramesController = {
53
53
  message: error.message,
54
54
  });
55
55
  }
56
- },
57
- delete: async (req, res, options) => {
56
+ };
57
+ static delete = async (req, res, options) => {
58
58
  try {
59
59
  const result = await ObjectLayerRenderFramesService.delete(req, res, options);
60
60
  return res.status(200).json({
@@ -68,7 +68,7 @@ const ObjectLayerRenderFramesController = {
68
68
  message: error.message,
69
69
  });
70
70
  }
71
- },
72
- };
71
+ };
72
+ }
73
73
 
74
74
  export { ObjectLayerRenderFramesController };
@@ -3,9 +3,7 @@
3
3
  * @module src/api/object-layer-render-frames/object-layer-render-frames.model.js
4
4
  * @namespace CyberiaObjectLayerRenderFramesModel
5
5
  */
6
-
7
6
  import { Schema, model } from 'mongoose';
8
-
9
7
  /**
10
8
  * @typedef {Object} ObjectLayerRenderFramesDirections
11
9
  * @property {number[][][]} up_idle - Up idle animation frames
@@ -51,13 +49,11 @@ const ObjectLayerRenderFramesDirectionsSchema = new Schema(
51
49
  },
52
50
  { _id: false },
53
51
  );
54
-
55
52
  /**
56
53
  * @typedef {Object} ObjectLayerRenderFrames
57
54
  * @property {RenderFrames} frames - Animation frames for different states
58
55
  * @property {number[][]} colors - Color palette for rendering
59
56
  * @property {number} frame_duration - Duration of each frame in milliseconds
60
- * @property {boolean} is_stateless - Whether the render is stateless
61
57
  * @property {Date} createdAt - When the document was created
62
58
  * @property {Date} updatedAt - When the document was last updated
63
59
  * @memberof CyberiaObjectLayerRenderFramesModel
@@ -67,7 +63,6 @@ const ObjectLayerRenderFramesSchema = new Schema(
67
63
  frames: { type: ObjectLayerRenderFramesDirectionsSchema, required: true },
68
64
  colors: { type: [[Number]], required: true },
69
65
  frame_duration: { type: Number, required: true, min: 0 },
70
- is_stateless: { type: Boolean, default: false },
71
66
  },
72
67
  {
73
68
  timestamps: true,
@@ -75,7 +70,6 @@ const ObjectLayerRenderFramesSchema = new Schema(
75
70
  toObject: { virtuals: true },
76
71
  },
77
72
  );
78
-
79
73
  // Pre-save hook to ensure data consistency
80
74
  ObjectLayerRenderFramesSchema.pre('save', function () {
81
75
  // Ensure all required fields are present
@@ -83,21 +77,17 @@ ObjectLayerRenderFramesSchema.pre('save', function () {
83
77
  throw new Error('Missing required fields: frames, colors, or frame_duration');
84
78
  }
85
79
  });
86
-
87
80
  // Create and export the model
88
81
  const ObjectLayerRenderFramesModel = model('ObjectLayerRenderFrames', ObjectLayerRenderFramesSchema);
89
-
90
82
  const ProviderSchema = ObjectLayerRenderFramesSchema;
91
-
92
- const ObjectLayerRenderFramesDto = {
93
- select: {
83
+ class ObjectLayerRenderFramesDto {
84
+ static select = {
94
85
  get: () => {
95
- return { _id: 1, frame_duration: 1, is_stateless: 1 };
86
+ return { _id: 1, frame_duration: 1 };
96
87
  },
97
88
  getFull: () => {
98
- return { _id: 1, frames: 1, colors: 1, frame_duration: 1, is_stateless: 1 };
89
+ return { _id: 1, frames: 1, colors: 1, frame_duration: 1 };
99
90
  },
100
- },
101
- };
102
-
91
+ };
92
+ }
103
93
  export { ObjectLayerRenderFramesSchema, ObjectLayerRenderFramesModel, ProviderSchema, ObjectLayerRenderFramesDto };
@@ -4,15 +4,17 @@ import { DataQuery } from '../../server/data-query.js';
4
4
 
5
5
  const logger = loggerFactory(import.meta);
6
6
 
7
- const ObjectLayerRenderFramesService = {
8
- post: async (req, res, options) => {
7
+ class ObjectLayerRenderFramesService {
8
+ static post = async (req, res, options) => {
9
9
  /** @type {import('./object-layer-render-frames.model.js').ObjectLayerRenderFramesModel} */
10
- const ObjectLayerRenderFrames = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
10
+ const ObjectLayerRenderFrames =
11
+ DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
11
12
  return await new ObjectLayerRenderFrames(req.body).save();
12
- },
13
- get: async (req, res, options) => {
13
+ };
14
+ static get = async (req, res, options) => {
14
15
  /** @type {import('./object-layer-render-frames.model.js').ObjectLayerRenderFramesModel} */
15
- const ObjectLayerRenderFrames = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
16
+ const ObjectLayerRenderFrames =
17
+ DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
16
18
  if (req.params.id) return await ObjectLayerRenderFrames.findById(req.params.id);
17
19
 
18
20
  // Parse query parameters using DataQuery helper
@@ -25,18 +27,20 @@ const ObjectLayerRenderFramesService = {
25
27
 
26
28
  const totalPages = Math.ceil(total / limit);
27
29
  return { data, total, page, totalPages };
28
- },
29
- put: async (req, res, options) => {
30
+ };
31
+ static put = async (req, res, options) => {
30
32
  /** @type {import('./object-layer-render-frames.model.js').ObjectLayerRenderFramesModel} */
31
- const ObjectLayerRenderFrames = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
33
+ const ObjectLayerRenderFrames =
34
+ DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
32
35
  return await ObjectLayerRenderFrames.findByIdAndUpdate(req.params.id, req.body);
33
- },
34
- delete: async (req, res, options) => {
36
+ };
37
+ static delete = async (req, res, options) => {
35
38
  /** @type {import('./object-layer-render-frames.model.js').ObjectLayerRenderFramesModel} */
36
- const ObjectLayerRenderFrames = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
39
+ const ObjectLayerRenderFrames =
40
+ DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
37
41
  if (req.params.id) return await ObjectLayerRenderFrames.findByIdAndDelete(req.params.id);
38
42
  else return await ObjectLayerRenderFrames.deleteMany();
39
- },
40
- };
43
+ };
44
+ }
41
45
 
42
46
  export { ObjectLayerRenderFramesService };
@@ -3,8 +3,8 @@ import { TestService } from './test.service.js';
3
3
 
4
4
  const logger = loggerFactory(import.meta);
5
5
 
6
- const TestController = {
7
- post: async (req, res, options) => {
6
+ class TestController {
7
+ static post = async (req, res, options) => {
8
8
  try {
9
9
  return res.status(200).json({
10
10
  status: 'success',
@@ -17,8 +17,8 @@ const TestController = {
17
17
  message: error.message,
18
18
  });
19
19
  }
20
- },
21
- get: async (req, res, options) => {
20
+ };
21
+ static get = async (req, res, options) => {
22
22
  try {
23
23
  const result = await TestService.get(req, res, options);
24
24
  if (result)
@@ -37,8 +37,8 @@ const TestController = {
37
37
  message: error.message,
38
38
  });
39
39
  }
40
- },
41
- delete: async (req, res, options) => {
40
+ };
41
+ static delete = async (req, res, options) => {
42
42
  try {
43
43
  const result = await TestService.delete(req, res, options);
44
44
 
@@ -53,7 +53,7 @@ const TestController = {
53
53
  message: error.message,
54
54
  });
55
55
  }
56
- },
57
- };
56
+ };
57
+ }
58
58
 
59
59
  export { TestController };
@@ -5,14 +5,14 @@ import { getYouTubeID, validatePassword } from '../../client/components/core/Com
5
5
 
6
6
  const logger = loggerFactory(import.meta);
7
7
 
8
- const TestService = {
9
- post: async (req, res, options) => {
8
+ class TestService {
9
+ static post = async (req, res, options) => {
10
10
  switch (req.params.id) {
11
11
  default:
12
12
  break;
13
13
  }
14
- },
15
- get: async (req, res, options) => {
14
+ };
15
+ static get = async (req, res, options) => {
16
16
  switch (req.params.id) {
17
17
  case 'verify-email':
18
18
  return validator.isEmail(req.query.email);
@@ -23,13 +23,13 @@ const TestService = {
23
23
 
24
24
  default:
25
25
  }
26
- },
27
- delete: async (req, res, options) => {
26
+ };
27
+ static delete = async (req, res, options) => {
28
28
  switch (req.params.id) {
29
29
  default:
30
30
  break;
31
31
  }
32
- },
33
- };
32
+ };
33
+ }
34
34
 
35
35
  export { TestService };
@@ -0,0 +1,99 @@
1
+ import mongoose from 'mongoose';
2
+ import { UserDto } from './user.model.js';
3
+ import { ValkeyAPI } from '../../server/valkey.js';
4
+ import { hashPassword, getBearerToken, jwtSign } from '../../server/auth.js';
5
+
6
+ // ─── TTL ──────────────────────────────────────────────────────────────────────
7
+
8
+ const _guestTtlMs = () => {
9
+ const minutes = Number.parseInt(process.env.REFRESH_EXPIRE_MINUTES || '60', 10);
10
+ return Number.isFinite(minutes) && minutes > 0 ? minutes * 60 * 1000 : 60 * 60 * 1000;
11
+ };
12
+
13
+ // ─── Domain helpers ───────────────────────────────────────────────────────────
14
+
15
+ /**
16
+ * Constructs a new ephemeral guest user object.
17
+ * This is domain logic specific to the guest lifecycle; it does not belong
18
+ * in the generic Valkey storage module.
19
+ *
20
+ * @param {{ host?: string }} options
21
+ * @returns {object}
22
+ */
23
+ const buildGuestUser = (options) => {
24
+ const now = new Date().toISOString();
25
+ const _id = new mongoose.Types.ObjectId().toString();
26
+ const role = 'guest';
27
+ return {
28
+ _id: `${role}${_id}`,
29
+ username: `${role}${_id.slice(-5)}`,
30
+ email: `${_id}@${options.host || 'localhost'}`,
31
+ password: hashPassword(process.env.JWT_SECRET),
32
+ role,
33
+ emailConfirmed: false,
34
+ profileImageId: null,
35
+ publicKey: [],
36
+ phoneNumbers: [],
37
+ activeSessions: [],
38
+ failedLoginAttempts: 0,
39
+ recoverTimeOut: null,
40
+ lastLoginDate: null,
41
+ createdAt: now,
42
+ updatedAt: now,
43
+ guestSessionExpiresAt: Date.now() + _guestTtlMs(),
44
+ };
45
+ };
46
+
47
+ /**
48
+ * Projects a user object to the public-safe fields defined by UserDto.select.get().
49
+ * Keeps this logic next to the guest domain instead of in a generic utility.
50
+ *
51
+ * @param {object} user
52
+ * @returns {object}
53
+ */
54
+ const _toPublicUser = (user) => {
55
+ const select = UserDto.select.get();
56
+ return Object.fromEntries(
57
+ Object.keys(select)
58
+ .filter((k) => select[k] === 1 && k in user)
59
+ .map((k) => [k, user[k]]),
60
+ );
61
+ };
62
+
63
+ const _withRefreshedExpiry = (user) => ({ ...user, guestSessionExpiresAt: Date.now() + _guestTtlMs() });
64
+
65
+ // ─── Service ──────────────────────────────────────────────────────────────────
66
+
67
+ class GuestService {
68
+ static async create(req, options) {
69
+ const user = buildGuestUser(options);
70
+
71
+ await ValkeyAPI.set(options, user.email, user, _guestTtlMs());
72
+
73
+ return {
74
+ token: jwtSign(
75
+ UserDto.auth.payload(user, null, req.ip, req.headers['user-agent'], options.host, options.path),
76
+ options,
77
+ ),
78
+ user: _toPublicUser(user),
79
+ };
80
+ }
81
+
82
+ static async auth(req, options) {
83
+ const user = await ValkeyAPI.get(options, req.auth.user.email);
84
+ if (!user) throw new Error('guest user expired');
85
+
86
+ const expiresAt = Number(user.guestSessionExpiresAt || 0);
87
+ if (expiresAt && expiresAt <= Date.now()) throw new Error('guest user expired');
88
+
89
+ const refreshed = _withRefreshedExpiry(user);
90
+ await ValkeyAPI.set(options, refreshed.email, refreshed, _guestTtlMs());
91
+
92
+ return {
93
+ user: _toPublicUser(refreshed),
94
+ token: getBearerToken(req),
95
+ };
96
+ }
97
+ }
98
+
99
+ export { GuestService };
@@ -25,11 +25,11 @@ const handleRequest = (serviceMethod) => async (req, res, options) => {
25
25
  }
26
26
  };
27
27
 
28
- const UserController = {
29
- post: handleRequest(UserService.post),
30
- get: handleRequest(UserService.get),
31
- delete: handleRequest(UserService.delete),
32
- put: handleRequest(UserService.put),
33
- };
28
+ class UserController {
29
+ static post = handleRequest(UserService.post);
30
+ static get = handleRequest(UserService.get);
31
+ static delete = handleRequest(UserService.delete);
32
+ static put = handleRequest(UserService.put);
33
+ }
34
34
 
35
35
  export { UserController };