cyberia 3.0.3 → 3.2.5

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 (296) hide show
  1. package/{.env.production → .env.example} +20 -4
  2. package/.github/workflows/engine-cyberia.cd.yml +43 -10
  3. package/.github/workflows/engine-cyberia.ci.yml +48 -26
  4. package/.github/workflows/ghpkg.ci.yml +5 -5
  5. package/.github/workflows/gitlab.ci.yml +1 -1
  6. package/.github/workflows/hardhat.ci.yml +82 -0
  7. package/.github/workflows/npmpkg.ci.yml +60 -14
  8. package/.github/workflows/publish.ci.yml +26 -7
  9. package/.github/workflows/publish.cyberia.ci.yml +5 -5
  10. package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -7
  11. package/.github/workflows/pwa-microservices-template-test.ci.yml +4 -4
  12. package/.github/workflows/release.cd.yml +14 -8
  13. package/.vscode/extensions.json +9 -8
  14. package/.vscode/settings.json +3 -2
  15. package/CHANGELOG.md +643 -1
  16. package/CLI-HELP.md +132 -57
  17. package/Dockerfile +4 -2
  18. package/README.md +347 -22
  19. package/WHITE-PAPER.md +1540 -0
  20. package/bin/build.js +21 -12
  21. package/bin/cyberia.js +2640 -106
  22. package/bin/deploy.js +258 -372
  23. package/bin/file.js +5 -1
  24. package/bin/index.js +2640 -106
  25. package/bin/vs.js +3 -3
  26. package/conf.js +169 -105
  27. package/deployment.yaml +236 -20
  28. package/hardhat/.env.example +31 -0
  29. package/hardhat/README.md +531 -0
  30. package/hardhat/WHITE-PAPER.md +1540 -0
  31. package/hardhat/contracts/ObjectLayerToken.sol +391 -0
  32. package/hardhat/deployments/.gitkeep +0 -0
  33. package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
  34. package/hardhat/hardhat.config.js +136 -0
  35. package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
  36. package/hardhat/networks/besu-object-layer.network.json +138 -0
  37. package/hardhat/package-lock.json +4323 -0
  38. package/hardhat/package.json +36 -0
  39. package/hardhat/scripts/deployObjectLayerToken.js +98 -0
  40. package/hardhat/test/ObjectLayerToken.js +592 -0
  41. package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
  42. package/hardhat/types/ethers-contracts/common.ts +92 -0
  43. package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
  44. package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
  45. package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
  46. package/hardhat/types/ethers-contracts/index.ts +6 -0
  47. package/jsdoc.dd-cyberia.json +68 -0
  48. package/jsdoc.json +65 -49
  49. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -4
  50. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +5 -4
  51. package/manifests/deployment/dd-cyberia-development/deployment.yaml +562 -0
  52. package/manifests/deployment/dd-cyberia-development/proxy.yaml +297 -0
  53. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
  54. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  55. package/manifests/deployment/dd-test-development/deployment.yaml +88 -74
  56. package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
  57. package/manifests/deployment/playwright/deployment.yaml +1 -1
  58. package/manifests/pv-pvc-dd.yaml +1 -1
  59. package/nodemon.json +1 -1
  60. package/package.json +60 -48
  61. package/proxy.yaml +118 -10
  62. package/pv-pvc.yaml +132 -0
  63. package/scripts/k3s-node-setup.sh +1 -1
  64. package/scripts/ports-ls.sh +2 -0
  65. package/scripts/rhel-grpc-setup.sh +56 -0
  66. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +47 -1
  67. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +17 -2
  68. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
  69. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +80 -7
  70. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
  71. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
  72. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
  73. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
  74. package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
  75. package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
  76. package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
  77. package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
  78. package/src/api/cyberia-instance/cyberia-fallback-world.js +368 -0
  79. package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
  80. package/src/api/cyberia-instance/cyberia-instance.model.js +84 -0
  81. package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
  82. package/src/api/cyberia-instance/cyberia-instance.service.js +191 -0
  83. package/src/api/cyberia-instance/cyberia-portal-connector.js +486 -0
  84. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
  85. package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +413 -0
  86. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +228 -0
  87. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
  88. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +42 -0
  89. package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
  90. package/src/api/cyberia-map/cyberia-map.model.js +30 -0
  91. package/src/api/cyberia-map/cyberia-map.router.js +40 -0
  92. package/src/api/cyberia-map/cyberia-map.service.js +74 -0
  93. package/src/api/document/document.service.js +1 -1
  94. package/src/api/file/file.controller.js +3 -1
  95. package/src/api/file/file.ref.json +18 -0
  96. package/src/api/file/file.service.js +28 -5
  97. package/src/api/ipfs/ipfs.controller.js +4 -25
  98. package/src/api/ipfs/ipfs.model.js +43 -34
  99. package/src/api/ipfs/ipfs.router.js +8 -13
  100. package/src/api/ipfs/ipfs.service.js +56 -104
  101. package/src/api/object-layer/README.md +347 -22
  102. package/src/api/object-layer/object-layer.controller.js +6 -2
  103. package/src/api/object-layer/object-layer.model.js +12 -8
  104. package/src/api/object-layer/object-layer.router.js +698 -42
  105. package/src/api/object-layer/object-layer.service.js +119 -37
  106. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
  107. package/src/api/user/user.router.js +10 -5
  108. package/src/api/user/user.service.js +15 -14
  109. package/src/cli/baremetal.js +6 -10
  110. package/src/cli/cloud-init.js +0 -3
  111. package/src/cli/cluster.js +7 -7
  112. package/src/cli/db.js +723 -857
  113. package/src/cli/deploy.js +215 -105
  114. package/src/cli/env.js +34 -5
  115. package/src/cli/fs.js +5 -4
  116. package/src/cli/image.js +0 -3
  117. package/src/cli/index.js +83 -15
  118. package/src/cli/kubectl.js +211 -0
  119. package/src/cli/monitor.js +5 -6
  120. package/src/cli/release.js +284 -0
  121. package/src/cli/repository.js +708 -62
  122. package/src/cli/run.js +371 -151
  123. package/src/cli/secrets.js +73 -2
  124. package/src/cli/ssh.js +1 -1
  125. package/src/cli/test.js +3 -3
  126. package/src/client/Cryptokoyn.index.js +3 -4
  127. package/src/client/CyberiaPortal.index.js +3 -4
  128. package/src/client/Default.index.js +3 -4
  129. package/src/client/Itemledger.index.js +4 -963
  130. package/src/client/Underpost.index.js +3 -4
  131. package/src/client/components/core/AgGrid.js +20 -5
  132. package/src/client/components/core/Alert.js +2 -2
  133. package/src/client/components/core/AppStore.js +69 -0
  134. package/src/client/components/core/CalendarCore.js +2 -2
  135. package/src/client/components/core/Content.js +22 -3
  136. package/src/client/components/core/Docs.js +30 -6
  137. package/src/client/components/core/DropDown.js +137 -17
  138. package/src/client/components/core/FileExplorer.js +71 -4
  139. package/src/client/components/core/Input.js +1 -1
  140. package/src/client/components/core/Keyboard.js +2 -2
  141. package/src/client/components/core/LogIn.js +2 -2
  142. package/src/client/components/core/LogOut.js +2 -2
  143. package/src/client/components/core/Modal.js +20 -7
  144. package/src/client/components/core/Panel.js +0 -1
  145. package/src/client/components/core/PanelForm.js +19 -19
  146. package/src/client/components/core/RichText.js +1 -2
  147. package/src/client/components/core/SocketIo.js +82 -29
  148. package/src/client/components/core/SocketIoHandler.js +75 -0
  149. package/src/client/components/core/Stream.js +143 -95
  150. package/src/client/components/core/Webhook.js +40 -7
  151. package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
  152. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +3 -3
  153. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +2 -2
  154. package/src/client/components/cryptokoyn/MenuCryptokoyn.js +3 -3
  155. package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
  156. package/src/client/components/cyberia/InstanceEngineCyberia.js +700 -0
  157. package/src/client/components/cyberia/MapEngineCyberia.js +1359 -2
  158. package/src/client/components/cyberia/ObjectLayerEngineModal.js +17 -6
  159. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +92 -54
  160. package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
  161. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +217 -30
  162. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
  163. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +3 -4
  164. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +2 -2
  165. package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +104 -9
  166. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +5 -0
  167. package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
  168. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
  169. package/src/client/components/default/AppStoreDefault.js +5 -0
  170. package/src/client/components/default/LogInDefault.js +3 -3
  171. package/src/client/components/default/LogOutDefault.js +2 -2
  172. package/src/client/components/default/MenuDefault.js +5 -5
  173. package/src/client/components/default/SocketIoDefault.js +3 -51
  174. package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
  175. package/src/client/components/itemledger/LogInItemledger.js +3 -3
  176. package/src/client/components/itemledger/LogOutItemledger.js +2 -2
  177. package/src/client/components/itemledger/MenuItemledger.js +3 -3
  178. package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
  179. package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
  180. package/src/client/components/underpost/CssUnderpost.js +59 -0
  181. package/src/client/components/underpost/LogInUnderpost.js +6 -3
  182. package/src/client/components/underpost/LogOutUnderpost.js +4 -2
  183. package/src/client/components/underpost/MenuUnderpost.js +104 -18
  184. package/src/client/components/underpost/RoutesUnderpost.js +2 -0
  185. package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
  186. package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
  187. package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
  188. package/src/client/public/cryptokoyn/microdata.json +85 -0
  189. package/src/client/public/cryptokoyn/site.webmanifest +57 -0
  190. package/src/client/public/cryptokoyn/sitemap +3 -3
  191. package/src/client/public/default/sitemap +3 -3
  192. package/src/client/public/itemledger/browserconfig.xml +2 -2
  193. package/src/client/public/itemledger/manifest.webmanifest +4 -4
  194. package/src/client/public/itemledger/microdata.json +71 -0
  195. package/src/client/public/itemledger/sitemap +3 -3
  196. package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
  197. package/src/client/public/test/sitemap +3 -3
  198. package/src/client/services/core/core.service.js +20 -8
  199. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +105 -0
  200. package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
  201. package/src/client/services/cyberia-entity/cyberia-entity.service.js +105 -0
  202. package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
  203. package/src/client/services/cyberia-instance/cyberia-instance.service.js +122 -0
  204. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +105 -0
  205. package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
  206. package/src/client/services/cyberia-map/cyberia-map.service.js +126 -0
  207. package/src/client/services/instance/instance.management.js +2 -2
  208. package/src/client/services/ipfs/ipfs.service.js +3 -23
  209. package/src/client/services/object-layer/object-layer.management.js +3 -3
  210. package/src/client/services/object-layer/object-layer.service.js +21 -0
  211. package/src/client/services/user/user.management.js +2 -2
  212. package/src/client/ssr/body/404.js +15 -11
  213. package/src/client/ssr/body/500.js +15 -11
  214. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  215. package/src/client/ssr/head/PwaItemledger.js +60 -0
  216. package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
  217. package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
  218. package/src/client/ssr/pages/Test.js +11 -10
  219. package/src/client.build.js +0 -3
  220. package/src/client.dev.js +0 -3
  221. package/src/db/DataBaseProvider.js +17 -2
  222. package/src/db/mariadb/MariaDB.js +14 -9
  223. package/src/db/mongo/MongooseDB.js +17 -1
  224. package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +305 -0
  225. package/src/grpc/cyberia/README.md +326 -0
  226. package/src/grpc/cyberia/grpc-server.js +530 -0
  227. package/src/index.js +24 -1
  228. package/src/proxy.js +0 -3
  229. package/src/runtime/express/Dockerfile +4 -0
  230. package/src/runtime/express/Express.js +33 -10
  231. package/src/runtime/lampp/Dockerfile +13 -2
  232. package/src/runtime/lampp/Lampp.js +33 -17
  233. package/src/runtime/wp/Dockerfile +68 -0
  234. package/src/runtime/wp/Wp.js +639 -0
  235. package/src/server/auth.js +36 -15
  236. package/src/server/backup.js +39 -12
  237. package/src/server/besu-genesis-generator.js +1630 -0
  238. package/src/server/client-build-docs.js +133 -17
  239. package/src/server/client-build-live.js +9 -18
  240. package/src/server/client-build.js +229 -101
  241. package/src/server/client-dev-server.js +14 -13
  242. package/src/server/client-formatted.js +109 -57
  243. package/src/server/conf.js +391 -164
  244. package/src/server/cron.js +27 -24
  245. package/src/server/dns.js +29 -12
  246. package/src/server/downloader.js +0 -2
  247. package/src/server/ipfs-client.js +24 -1
  248. package/src/server/logger.js +27 -9
  249. package/src/server/object-layer.js +217 -103
  250. package/src/server/peer.js +8 -2
  251. package/src/server/process.js +1 -50
  252. package/src/server/proxy.js +4 -8
  253. package/src/server/runtime.js +30 -9
  254. package/src/server/semantic-layer-generator-floor.js +359 -0
  255. package/src/server/semantic-layer-generator-skin.js +1294 -0
  256. package/src/server/semantic-layer-generator.js +116 -555
  257. package/src/server/ssr.js +0 -3
  258. package/src/server/start.js +19 -12
  259. package/src/server/tls.js +0 -2
  260. package/src/server.js +0 -4
  261. package/src/ws/IoInterface.js +1 -10
  262. package/src/ws/IoServer.js +14 -33
  263. package/src/ws/core/channels/core.ws.chat.js +65 -20
  264. package/src/ws/core/channels/core.ws.mailer.js +113 -32
  265. package/src/ws/core/channels/core.ws.stream.js +90 -31
  266. package/src/ws/core/core.ws.connection.js +12 -33
  267. package/src/ws/core/core.ws.emit.js +10 -26
  268. package/src/ws/core/core.ws.server.js +25 -58
  269. package/src/ws/default/channels/default.ws.main.js +53 -12
  270. package/src/ws/default/default.ws.connection.js +26 -13
  271. package/src/ws/default/default.ws.server.js +30 -12
  272. package/.env.development +0 -43
  273. package/.env.test +0 -43
  274. package/hardhat/contracts/CryptoKoyn.sol +0 -59
  275. package/hardhat/contracts/ItemLedger.sol +0 -73
  276. package/hardhat/contracts/Lock.sol +0 -34
  277. package/hardhat/hardhat.config.cjs +0 -45
  278. package/hardhat/ignition/modules/Lock.js +0 -18
  279. package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
  280. package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
  281. package/hardhat/scripts/deployItemledger.cjs +0 -25
  282. package/hardhat/test/Lock.js +0 -126
  283. package/hardhat/white-paper.md +0 -581
  284. package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
  285. package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
  286. package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
  287. package/src/client/components/default/ElementsDefault.js +0 -38
  288. package/src/client/components/itemledger/CommonItemledger.js +0 -29
  289. package/src/client/components/itemledger/ElementsItemledger.js +0 -38
  290. package/src/client/components/underpost/CommonUnderpost.js +0 -29
  291. package/src/client/components/underpost/ElementsUnderpost.js +0 -38
  292. package/src/ws/core/management/core.ws.chat.js +0 -8
  293. package/src/ws/core/management/core.ws.mailer.js +0 -16
  294. package/src/ws/core/management/core.ws.stream.js +0 -8
  295. package/src/ws/default/management/default.ws.main.js +0 -8
  296. package/white-paper.md +0 -581
@@ -46,7 +46,7 @@ const ObjectLayerService = {
46
46
  * - Default — Create an object layer directly from the request body.
47
47
  *
48
48
  * The `/metadata` and default routes delegate to {@link ObjectLayerEngine.createObjectLayerDocuments}
49
- * for centralized document creation, atlas generation, SHA-256 computation, and IPFS pinning.
49
+ * for document creation, atlas generation, SHA-256 computation, and IPFS pinning.
50
50
  *
51
51
  * @async
52
52
  * @function post
@@ -148,7 +148,7 @@ const ObjectLayerService = {
148
148
  fs.writeFileSync(`${folder}/metadata.json`, metadataContent);
149
149
  fs.writeFileSync(`${publicFolder}/metadata.json`, metadataContent);
150
150
 
151
- // Build object layer data from the asset directory using centralized logic
151
+ // Build object layer data from the asset directory
152
152
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
153
153
  const ObjectLayerRenderFrames =
154
154
  DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
@@ -161,7 +161,6 @@ const ObjectLayerService = {
161
161
  metadataOverride: req.body,
162
162
  });
163
163
 
164
- // Create documents using centralized engine method (with atlas generation)
165
164
  const { objectLayer } = await ObjectLayerEngine.createObjectLayerDocuments({
166
165
  ObjectLayer,
167
166
  ObjectLayerRenderFrames,
@@ -183,29 +182,66 @@ const ObjectLayerService = {
183
182
  return objectLayer;
184
183
  }
185
184
 
186
- // create object layer from body
185
+ // create object layer from body – cut-over consistency: stage all CIDs before writing to DB
187
186
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
188
187
  const ObjectLayerRenderFrames =
189
188
  DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
190
- let newObjectLayer = await new ObjectLayer(req.body).save();
191
189
 
192
- // 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
193
224
  try {
194
- await AtlasSpriteSheetService.generate({ params: { id: newObjectLayer._id }, auth: req.auth }, res, options);
195
- } catch (atlasError) {
196
- 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);
197
234
  }
198
235
 
199
- // Re-read so data.render.cid is up-to-date, then recompute SHA-256 & IPFS CID
200
- newObjectLayer = await ObjectLayer.findById(newObjectLayer._id).populate('objectLayerRenderFramesId');
201
- if (newObjectLayer) {
202
- newObjectLayer = await ObjectLayerEngine.computeAndSaveFinalSha256({
203
- objectLayer: newObjectLayer,
204
- ipfsClient: IpfsClient,
205
- createPinRecord,
206
- userId: req.auth && req.auth.user ? req.auth.user._id : undefined,
207
- options,
208
- });
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');
209
245
  }
210
246
 
211
247
  return newObjectLayer;
@@ -236,6 +272,22 @@ const ObjectLayerService = {
236
272
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
237
273
  const ObjectLayer = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayer;
238
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
+
239
291
  // GET /frame-counts/:id - Get frame counts for each direction using numeric codes
240
292
  if (req.path.startsWith('/frame-counts/')) {
241
293
  const objectLayer = await ObjectLayer.findById(req.params.id)
@@ -519,7 +571,7 @@ const ObjectLayerService = {
519
571
  * - `/:id` — Standard update from request body.
520
572
  *
521
573
  * The `/metadata` route delegates to {@link ObjectLayerEngine.updateObjectLayerDocuments}
522
- * for centralized document update, atlas regeneration, SHA-256 computation, and IPFS pinning.
574
+ * for document update, atlas regeneration, SHA-256 computation, and IPFS pinning.
523
575
  *
524
576
  * @async
525
577
  * @function put
@@ -636,7 +688,7 @@ const ObjectLayerService = {
636
688
  const ObjectLayerRenderFrames =
637
689
  DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.ObjectLayerRenderFrames;
638
690
 
639
- // Build object layer data from the asset directory using centralized logic
691
+ // Build object layer data from the asset directory
640
692
  const { objectLayerRenderFramesData, objectLayerData } =
641
693
  await ObjectLayerEngine.buildObjectLayerDataFromDirectory({
642
694
  folder,
@@ -645,7 +697,7 @@ const ObjectLayerService = {
645
697
  metadataOverride: req.body,
646
698
  });
647
699
 
648
- // Update documents using centralized engine method (with atlas generation)
700
+ // Update documents using engine method (with atlas generation)
649
701
  const { objectLayer } = await ObjectLayerEngine.updateObjectLayerDocuments({
650
702
  objectLayerId,
651
703
  ObjectLayer,
@@ -668,30 +720,60 @@ const ObjectLayerService = {
668
720
  return objectLayer;
669
721
  }
670
722
 
671
- // PUT /:id - Standard update
672
- let updatedObjectLayer = await ObjectLayer.findByIdAndUpdate(req.params.id, req.body, { new: true });
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 = {};
673
733
 
674
- if (updatedObjectLayer) {
675
- // 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) {
676
737
  try {
677
- 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;
678
751
  } catch (atlasError) {
679
752
  logger.error('Failed to auto-update atlas for ObjectLayer:', atlasError);
680
753
  }
754
+ }
681
755
 
682
- // Re-read so data.render.cid is up-to-date, then recompute SHA-256 & IPFS CID
683
- updatedObjectLayer = await ObjectLayer.findById(req.params.id).populate('objectLayerRenderFramesId');
684
- if (updatedObjectLayer) {
685
- updatedObjectLayer = await ObjectLayerEngine.computeAndSaveFinalSha256({
686
- objectLayer: updatedObjectLayer,
687
- ipfsClient: IpfsClient,
688
- createPinRecord,
689
- userId: req.auth && req.auth.user ? req.auth.user._id : undefined,
690
- options,
691
- });
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 });
692
767
  }
768
+ } catch (ipfsError) {
769
+ logger.warn('Failed to pin data JSON to IPFS:', ipfsError.message);
693
770
  }
694
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
+
695
777
  return updatedObjectLayer;
696
778
  },
697
779
 
@@ -77,12 +77,11 @@ const ObjectLayerRenderFramesSchema = new Schema(
77
77
  );
78
78
 
79
79
  // Pre-save hook to ensure data consistency
80
- ObjectLayerRenderFramesSchema.pre('save', function (next) {
80
+ ObjectLayerRenderFramesSchema.pre('save', function () {
81
81
  // Ensure all required fields are present
82
82
  if (!this.frames || !this.colors || this.frame_duration === undefined) {
83
83
  throw new Error('Missing required fields: frames, colors, or frame_duration');
84
84
  }
85
- next();
86
85
  });
87
86
 
88
87
  // Create and export the model
@@ -30,12 +30,15 @@ const UserRouter = (options) => {
30
30
  emailConfirmed: true,
31
31
  publicKey: [],
32
32
  });
33
- logger.warn('Default admin user created. Please change the default password immediately!', result._doc);
33
+ logger.warn('Default admin user created. Please change the default password immediately!', {
34
+ username: result._doc.username,
35
+ email: result._doc.email,
36
+ role: result._doc.role,
37
+ });
34
38
  }
35
39
  }
36
40
  } catch (error) {
37
- logger.error('Error checking/creating admin user');
38
- console.log(error);
41
+ logger.error('Error checking/creating admin user', { error: error.message });
39
42
  }
40
43
 
41
44
  // Cache mailer images
@@ -46,10 +49,12 @@ const UserRouter = (options) => {
46
49
  check: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-check.png`),
47
50
  avatar: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-default-avatar.png`),
48
51
  },
49
- header: (res) => {
52
+ header: (res, req) => {
50
53
  res.set('Cross-Origin-Resource-Policy', 'cross-origin');
51
- res.set('Access-Control-Allow-Origin', '*');
52
54
  res.set('Access-Control-Allow-Headers', '*');
55
+ if (req && req.headers && req.headers.origin) {
56
+ res.set('Access-Control-Allow-Origin', req.headers.origin);
57
+ } else res.setHeader('Access-Control-Allow-Origin', '*');
53
58
  res.set('Content-Type', 'image/png');
54
59
  },
55
60
  };
@@ -13,8 +13,7 @@ import {
13
13
  validatePasswordMiddleware,
14
14
  } from '../../server/auth.js';
15
15
  import { MailerProvider } from '../../mailer/MailerProvider.js';
16
- import { CoreWsMailerManagement } from '../../ws/core/management/core.ws.mailer.js';
17
- import { CoreWsEmit } from '../../ws/core/core.ws.emit.js';
16
+ import { CoreWsEmitter } from '../../ws/core/core.ws.emit.js';
18
17
  import { CoreWsMailerChannel } from '../../ws/core/channels/core.ws.mailer.js';
19
18
  import validator from 'validator';
20
19
  import { DataBaseProvider } from '../../db/DataBaseProvider.js';
@@ -265,7 +264,7 @@ const UserService = {
265
264
  }
266
265
 
267
266
  if (req.path.startsWith('/assets')) {
268
- options.png.header(res);
267
+ options.png.header(res, req);
269
268
  return options.png.buffer[req.params.id];
270
269
  }
271
270
 
@@ -281,7 +280,7 @@ const UserService = {
281
280
  payload = verifyJWT(req.params.id, options);
282
281
  } catch (error) {
283
282
  logger.error(error, { 'req.params.id': req.params.id });
284
- options.png.header(res);
283
+ options.png.header(res, req);
285
284
  return options.png.buffer['invalid-token'];
286
285
  }
287
286
  const user = await User.findOne({
@@ -294,10 +293,10 @@ const UserService = {
294
293
  { recoverTimeOut: new Date(+new Date() + 1000 * 60 * 15) },
295
294
  { runValidators: true },
296
295
  );
297
- options.png.header(res);
296
+ options.png.header(res, req);
298
297
  return options.png.buffer['recover'];
299
298
  } else {
300
- options.png.header(res);
299
+ options.png.header(res, req);
301
300
  return options.png.buffer['invalid-token'];
302
301
  }
303
302
  }
@@ -308,7 +307,7 @@ const UserService = {
308
307
  payload = verifyJWT(req.params.id, options);
309
308
  } catch (error) {
310
309
  logger.error(error, { 'req.params.id': req.params.id });
311
- options.png.header(res);
310
+ options.png.header(res, req);
312
311
  return options.png.buffer['invalid-token'];
313
312
  }
314
313
  const user = await User.findOne({
@@ -319,15 +318,17 @@ const UserService = {
319
318
  {
320
319
  const user = await User.findByIdAndUpdate(_id, { emailConfirmed: true }, { runValidators: true });
321
320
  }
322
- const userWsId = CoreWsMailerManagement.getUserWsId(`${options.host}${options.path}`, user._id.toString());
323
- CoreWsEmit(CoreWsMailerChannel.channel, CoreWsMailerChannel.client[userWsId], {
324
- status: 'email-confirmed',
325
- id: userWsId,
326
- });
327
- options.png.header(res);
321
+ const userWsId = CoreWsMailerChannel.getUserWsId(`${options.host}${options.path}`, user._id.toString());
322
+ if (userWsId && CoreWsMailerChannel.client[userWsId]) {
323
+ CoreWsEmitter.emit(CoreWsMailerChannel.channel, CoreWsMailerChannel.client[userWsId], {
324
+ status: 'email-confirmed',
325
+ id: userWsId,
326
+ });
327
+ }
328
+ options.png.header(res, req);
328
329
  return options.png.buffer['check'];
329
330
  } else {
330
- options.png.header(res);
331
+ options.png.header(res, req);
331
332
  return options.png.buffer['invalid-token'];
332
333
  }
333
334
  }
@@ -135,9 +135,6 @@ class UnderpostBaremetal {
135
135
  ) {
136
136
  let { ipAddress, hostname, ipFileServer, ipConfig, netmask, dnsServer } = options;
137
137
 
138
- // Load environment variables from .env file, overriding existing ones if present.
139
- dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
140
-
141
138
  // Determine the root path for npm and underpost.
142
139
  const npmRoot = getNpmRootPath();
143
140
  const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
@@ -1147,9 +1144,8 @@ rm -rf ${artifacts.join(' ')}`);
1147
1144
  machine: machine ? machine.system_id : null,
1148
1145
  });
1149
1146
 
1150
- const { discovery, machine: discoveredMachine } = await Underpost.baremetal.commissionMonitor(
1151
- commissionMonitorPayload,
1152
- );
1147
+ const { discovery, machine: discoveredMachine } =
1148
+ await Underpost.baremetal.commissionMonitor(commissionMonitorPayload);
1153
1149
  if (discoveredMachine) machine = discoveredMachine;
1154
1150
  }
1155
1151
  },
@@ -2494,10 +2490,10 @@ fi
2494
2490
  const discoverHostname = discovery.hostname
2495
2491
  ? discovery.hostname
2496
2492
  : discovery.mac_organization
2497
- ? discovery.mac_organization
2498
- : discovery.domain
2499
- ? discovery.domain
2500
- : `generic-host-${s4()}${s4()}`;
2493
+ ? discovery.mac_organization
2494
+ : discovery.domain
2495
+ ? discovery.domain
2496
+ : `generic-host-${s4()}${s4()}`;
2501
2497
 
2502
2498
  console.log(discoverHostname.bgBlue.bold.white);
2503
2499
  console.log('ip target:'.green + ipAddress, 'ip discovered:'.green + discovery.ip);
@@ -5,15 +5,12 @@
5
5
  * @namespace UnderpostCloudInit
6
6
  */
7
7
 
8
- import dotenv from 'dotenv';
9
8
  import { shellExec } from '../server/process.js';
10
9
  import fs from 'fs-extra';
11
10
  import { loggerFactory } from '../server/logger.js';
12
11
  import { getNpmRootPath } from '../server/conf.js';
13
12
  import Underpost from '../index.js';
14
13
 
15
- dotenv.config();
16
-
17
14
  const logger = loggerFactory(import.meta);
18
15
 
19
16
  /**
@@ -111,7 +111,7 @@ class UnderpostCluster {
111
111
  const npmRoot = getNpmRootPath();
112
112
  const underpostRoot = options.dev ? '.' : `${npmRoot}/underpost`;
113
113
 
114
- if (options.listPods) return console.table(Underpost.deploy.get(podName ?? undefined));
114
+ if (options.listPods) return console.table(Underpost.kubectl.get(podName ?? undefined));
115
115
  // Set default namespace if not specified
116
116
  if (!options.namespace) options.namespace = 'default';
117
117
 
@@ -146,10 +146,10 @@ class UnderpostCluster {
146
146
  }
147
147
 
148
148
  // Check if a cluster (Kind, Kubeadm, or K3s) is already initialized
149
- const alreadyKubeadmCluster = Underpost.deploy.get('calico-kube-controllers')[0];
150
- const alreadyKindCluster = Underpost.deploy.get('kube-apiserver-kind-control-plane')[0];
149
+ const alreadyKubeadmCluster = Underpost.kubectl.get('calico-kube-controllers')[0];
150
+ const alreadyKindCluster = Underpost.kubectl.get('kube-apiserver-kind-control-plane')[0];
151
151
  // K3s pods often contain 'svclb-traefik' in the kube-system namespace
152
- const alreadyK3sCluster = Underpost.deploy.get('svclb-traefik')[0];
152
+ const alreadyK3sCluster = Underpost.kubectl.get('svclb-traefik')[0];
153
153
 
154
154
  // --- Kubeadm/Kind/K3s Cluster Initialization ---
155
155
  if (!alreadyKubeadmCluster && !alreadyKindCluster && !alreadyK3sCluster) {
@@ -299,7 +299,7 @@ EOF
299
299
  members: [{ _id: 0, host: `${options.mongoDbHost}:27017` }],
300
300
  };
301
301
 
302
- const [pod] = Underpost.deploy.get(deploymentName);
302
+ const [pod] = Underpost.kubectl.get(deploymentName);
303
303
 
304
304
  shellExec(
305
305
  `sudo kubectl exec -i ${pod.NAME} -- mongo --quiet \
@@ -351,7 +351,7 @@ EOF
351
351
  }
352
352
 
353
353
  if (options.certManager) {
354
- if (!Underpost.deploy.get('cert-manager').find((p) => p.STATUS === 'Running')) {
354
+ if (!Underpost.kubectl.get('cert-manager').find((p) => p.STATUS === 'Running')) {
355
355
  shellExec(`helm repo add jetstack https://charts.jetstack.io --force-update`);
356
356
  shellExec(
357
357
  `helm install cert-manager jetstack/cert-manager \
@@ -641,7 +641,7 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
641
641
  const resources = {};
642
642
  const nodeName = node
643
643
  ? node
644
- : Underpost.deploy.get('kind-control-plane', 'node').length > 0
644
+ : Underpost.kubectl.get('kind-control-plane', 'node').length > 0
645
645
  ? 'kind-control-plane'
646
646
  : os.hostname();
647
647
  const info = shellExec(`kubectl describe node ${nodeName} | grep -E '(Allocatable:|Capacity:)' -A 6`, {