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
@@ -10,23 +10,43 @@
10
10
  * @module src/server/ipfs-client.js
11
11
  * @namespace IpfsClient
12
12
  */
13
-
14
13
  import stringify from 'fast-json-stable-stringify';
15
14
  import { loggerFactory } from './logger.js';
16
-
17
15
  const logger = loggerFactory(import.meta);
18
-
16
+ const DEFAULT_IPFS_HTTP_TIMEOUT_MS = Number(process.env.IPFS_HTTP_TIMEOUT_MS || 10000);
17
+ const getRequestTimeoutMs = (kind = 'kubo') => {
18
+ if (kind === 'cluster') {
19
+ return Number(process.env.IPFS_CLUSTER_TIMEOUT_MS || DEFAULT_IPFS_HTTP_TIMEOUT_MS);
20
+ }
21
+ if (kind === 'gateway') {
22
+ return Number(process.env.IPFS_GATEWAY_TIMEOUT_MS || DEFAULT_IPFS_HTTP_TIMEOUT_MS);
23
+ }
24
+ return Number(process.env.IPFS_KUBO_TIMEOUT_MS || DEFAULT_IPFS_HTTP_TIMEOUT_MS);
25
+ };
26
+ const fetchWithTimeout = async (url, options = {}, { kind = 'kubo', label = url } = {}) => {
27
+ const controller = new AbortController();
28
+ const timeoutMs = getRequestTimeoutMs(kind);
29
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
30
+ try {
31
+ return await fetch(url, { ...options, signal: controller.signal });
32
+ } catch (err) {
33
+ if (err.name === 'AbortError') {
34
+ throw new Error(`${label} timed out after ${timeoutMs}ms`);
35
+ }
36
+ throw err;
37
+ } finally {
38
+ clearTimeout(timeoutId);
39
+ }
40
+ };
19
41
  // ─────────────────────────────────────────────────────────
20
42
  // URL helpers
21
43
  // ─────────────────────────────────────────────────────────
22
-
23
44
  /**
24
45
  * Base URL of the Kubo RPC API (port 5001).
25
46
  * @returns {string}
26
47
  */
27
48
  const getIpfsApiUrl = () =>
28
49
  process.env.IPFS_API_URL || `http://${process.env.NODE_ENV === 'development' ? 'localhost' : 'ipfs-cluster'}:5001`;
29
-
30
50
  /**
31
51
  * Base URL of the IPFS Cluster REST API (port 9094).
32
52
  * @returns {string}
@@ -34,7 +54,6 @@ const getIpfsApiUrl = () =>
34
54
  const getClusterApiUrl = () =>
35
55
  process.env.IPFS_CLUSTER_API_URL ||
36
56
  `http://${process.env.NODE_ENV === 'development' ? 'localhost' : 'ipfs-cluster'}:9094`;
37
-
38
57
  /**
39
58
  * Base URL of the IPFS HTTP Gateway (port 8080).
40
59
  * @returns {string}
@@ -42,17 +61,14 @@ const getClusterApiUrl = () =>
42
61
  const getGatewayUrl = () =>
43
62
  process.env.IPFS_GATEWAY_URL ||
44
63
  `http://${process.env.NODE_ENV === 'development' ? 'localhost' : 'ipfs-cluster'}:8080`;
45
-
46
64
  // ─────────────────────────────────────────────────────────
47
65
  // Core: add content
48
66
  // ─────────────────────────────────────────────────────────
49
-
50
67
  /**
51
68
  * @typedef {Object} IpfsAddResult
52
69
  * @property {string} cid – CID (Content Identifier) returned by the node.
53
70
  * @property {number} size – Cumulative DAG size reported by the node.
54
71
  */
55
-
56
72
  /**
57
73
  * Add arbitrary bytes to the Kubo node AND pin them on the IPFS Cluster.
58
74
  *
@@ -70,27 +86,27 @@ const getGatewayUrl = () =>
70
86
  const addToIpfs = async (content, filename = 'data', mfsPath) => {
71
87
  const kuboUrl = getIpfsApiUrl();
72
88
  const clusterUrl = getClusterApiUrl();
73
-
74
89
  // Build multipart body using native FormData + Blob (Node ≥ 18).
75
90
  const buf = Buffer.isBuffer(content) ? content : Buffer.from(content, 'utf-8');
76
91
  const formData = new FormData();
77
92
  formData.append('file', new Blob([buf]), filename);
78
-
79
93
  // ── Step 1: add to Kubo ──────────────────────────────
80
94
  let cid;
81
95
  let size;
82
96
  try {
83
- const res = await fetch(`${kuboUrl}/api/v0/add?pin=true&cid-version=1`, {
84
- method: 'POST',
85
- body: formData,
86
- });
87
-
97
+ const res = await fetchWithTimeout(
98
+ `${kuboUrl}/api/v0/add?pin=true&cid-version=1`,
99
+ {
100
+ method: 'POST',
101
+ body: formData,
102
+ },
103
+ { kind: 'kubo', label: `IPFS Kubo add ${filename}` },
104
+ );
88
105
  if (!res.ok) {
89
106
  const text = await res.text();
90
107
  logger.error(`IPFS Kubo add failed (${res.status}): ${text}`);
91
108
  return null;
92
109
  }
93
-
94
110
  const json = await res.json();
95
111
  cid = json.Hash;
96
112
  size = Number(json.Size);
@@ -99,13 +115,15 @@ const addToIpfs = async (content, filename = 'data', mfsPath) => {
99
115
  logger.warn(`IPFS Kubo node unreachable at ${kuboUrl}: ${err.message}`);
100
116
  return null;
101
117
  }
102
-
103
118
  // ── Step 2: pin to the Cluster ───────────────────────
104
119
  try {
105
- const clusterRes = await fetch(`${clusterUrl}/pins/${encodeURIComponent(cid)}`, {
106
- method: 'POST',
107
- });
108
-
120
+ const clusterRes = await fetchWithTimeout(
121
+ `${clusterUrl}/pins/${encodeURIComponent(cid)}`,
122
+ {
123
+ method: 'POST',
124
+ },
125
+ { kind: 'cluster', label: `IPFS Cluster pin ${cid}` },
126
+ );
109
127
  if (!clusterRes.ok) {
110
128
  const text = await clusterRes.text();
111
129
  logger.warn(`IPFS Cluster pin failed (${clusterRes.status}): ${text}`);
@@ -115,25 +133,30 @@ const addToIpfs = async (content, filename = 'data', mfsPath) => {
115
133
  } catch (err) {
116
134
  logger.warn(`IPFS Cluster unreachable at ${clusterUrl}: ${err.message}`);
117
135
  }
118
-
119
136
  // ── Step 3: copy into MFS so the Web UI "Files" section shows it ─
120
137
  const destPath = mfsPath || `/pinned/${filename}`;
121
138
  const destDir = destPath.substring(0, destPath.lastIndexOf('/')) || '/';
122
139
  try {
123
140
  // Ensure parent directory exists in MFS
124
- await fetch(`${kuboUrl}/api/v0/files/mkdir?arg=${encodeURIComponent(destDir)}&parents=true`, { method: 'POST' });
125
-
141
+ await fetchWithTimeout(
142
+ `${kuboUrl}/api/v0/files/mkdir?arg=${encodeURIComponent(destDir)}&parents=true`,
143
+ { method: 'POST' },
144
+ { kind: 'kubo', label: `IPFS MFS mkdir ${destDir}` },
145
+ );
126
146
  // Remove existing entry if present (cp fails on duplicates)
127
- await fetch(`${kuboUrl}/api/v0/files/rm?arg=${encodeURIComponent(destPath)}&force=true`, {
128
- method: 'POST',
129
- });
130
-
147
+ await fetchWithTimeout(
148
+ `${kuboUrl}/api/v0/files/rm?arg=${encodeURIComponent(destPath)}&force=true`,
149
+ {
150
+ method: 'POST',
151
+ },
152
+ { kind: 'kubo', label: `IPFS MFS rm ${destPath}` },
153
+ );
131
154
  // Copy the CID into MFS
132
- const cpRes = await fetch(
155
+ const cpRes = await fetchWithTimeout(
133
156
  `${kuboUrl}/api/v0/files/cp?arg=/ipfs/${encodeURIComponent(cid)}&arg=${encodeURIComponent(destPath)}`,
134
157
  { method: 'POST' },
158
+ { kind: 'kubo', label: `IPFS MFS cp ${destPath}` },
135
159
  );
136
-
137
160
  if (!cpRes.ok) {
138
161
  const text = await cpRes.text();
139
162
  logger.warn(`IPFS MFS cp failed (${cpRes.status}): ${text}`);
@@ -143,14 +166,11 @@ const addToIpfs = async (content, filename = 'data', mfsPath) => {
143
166
  } catch (err) {
144
167
  logger.warn(`IPFS MFS cp unreachable: ${err.message}`);
145
168
  }
146
-
147
169
  return { cid, size };
148
170
  };
149
-
150
171
  // ─────────────────────────────────────────────────────────
151
172
  // Convenience wrappers
152
173
  // ─────────────────────────────────────────────────────────
153
-
154
174
  /**
155
175
  * Add a JSON-serialisable object to IPFS.
156
176
  *
@@ -163,7 +183,52 @@ const addJsonToIpfs = async (obj, filename = 'data.json', mfsPath) => {
163
183
  const payload = stringify(obj);
164
184
  return addToIpfs(Buffer.from(payload, 'utf-8'), filename, mfsPath);
165
185
  };
166
-
186
+ /**
187
+ * Compute the CID that Kubo would assign to a payload without pinning or copying it into MFS.
188
+ * Useful when building canonical backup manifests from the actual bytes that will be restored later.
189
+ *
190
+ * @param {Buffer|string} content
191
+ * @param {string} [filename='data']
192
+ * @returns {Promise<IpfsAddResult|null>}
193
+ */
194
+ const hashContentForIpfs = async (content, filename = 'data') => {
195
+ const kuboUrl = getIpfsApiUrl();
196
+ const buf = Buffer.isBuffer(content) ? content : Buffer.from(content, 'utf-8');
197
+ const formData = new FormData();
198
+ formData.append('file', new Blob([buf]), filename);
199
+ try {
200
+ const res = await fetchWithTimeout(
201
+ `${kuboUrl}/api/v0/add?only-hash=true&pin=false&cid-version=1`,
202
+ {
203
+ method: 'POST',
204
+ body: formData,
205
+ },
206
+ { kind: 'kubo', label: `IPFS Kubo only-hash ${filename}` },
207
+ );
208
+ if (!res.ok) {
209
+ const text = await res.text();
210
+ logger.error(`IPFS Kubo only-hash failed (${res.status}): ${text}`);
211
+ return null;
212
+ }
213
+ const json = await res.json();
214
+ return { cid: json.Hash, size: Number(json.Size) };
215
+ } catch (err) {
216
+ logger.warn(`IPFS Kubo only-hash unreachable at ${kuboUrl}: ${err.message}`);
217
+ return null;
218
+ }
219
+ };
220
+ /**
221
+ * Compute the CID for a JSON-serialisable object using the same stable stringification
222
+ * that the regular addJsonToIpfs path uses.
223
+ *
224
+ * @param {any} obj
225
+ * @param {string} [filename='data.json']
226
+ * @returns {Promise<IpfsAddResult|null>}
227
+ */
228
+ const hashJsonForIpfs = async (obj, filename = 'data.json') => {
229
+ const payload = stringify(obj);
230
+ return hashContentForIpfs(Buffer.from(payload, 'utf-8'), filename);
231
+ };
167
232
  /**
168
233
  * Add a binary buffer (e.g. a PNG image) to IPFS.
169
234
  *
@@ -175,11 +240,19 @@ const addJsonToIpfs = async (obj, filename = 'data.json', mfsPath) => {
175
240
  const addBufferToIpfs = async (buffer, filename, mfsPath) => {
176
241
  return addToIpfs(buffer, filename, mfsPath);
177
242
  };
178
-
243
+ /**
244
+ * Compute the CID for a binary buffer without pinning it.
245
+ *
246
+ * @param {Buffer} buffer
247
+ * @param {string} filename
248
+ * @returns {Promise<IpfsAddResult|null>}
249
+ */
250
+ const hashBufferForIpfs = async (buffer, filename) => {
251
+ return hashContentForIpfs(buffer, filename);
252
+ };
179
253
  // ─────────────────────────────────────────────────────────
180
254
  // Pin management
181
255
  // ─────────────────────────────────────────────────────────
182
-
183
256
  /**
184
257
  * Explicitly pin an existing CID on both the Kubo node and the Cluster.
185
258
  *
@@ -191,12 +264,15 @@ const pinCid = async (cid, type = 'recursive') => {
191
264
  const kuboUrl = getIpfsApiUrl();
192
265
  const clusterUrl = getClusterApiUrl();
193
266
  let kuboOk = false;
194
-
195
267
  // Kubo pin
196
268
  try {
197
- const res = await fetch(`${kuboUrl}/api/v0/pin/add?arg=${encodeURIComponent(cid)}&type=${type}`, {
198
- method: 'POST',
199
- });
269
+ const res = await fetchWithTimeout(
270
+ `${kuboUrl}/api/v0/pin/add?arg=${encodeURIComponent(cid)}&type=${type}`,
271
+ {
272
+ method: 'POST',
273
+ },
274
+ { kind: 'kubo', label: `IPFS Kubo pin/add ${cid}` },
275
+ );
200
276
  if (!res.ok) {
201
277
  const text = await res.text();
202
278
  logger.error(`IPFS Kubo pin/add failed (${res.status}): ${text}`);
@@ -207,12 +283,15 @@ const pinCid = async (cid, type = 'recursive') => {
207
283
  } catch (err) {
208
284
  logger.warn(`IPFS Kubo pin unreachable: ${err.message}`);
209
285
  }
210
-
211
286
  // Cluster pin
212
287
  try {
213
- const clusterRes = await fetch(`${clusterUrl}/pins/${encodeURIComponent(cid)}`, {
214
- method: 'POST',
215
- });
288
+ const clusterRes = await fetchWithTimeout(
289
+ `${clusterUrl}/pins/${encodeURIComponent(cid)}`,
290
+ {
291
+ method: 'POST',
292
+ },
293
+ { kind: 'cluster', label: `IPFS Cluster pin ${cid}` },
294
+ );
216
295
  if (!clusterRes.ok) {
217
296
  const text = await clusterRes.text();
218
297
  logger.warn(`IPFS Cluster pin failed (${clusterRes.status}): ${text}`);
@@ -222,10 +301,8 @@ const pinCid = async (cid, type = 'recursive') => {
222
301
  } catch (err) {
223
302
  logger.warn(`IPFS Cluster pin unreachable: ${err.message}`);
224
303
  }
225
-
226
304
  return kuboOk;
227
305
  };
228
-
229
306
  /**
230
307
  * Unpin a CID from both the Kubo node and the Cluster.
231
308
  *
@@ -236,27 +313,37 @@ const unpinCid = async (cid) => {
236
313
  const kuboUrl = getIpfsApiUrl();
237
314
  const clusterUrl = getClusterApiUrl();
238
315
  let kuboOk = false;
239
-
240
316
  // Cluster unpin
241
317
  try {
242
- const clusterRes = await fetch(`${clusterUrl}/pins/${encodeURIComponent(cid)}`, {
243
- method: 'DELETE',
244
- });
318
+ const clusterRes = await fetchWithTimeout(
319
+ `${clusterUrl}/pins/${encodeURIComponent(cid)}`,
320
+ {
321
+ method: 'DELETE',
322
+ },
323
+ { kind: 'cluster', label: `IPFS Cluster unpin ${cid}` },
324
+ );
245
325
  if (!clusterRes.ok) {
246
326
  const text = await clusterRes.text();
247
- logger.warn(`IPFS Cluster unpin failed (${clusterRes.status}): ${text}`);
327
+ if (clusterRes.status === 404) {
328
+ logger.info(`IPFS Cluster unpin – CID already not pinned: ${cid}`);
329
+ } else {
330
+ logger.warn(`IPFS Cluster unpin failed (${clusterRes.status}): ${text}`);
331
+ }
248
332
  } else {
249
333
  logger.info(`IPFS Cluster unpin OK – CID: ${cid}`);
250
334
  }
251
335
  } catch (err) {
252
336
  logger.warn(`IPFS Cluster unpin unreachable: ${err.message}`);
253
337
  }
254
-
255
338
  // Kubo unpin
256
339
  try {
257
- const res = await fetch(`${kuboUrl}/api/v0/pin/rm?arg=${encodeURIComponent(cid)}`, {
258
- method: 'POST',
259
- });
340
+ const res = await fetchWithTimeout(
341
+ `${kuboUrl}/api/v0/pin/rm?arg=${encodeURIComponent(cid)}`,
342
+ {
343
+ method: 'POST',
344
+ },
345
+ { kind: 'kubo', label: `IPFS Kubo pin/rm ${cid}` },
346
+ );
260
347
  if (!res.ok) {
261
348
  const text = await res.text();
262
349
  // "not pinned or pinned indirectly" means the CID is already unpinned – treat as success
@@ -273,14 +360,11 @@ const unpinCid = async (cid) => {
273
360
  } catch (err) {
274
361
  logger.warn(`IPFS Kubo unpin unreachable: ${err.message}`);
275
362
  }
276
-
277
363
  return kuboOk;
278
364
  };
279
-
280
365
  // ─────────────────────────────────────────────────────────
281
366
  // Retrieval
282
367
  // ─────────────────────────────────────────────────────────
283
-
284
368
  /**
285
369
  * Retrieve raw bytes for a CID from the IPFS HTTP Gateway (port 8080).
286
370
  *
@@ -290,7 +374,14 @@ const unpinCid = async (cid) => {
290
374
  const getFromIpfs = async (cid) => {
291
375
  const url = getGatewayUrl();
292
376
  try {
293
- const res = await fetch(`${url}/ipfs/${encodeURIComponent(cid)}`);
377
+ const res = await fetchWithTimeout(
378
+ `${url}/ipfs/${encodeURIComponent(cid)}`,
379
+ {},
380
+ {
381
+ kind: 'gateway',
382
+ label: `IPFS gateway GET ${cid}`,
383
+ },
384
+ );
294
385
  if (!res.ok) {
295
386
  logger.error(`IPFS gateway GET failed (${res.status}) for ${cid}`);
296
387
  return null;
@@ -302,11 +393,9 @@ const getFromIpfs = async (cid) => {
302
393
  return null;
303
394
  }
304
395
  };
305
-
306
396
  // ─────────────────────────────────────────────────────────
307
397
  // Diagnostics
308
398
  // ─────────────────────────────────────────────────────────
309
-
310
399
  /**
311
400
  * List all pins tracked by the IPFS Cluster (port 9094).
312
401
  * Each line in the response is a JSON object with at least a `cid` field.
@@ -316,7 +405,14 @@ const getFromIpfs = async (cid) => {
316
405
  const listClusterPins = async () => {
317
406
  const clusterUrl = getClusterApiUrl();
318
407
  try {
319
- const res = await fetch(`${clusterUrl}/pins`);
408
+ const res = await fetchWithTimeout(
409
+ `${clusterUrl}/pins`,
410
+ {},
411
+ {
412
+ kind: 'cluster',
413
+ label: 'IPFS Cluster list pins',
414
+ },
415
+ );
320
416
  if (res.status === 204) {
321
417
  // 204 No Content → the cluster has no pins at all.
322
418
  return [];
@@ -344,7 +440,6 @@ const listClusterPins = async () => {
344
440
  return [];
345
441
  }
346
442
  };
347
-
348
443
  /**
349
444
  * List pins tracked by the local Kubo node (port 5001).
350
445
  *
@@ -354,9 +449,13 @@ const listClusterPins = async () => {
354
449
  const listKuboPins = async (type = 'recursive') => {
355
450
  const kuboUrl = getIpfsApiUrl();
356
451
  try {
357
- const res = await fetch(`${kuboUrl}/api/v0/pin/ls?type=${type}`, {
358
- method: 'POST',
359
- });
452
+ const res = await fetchWithTimeout(
453
+ `${kuboUrl}/api/v0/pin/ls?type=${type}`,
454
+ {
455
+ method: 'POST',
456
+ },
457
+ { kind: 'kubo', label: `IPFS Kubo pin/ls type=${type}` },
458
+ );
360
459
  if (!res.ok) {
361
460
  const text = await res.text();
362
461
  logger.error(`IPFS Kubo pin/ls failed (${res.status}): ${text}`);
@@ -369,11 +468,9 @@ const listKuboPins = async (type = 'recursive') => {
369
468
  return {};
370
469
  }
371
470
  };
372
-
373
471
  // ─────────────────────────────────────────────────────────
374
472
  // MFS management
375
473
  // ─────────────────────────────────────────────────────────
376
-
377
474
  /**
378
475
  * Remove a file or directory from the Kubo MFS (Mutable File System).
379
476
  * This cleans up entries visible in the IPFS Web UI "Files" section.
@@ -387,16 +484,20 @@ const removeMfsPath = async (mfsPath, recursive = true) => {
387
484
  const kuboUrl = getIpfsApiUrl();
388
485
  try {
389
486
  // First check if the path exists via stat; if it doesn't we can return early.
390
- const statRes = await fetch(`${kuboUrl}/api/v0/files/stat?arg=${encodeURIComponent(mfsPath)}`, { method: 'POST' });
487
+ const statRes = await fetchWithTimeout(
488
+ `${kuboUrl}/api/v0/files/stat?arg=${encodeURIComponent(mfsPath)}`,
489
+ { method: 'POST' },
490
+ { kind: 'kubo', label: `IPFS MFS stat ${mfsPath}` },
491
+ );
391
492
  if (!statRes.ok) {
392
493
  // Path doesn't exist – nothing to remove.
393
494
  logger.info(`IPFS MFS rm – path does not exist, skipping: ${mfsPath}`);
394
495
  return true;
395
496
  }
396
-
397
- const rmRes = await fetch(
497
+ const rmRes = await fetchWithTimeout(
398
498
  `${kuboUrl}/api/v0/files/rm?arg=${encodeURIComponent(mfsPath)}&force=true${recursive ? '&recursive=true' : ''}`,
399
499
  { method: 'POST' },
500
+ { kind: 'kubo', label: `IPFS MFS rm ${mfsPath}` },
400
501
  );
401
502
  if (!rmRes.ok) {
402
503
  const text = await rmRes.text();
@@ -410,24 +511,87 @@ const removeMfsPath = async (mfsPath, recursive = true) => {
410
511
  return false;
411
512
  }
412
513
  };
413
-
514
+ /**
515
+ * Restore a CID into the Kubo MFS at a specific path (e.g. when re-importing a backup).
516
+ * Creates the parent directory if needed, removes any existing entry, then copies the CID.
517
+ *
518
+ * @param {string} cid – IPFS CID to copy into MFS.
519
+ * @param {string} mfsPath – Full destination MFS path, e.g. `/object-layer/sword/sword_data.json`.
520
+ * @returns {Promise<boolean>} `true` when the MFS entry was created successfully.
521
+ */
522
+ const restoreMfsPath = async (cid, mfsPath) => {
523
+ const kuboUrl = getIpfsApiUrl();
524
+ const destDir = mfsPath.substring(0, mfsPath.lastIndexOf('/')) || '/';
525
+ try {
526
+ await fetchWithTimeout(
527
+ `${kuboUrl}/api/v0/files/mkdir?arg=${encodeURIComponent(destDir)}&parents=true`,
528
+ { method: 'POST' },
529
+ { kind: 'kubo', label: `IPFS MFS mkdir ${destDir}` },
530
+ );
531
+ await fetchWithTimeout(
532
+ `${kuboUrl}/api/v0/files/rm?arg=${encodeURIComponent(mfsPath)}&force=true`,
533
+ { method: 'POST' },
534
+ { kind: 'kubo', label: `IPFS MFS rm ${mfsPath}` },
535
+ );
536
+ const cpRes = await fetchWithTimeout(
537
+ `${kuboUrl}/api/v0/files/cp?arg=/ipfs/${encodeURIComponent(cid)}&arg=${encodeURIComponent(mfsPath)}`,
538
+ { method: 'POST' },
539
+ { kind: 'kubo', label: `IPFS MFS restore ${mfsPath}` },
540
+ );
541
+ if (!cpRes.ok) {
542
+ const text = await cpRes.text();
543
+ logger.warn(`IPFS MFS restore failed (${cpRes.status}): ${text} – ${mfsPath}`);
544
+ return false;
545
+ }
546
+ logger.info(`IPFS MFS restore OK – ${mfsPath} → ${cid}`);
547
+ return true;
548
+ } catch (err) {
549
+ logger.warn(`IPFS MFS restore unreachable: ${err.message}`);
550
+ return false;
551
+ }
552
+ };
414
553
  // ─────────────────────────────────────────────────────────
415
554
  // Export
416
555
  // ─────────────────────────────────────────────────────────
417
-
418
- const IpfsClient = {
419
- getIpfsApiUrl,
420
- getClusterApiUrl,
421
- getGatewayUrl,
422
- addToIpfs,
423
- addJsonToIpfs,
424
- addBufferToIpfs,
425
- pinCid,
426
- unpinCid,
427
- getFromIpfs,
428
- listClusterPins,
429
- listKuboPins,
430
- removeMfsPath,
431
- };
432
-
556
+ class IpfsClient {
557
+ static getIpfsApiUrl = getIpfsApiUrl;
558
+ static getClusterApiUrl = getClusterApiUrl;
559
+ static getGatewayUrl = getGatewayUrl;
560
+ static addToIpfs = addToIpfs;
561
+ static addJsonToIpfs = addJsonToIpfs;
562
+ static addBufferToIpfs = addBufferToIpfs;
563
+ static hashContentForIpfs = hashContentForIpfs;
564
+ static hashJsonForIpfs = hashJsonForIpfs;
565
+ static hashBufferForIpfs = hashBufferForIpfs;
566
+ static pinCid = pinCid;
567
+ static unpinCid = unpinCid;
568
+ static getFromIpfs = getFromIpfs;
569
+ static listClusterPins = listClusterPins;
570
+ static listKuboPins = listKuboPins;
571
+ static removeMfsPath = removeMfsPath;
572
+ static restoreMfsPath = restoreMfsPath;
573
+ /**
574
+ * Check whether a single CID is currently pinned on the local Kubo node.
575
+ * Uses the pin/ls?arg=<cid> endpoint which returns only that one pin
576
+ * (much cheaper than fetching the full list).
577
+ *
578
+ * @param {string} cid - IPFS Content Identifier to check.
579
+ * @returns {Promise<boolean>} true when the CID is pinned.
580
+ */
581
+ static isCidPinned = async (cid) => {
582
+ const kuboUrl = getIpfsApiUrl();
583
+ try {
584
+ const res = await fetchWithTimeout(
585
+ `${kuboUrl}/api/v0/pin/ls?arg=${encodeURIComponent(cid)}&type=all`,
586
+ { method: 'POST' },
587
+ { kind: 'kubo', label: `IPFS Kubo pin/ls ${cid}` },
588
+ );
589
+ if (!res.ok) return false;
590
+ const json = await res.json();
591
+ return !!(json.Keys && json.Keys[cid]);
592
+ } catch {
593
+ return false;
594
+ }
595
+ };
596
+ }
433
597
  export { IpfsClient };