cyberia 3.2.12 → 3.2.70

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 (194) hide show
  1. package/.env.example +127 -68
  2. package/.github/workflows/cyberia-client.cd.yml +40 -0
  3. package/.github/workflows/cyberia-server.cd.yml +40 -0
  4. package/.github/workflows/docker-image.cyberia-client.ci.yml +49 -0
  5. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +48 -0
  6. package/.github/workflows/docker-image.cyberia-server.ci.yml +69 -0
  7. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +69 -0
  8. package/.github/workflows/docker-image.engine-cyberia.ci.yml +52 -0
  9. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +52 -0
  10. package/.github/workflows/engine-cyberia.cd.yml +34 -24
  11. package/.github/workflows/engine-cyberia.ci.yml +27 -5
  12. package/.github/workflows/ghpkg.ci.yml +89 -1
  13. package/.github/workflows/gitlab.ci.yml +1 -1
  14. package/.github/workflows/hardhat.ci.yml +1 -1
  15. package/.github/workflows/npmpkg.ci.yml +19 -12
  16. package/.github/workflows/publish.ci.yml +2 -2
  17. package/.github/workflows/publish.cyberia.ci.yml +5 -16
  18. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -8
  19. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  20. package/CHANGELOG.md +451 -1
  21. package/CLI-HELP.md +1040 -1130
  22. package/Dockerfile +141 -43
  23. package/Dockerfile.dev +143 -0
  24. package/Dockerfile.test +165 -0
  25. package/README.md +1 -1
  26. package/baremetal/commission-workflows.json +1 -0
  27. package/bin/build.js +128 -136
  28. package/bin/build.template.js +25 -179
  29. package/bin/cyberia.js +1089 -188
  30. package/bin/deploy.js +6 -3
  31. package/bin/index.js +1089 -188
  32. package/bump.config.js +1 -0
  33. package/compose.env +131 -0
  34. package/conf.js +19 -1
  35. package/deployment.yaml +74 -2
  36. package/docker-compose.yml +316 -0
  37. package/hardhat/hardhat.config.js +2 -2
  38. package/hardhat/package-lock.json +620 -2041
  39. package/hardhat/package.json +7 -5
  40. package/hardhat/scripts/deployObjectLayerToken.js +18 -18
  41. package/hardhat/test/ObjectLayerToken.js +378 -274
  42. package/ipfs/configure-ipfs.sh +13 -0
  43. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
  44. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  45. package/manifests/deployment/dd-cyberia-development/deployment.yaml +74 -2
  46. package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
  47. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +32 -0
  48. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  49. package/mongodb/entrypoint.sh +76 -0
  50. package/nginx.conf +87 -0
  51. package/package.json +34 -22
  52. package/pv-pvc.yaml +32 -0
  53. package/scripts/disk-clean.sh +85 -60
  54. package/scripts/kubeadm-node-setup.sh +317 -0
  55. package/scripts/link-local-underpost-cli.sh +6 -0
  56. package/scripts/rocky-kickstart.sh +877 -185
  57. package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
  58. package/scripts/test-monitor.sh +248 -0
  59. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +43 -7
  60. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +17 -25
  61. package/src/api/cyberia-action/cyberia-action.controller.js +19 -0
  62. package/src/api/cyberia-action/cyberia-action.model.js +21 -29
  63. package/src/api/cyberia-action/cyberia-action.router.js +42 -7
  64. package/src/api/cyberia-action/cyberia-action.service.js +20 -4
  65. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +58 -57
  66. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +37 -6
  67. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +8 -2
  68. package/src/api/cyberia-entity/cyberia-entity.router.js +39 -7
  69. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +74 -0
  70. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
  71. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +63 -0
  72. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
  73. package/src/api/cyberia-instance/cyberia-fallback-world.js +62 -10
  74. package/src/api/cyberia-instance/cyberia-instance.model.js +32 -2
  75. package/src/api/cyberia-instance/cyberia-instance.router.js +6 -6
  76. package/src/api/cyberia-instance/cyberia-world-generator.js +116 -3
  77. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +3 -0
  78. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +39 -7
  79. package/src/api/cyberia-map/cyberia-map.router.js +21 -6
  80. package/src/api/cyberia-quest/cyberia-quest.controller.js +38 -0
  81. package/src/api/cyberia-quest/cyberia-quest.router.js +47 -7
  82. package/src/api/cyberia-quest/cyberia-quest.service.js +59 -4
  83. package/src/api/cyberia-saga/cyberia-saga.controller.js +74 -0
  84. package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
  85. package/src/api/cyberia-saga/cyberia-saga.router.js +63 -0
  86. package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
  87. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +551 -122
  88. package/src/api/cyberia-skill/cyberia-skill.controller.js +74 -0
  89. package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
  90. package/src/api/cyberia-skill/cyberia-skill.router.js +63 -0
  91. package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
  92. package/src/api/ipfs/ipfs.service.js +28 -15
  93. package/src/api/object-layer/object-layer.router.js +25 -15
  94. package/src/api/object-layer/object-layer.service.js +15 -20
  95. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +39 -7
  96. package/src/cli/baremetal.js +717 -16
  97. package/src/cli/cluster.js +80 -5
  98. package/src/cli/deploy.js +326 -292
  99. package/src/cli/docker-compose.js +648 -0
  100. package/src/cli/env.js +12 -6
  101. package/src/cli/fs.js +75 -30
  102. package/src/cli/image.js +187 -55
  103. package/src/cli/index.js +157 -6
  104. package/src/cli/kickstart.js +142 -20
  105. package/src/cli/monitor.js +387 -6
  106. package/src/cli/release.js +72 -15
  107. package/src/cli/repository.js +339 -40
  108. package/src/cli/run.js +678 -186
  109. package/src/cli/secrets.js +82 -48
  110. package/src/cli/ssh.js +234 -0
  111. package/src/cli/static.js +2 -2
  112. package/src/client/components/core/PanelForm.js +44 -44
  113. package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
  114. package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
  115. package/src/client/components/cyberia/InstanceEngineCyberia.js +219 -13
  116. package/src/client/components/cyberia/MapEngineCyberia.js +154 -71
  117. package/src/client/components/cyberia/ObjectLayerEngineModal.js +40 -63
  118. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +34 -20
  119. package/src/client/components/cyberia/SharedDefaultsCyberia.js +195 -4
  120. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +66 -0
  121. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +8 -0
  122. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -0
  123. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +92 -20
  124. package/src/client/public/cyberia-docs/ARCHITECTURE.md +272 -50
  125. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +3 -3
  126. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +39 -22
  127. package/src/client/public/cyberia-docs/CYBERIA-LORE.md +88 -0
  128. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
  129. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +28 -12
  130. package/src/client/public/cyberia-docs/CYBERIA.md +1 -1
  131. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +27 -5
  132. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  133. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  134. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
  135. package/src/client/services/cyberia-instance/cyberia-instance.management.js +2 -2
  136. package/src/client/services/cyberia-map/cyberia-map.management.js +2 -2
  137. package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
  138. package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
  139. package/src/client/services/object-layer/object-layer.management.js +6 -6
  140. package/src/{server → client-builder}/client-build-docs.js +15 -5
  141. package/src/{server → client-builder}/client-build-live.js +3 -3
  142. package/src/{server → client-builder}/client-build.js +25 -22
  143. package/src/{server → client-builder}/client-dev-server.js +3 -3
  144. package/src/{server → client-builder}/client-icons.js +2 -2
  145. package/src/{server → client-builder}/ssr.js +5 -5
  146. package/src/client.build.js +1 -3
  147. package/src/client.dev.js +1 -1
  148. package/src/db/mongo/MongoBootstrap.js +12 -12
  149. package/src/db/mongo/MongooseDB.js +2 -1
  150. package/src/grpc/cyberia/grpc-server.js +255 -70
  151. package/src/index.js +12 -1
  152. package/src/mailer/EmailRender.js +1 -1
  153. package/src/{server → projects/cyberia}/atlas-sprite-sheet-generator.js +2 -2
  154. package/src/{server → projects/cyberia}/besu-genesis-generator.js +3 -3
  155. package/src/projects/cyberia/catalog-cyberia.js +81 -0
  156. package/src/projects/cyberia/gemini-client.js +175 -0
  157. package/src/projects/cyberia/generate-saga.js +2107 -0
  158. package/src/{server → projects/cyberia}/ipfs-client.js +6 -4
  159. package/src/{server → projects/cyberia}/object-layer.js +12 -108
  160. package/src/{server → projects/cyberia}/semantic-layer-generator-floor.js +1 -1
  161. package/src/{server → projects/cyberia}/semantic-layer-generator-resource.js +1 -1
  162. package/src/{server → projects/cyberia}/semantic-layer-generator-skin.js +1 -1
  163. package/src/{server → projects/cyberia}/semantic-layer-generator.js +2 -2
  164. package/src/{server → projects/cyberia}/shape-generator.js +2 -2
  165. package/src/projects/underpost/catalog-underpost.js +60 -0
  166. package/src/runtime/cyberia-client/Dockerfile +31 -83
  167. package/src/runtime/cyberia-client/Dockerfile.dev +23 -30
  168. package/src/runtime/cyberia-server/Dockerfile +23 -42
  169. package/src/runtime/cyberia-server/Dockerfile.dev +20 -35
  170. package/src/runtime/engine-cyberia/Dockerfile +143 -0
  171. package/src/runtime/engine-cyberia/Dockerfile.dev +143 -0
  172. package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
  173. package/src/runtime/engine-cyberia/compose.env +131 -0
  174. package/src/runtime/engine-cyberia/docker-compose.yml +316 -0
  175. package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
  176. package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
  177. package/src/runtime/engine-cyberia/nginx.conf +87 -0
  178. package/src/runtime/express/Express.js +2 -2
  179. package/src/runtime/nginx/Nginx.js +250 -0
  180. package/src/runtime/wp/Dockerfile +3 -3
  181. package/src/server/catalog.js +72 -0
  182. package/src/server/conf.js +415 -60
  183. package/src/server/runtime-status.js +252 -0
  184. package/src/server/start.js +42 -11
  185. package/src/server.js +6 -2
  186. package/test/cyberia-instance-conf-defaults.test.js +140 -0
  187. package/test/deploy-monitor.test.js +267 -0
  188. package/test/shape-generator.test.js +7 -1
  189. package/typedoc.dd-cyberia.json +3 -1
  190. package/typedoc.json +3 -1
  191. package/manifests/deployment/dd-test-development/deployment.yaml +0 -256
  192. package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
  193. /package/src/client/ssr/{Render.js → RootDocument.js} +0 -0
  194. /package/src/{server → client-builder}/client-formatted.js +0 -0
@@ -0,0 +1,74 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { CyberiaSkillService } from './cyberia-skill.service.js';
3
+
4
+ const logger = loggerFactory(import.meta);
5
+
6
+ class CyberiaSkillController {
7
+ static post = async (req, res, options) => {
8
+ try {
9
+ const result = await CyberiaSkillService.post(req, res, options);
10
+ return res.status(200).json({
11
+ status: 'success',
12
+ data: result,
13
+ });
14
+ } catch (error) {
15
+ logger.error(error, error.stack);
16
+ return res.status(400).json({
17
+ status: 'error',
18
+ message: error.message,
19
+ });
20
+ }
21
+ };
22
+ static get = async (req, res, options) => {
23
+ try {
24
+ const { page, limit } = req.query;
25
+ const result = await CyberiaSkillService.get(
26
+ { ...req, query: { ...req.query, page: parseInt(page), limit: parseInt(limit) } },
27
+ res,
28
+ options,
29
+ );
30
+ return res.status(200).json({
31
+ status: 'success',
32
+ data: result,
33
+ });
34
+ } catch (error) {
35
+ logger.error(error, error.stack);
36
+ return res.status(400).json({
37
+ status: 'error',
38
+ message: error.message,
39
+ });
40
+ }
41
+ };
42
+ static put = async (req, res, options) => {
43
+ try {
44
+ const result = await CyberiaSkillService.put(req, res, options);
45
+ return res.status(200).json({
46
+ status: 'success',
47
+ data: result,
48
+ });
49
+ } catch (error) {
50
+ logger.error(error, error.stack);
51
+ return res.status(400).json({
52
+ status: 'error',
53
+ message: error.message,
54
+ });
55
+ }
56
+ };
57
+ static delete = async (req, res, options) => {
58
+ try {
59
+ const result = await CyberiaSkillService.delete(req, res, options);
60
+ return res.status(200).json({
61
+ status: 'success',
62
+ data: result,
63
+ });
64
+ } catch (error) {
65
+ logger.error(error, error.stack);
66
+ return res.status(400).json({
67
+ status: 'error',
68
+ message: error.message,
69
+ });
70
+ }
71
+ };
72
+ }
73
+
74
+ export { CyberiaSkillController };
@@ -0,0 +1,50 @@
1
+ import { Schema, model } from 'mongoose';
2
+
3
+ // https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
4
+
5
+ // Expanded metadata for one logic event a trigger item can fire. Mirrors the
6
+ // `skills[]` entries in DefaultSkillConfig (cyberia-server-defaults.js) and the
7
+ // SkillDefinition consumed by cyberia-server (game/skill.go).
8
+ const SkillDefinitionSchema = new Schema(
9
+ {
10
+ // Handler key dispatched by the simulation skill engine (e.g. 'projectile',
11
+ // 'coin_drop_or_transaction', 'doppelganger').
12
+ logicEventId: { type: String, required: true, trim: true },
13
+ name: { type: String, default: '', trim: true },
14
+ description: { type: String, default: '' },
15
+ // ObjectLayer item id the skill summons. A leading '$' marks a runtime
16
+ // placeholder resolved by the server (e.g. '$active_skin').
17
+ summonedEntityItemId: { type: String, default: '', trim: true },
18
+ },
19
+ { _id: false },
20
+ );
21
+
22
+ /**
23
+ * Authoritative skill definition for a single trigger item. Owns the full skill
24
+ * record (logic event keys + expanded metadata) so the simulation receives the
25
+ * summoned-entity item ids the instance-conf skillConfig schema does not carry.
26
+ */
27
+ const CyberiaSkillSchema = new Schema(
28
+ {
29
+ // ObjectLayer item id whose active layer fires these skills (e.g. 'coin',
30
+ // 'atlas_pistol_mk2'). One skill document per trigger item. The unique
31
+ // index is declared via schema.index() below (not `unique: true` here) to
32
+ // avoid a duplicate-index definition.
33
+ triggerItemId: { type: String, required: true, trim: true },
34
+
35
+ // Compact list of handler keys — the discriminator the dispatcher matches.
36
+ logicEventIds: { type: [String], default: [] },
37
+
38
+ // Expanded per-logic-event metadata (name, description, summoned entity).
39
+ skills: { type: [SkillDefinitionSchema], default: [] },
40
+ },
41
+ { timestamps: true },
42
+ );
43
+
44
+ CyberiaSkillSchema.index({ triggerItemId: 1 }, { unique: true });
45
+
46
+ const CyberiaSkillModel = model('CyberiaSkill', CyberiaSkillSchema);
47
+
48
+ const ProviderSchema = CyberiaSkillSchema;
49
+
50
+ export { CyberiaSkillSchema, CyberiaSkillModel, ProviderSchema };
@@ -0,0 +1,63 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { CyberiaSkillController } from './cyberia-skill.controller.js';
3
+ import express from 'express';
4
+ import { moderatorGuard, adminGuard } from '../../server/auth.js';
5
+
6
+ const logger = loggerFactory(import.meta);
7
+
8
+ class CyberiaSkillRouter {
9
+ /**
10
+ * @param {import('../types.js').RouterOptions} options
11
+ * @returns {import('express').Router}
12
+ */
13
+ static router(options) {
14
+ const router = express.Router();
15
+ router.post(
16
+ `/:id`,
17
+ options.authMiddleware,
18
+ moderatorGuard,
19
+ async (req, res) => await CyberiaSkillController.post(req, res, options),
20
+ );
21
+ router.post(
22
+ `/`,
23
+ options.authMiddleware,
24
+ moderatorGuard,
25
+ async (req, res) => await CyberiaSkillController.post(req, res, options),
26
+ );
27
+ router.get(
28
+ `/:id`,
29
+ // options.authMiddleware,
30
+ async (req, res) => await CyberiaSkillController.get(req, res, options),
31
+ );
32
+ router.get(`/`, async (req, res) => await CyberiaSkillController.get(req, res, options));
33
+ router.put(
34
+ `/:id`,
35
+ options.authMiddleware,
36
+ moderatorGuard,
37
+ async (req, res) => await CyberiaSkillController.put(req, res, options),
38
+ );
39
+ router.put(
40
+ `/`,
41
+ options.authMiddleware,
42
+ moderatorGuard,
43
+ async (req, res) => await CyberiaSkillController.put(req, res, options),
44
+ );
45
+ router.delete(
46
+ `/:id`,
47
+ options.authMiddleware,
48
+ moderatorGuard,
49
+ async (req, res) => await CyberiaSkillController.delete(req, res, options),
50
+ );
51
+ router.delete(
52
+ `/`,
53
+ options.authMiddleware,
54
+ adminGuard,
55
+ async (req, res) => await CyberiaSkillController.delete(req, res, options),
56
+ );
57
+ return router;
58
+ }
59
+ }
60
+
61
+ const ApiRouter = (options) => CyberiaSkillRouter.router(options);
62
+
63
+ export { ApiRouter, CyberiaSkillRouter };
@@ -0,0 +1,42 @@
1
+ import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
2
+ import { loggerFactory } from '../../server/logger.js';
3
+ import { DataQuery } from '../../server/data-query.js';
4
+
5
+ const logger = loggerFactory(import.meta);
6
+
7
+ class CyberiaSkillService {
8
+ static post = async (req, res, options) => {
9
+ /** @type {import('./cyberia-skill.model.js').CyberiaSkillModel} */
10
+ const CyberiaSkill = DataBaseProviderService.getModel("CyberiaSkill", options);
11
+ return await new CyberiaSkill(req.body).save();
12
+ };
13
+ static get = async (req, res, options) => {
14
+ /** @type {import('./cyberia-skill.model.js').CyberiaSkillModel} */
15
+ const CyberiaSkill = DataBaseProviderService.getModel("CyberiaSkill", options);
16
+ if (req.params.id) return await CyberiaSkill.findById(req.params.id);
17
+
18
+ // Parse query parameters using DataQuery helper
19
+ const { query, sort, skip, limit, page } = DataQuery.parse(req.query);
20
+
21
+ const [data, total] = await Promise.all([
22
+ CyberiaSkill.find(query).sort(sort).limit(limit).skip(skip),
23
+ CyberiaSkill.countDocuments(query),
24
+ ]);
25
+
26
+ const totalPages = Math.ceil(total / limit);
27
+ return { data, total, page, totalPages };
28
+ };
29
+ static put = async (req, res, options) => {
30
+ /** @type {import('./cyberia-skill.model.js').CyberiaSkillModel} */
31
+ const CyberiaSkill = DataBaseProviderService.getModel("CyberiaSkill", options);
32
+ return await CyberiaSkill.findByIdAndUpdate(req.params.id, req.body);
33
+ };
34
+ static delete = async (req, res, options) => {
35
+ /** @type {import('./cyberia-skill.model.js').CyberiaSkillModel} */
36
+ const CyberiaSkill = DataBaseProviderService.getModel("CyberiaSkill", options);
37
+ if (req.params.id) return await CyberiaSkill.findByIdAndDelete(req.params.id);
38
+ else return await CyberiaSkill.deleteMany();
39
+ };
40
+ }
41
+
42
+ export { CyberiaSkillService };
@@ -1,7 +1,7 @@
1
1
  import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
2
2
  import { loggerFactory } from '../../server/logger.js';
3
3
  import { DataQuery } from '../../server/data-query.js';
4
- import { IpfsClient } from '../../server/ipfs-client.js';
4
+ import { IpfsClient } from '../../projects/cyberia/ipfs-client.js';
5
5
  import { IpfsDto } from './ipfs.model.js';
6
6
  const logger = loggerFactory(import.meta);
7
7
  /**
@@ -17,14 +17,27 @@ const logger = loggerFactory(import.meta);
17
17
  * @returns {Promise<import('mongoose').Document>}
18
18
  */
19
19
  const createPinRecord = async ({ cid, resourceType, mfsPath = '', options }) => {
20
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
21
- const record = await Ipfs.findOneAndUpdate(
22
- { cid, resourceType },
23
- { cid, resourceType, mfsPath },
24
- { upsert: true, returnDocument: 'after', setDefaultsOnInsert: true },
25
- );
26
- logger.info(`IPFS registry upserted – CID: ${cid}, type: ${resourceType}, mfsPath: ${mfsPath}`);
27
- return record;
20
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
21
+ try {
22
+ const record = await Ipfs.findOneAndUpdate(
23
+ { cid, resourceType },
24
+ { $set: { mfsPath } },
25
+ { upsert: true, returnDocument: 'after', setDefaultsOnInsert: true },
26
+ );
27
+ logger.info(`IPFS registry upserted – CID: ${cid}, type: ${resourceType}, mfsPath: ${mfsPath}`);
28
+ return record;
29
+ } catch (err) {
30
+ if (err?.code === 11000) {
31
+ const record = await Ipfs.findOneAndUpdate(
32
+ { cid, resourceType },
33
+ { $set: { mfsPath } },
34
+ { returnDocument: 'after' },
35
+ );
36
+ logger.info(`IPFS registry reconciled (duplicate key) – CID: ${cid}, type: ${resourceType}, mfsPath: ${mfsPath}`);
37
+ return record;
38
+ }
39
+ throw err;
40
+ }
28
41
  };
29
42
  /**
30
43
  * Remove all DB registry entries for a CID, then best-effort unpin from the IPFS node.
@@ -35,7 +48,7 @@ const createPinRecord = async ({ cid, resourceType, mfsPath = '', options }) =>
35
48
  * @returns {Promise<void>}
36
49
  */
37
50
  const removePinRecordsAndUnpin = async (cid, options) => {
38
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
51
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
39
52
  await Ipfs.deleteMany({ cid });
40
53
  logger.info(`Removed IPFS registry entries for CID: ${cid}`);
41
54
  try {
@@ -52,11 +65,11 @@ class IpfsService {
52
65
  // Standard CRUD
53
66
  // ──────────────────────────────────────────────
54
67
  static post = async (req, res, options) => {
55
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
68
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
56
69
  return await new Ipfs(req.body).save();
57
70
  };
58
71
  static get = async (req, res, options) => {
59
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
72
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
60
73
  if (req.params.id) {
61
74
  return await Ipfs.findById(req.params.id).select(IpfsDto.select.get());
62
75
  }
@@ -69,11 +82,11 @@ class IpfsService {
69
82
  return { data, total, page, totalPages };
70
83
  };
71
84
  static put = async (req, res, options) => {
72
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
85
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
73
86
  return await Ipfs.findByIdAndUpdate(req.params.id, req.body, { returnDocument: 'after' });
74
87
  };
75
88
  static delete = async (req, res, options) => {
76
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
89
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
77
90
  if (req.params.id) {
78
91
  const record = await Ipfs.findById(req.params.id);
79
92
  if (record) {
@@ -107,7 +120,7 @@ class IpfsService {
107
120
  * { total, pinned, unpinned, errors, entries: [{ cid, resourceType, mfsPath, pinned, error? }] }
108
121
  */
109
122
  static verify = async (req, res, options) => {
110
- const Ipfs = DataBaseProviderService.getModel("Ipfs", options);
123
+ const Ipfs = DataBaseProviderService.getModel('Ipfs', options);
111
124
  const records = await Ipfs.find({}).select(IpfsDto.select.get()).lean();
112
125
  let pinned = 0;
113
126
  let unpinned = 0;
@@ -1,7 +1,7 @@
1
1
  import { loggerFactory } from '../../server/logger.js';
2
2
  import { ObjectLayerController } from './object-layer.controller.js';
3
3
  import express from 'express';
4
- import { adminGuard } from '../../server/auth.js';
4
+ import { moderatorGuard, adminGuard } from '../../server/auth.js';
5
5
 
6
6
  const logger = loggerFactory(import.meta);
7
7
 
@@ -12,8 +12,12 @@ class ObjectLayerRouter {
12
12
  */
13
13
  static router(options) {
14
14
  const router = express.Router();
15
- router.post(`/frame-image/:itemType/:itemId/:directionCode`, async (req, res) => {
16
- /*
15
+ router.post(
16
+ `/frame-image/:itemType/:itemId/:directionCode`,
17
+ options.authMiddleware,
18
+ moderatorGuard,
19
+ async (req, res) => {
20
+ /*
17
21
  #swagger.auto = false
18
22
  #swagger.tags = ['object-layer']
19
23
  #swagger.summary = 'Upload frame image'
@@ -65,9 +69,10 @@ class ObjectLayerRouter {
65
69
  }
66
70
  }
67
71
  */
68
- return await ObjectLayerController.post(req, res, options);
69
- });
70
- router.post(`/metadata/:itemType/:itemId`, async (req, res) => {
72
+ return await ObjectLayerController.post(req, res, options);
73
+ },
74
+ );
75
+ router.post(`/metadata/:itemType/:itemId`, options.authMiddleware, moderatorGuard, async (req, res) => {
71
76
  /*
72
77
  #swagger.auto = false
73
78
  #swagger.tags = ['object-layer']
@@ -117,7 +122,7 @@ class ObjectLayerRouter {
117
122
  return await ObjectLayerController.post(req, res, options);
118
123
  });
119
124
 
120
- router.post(`/:id`, options.authMiddleware, async (req, res) => {
125
+ router.post(`/:id`, options.authMiddleware, moderatorGuard, async (req, res) => {
121
126
  /*
122
127
  #swagger.auto = false
123
128
  #swagger.tags = ['object-layer']
@@ -162,7 +167,7 @@ class ObjectLayerRouter {
162
167
  */
163
168
  return await ObjectLayerController.post(req, res, options);
164
169
  });
165
- router.post(`/`, options.authMiddleware, async (req, res) => {
170
+ router.post(`/`, options.authMiddleware, moderatorGuard, async (req, res) => {
166
171
  /*
167
172
  #swagger.auto = false
168
173
  #swagger.tags = ['object-layer']
@@ -484,8 +489,12 @@ class ObjectLayerRouter {
484
489
  */
485
490
  return await ObjectLayerController.get(req, res, options);
486
491
  });
487
- router.put(`/:id/frame-image/:itemType/:itemId/:directionCode`, options.authMiddleware, async (req, res) => {
488
- /*
492
+ router.put(
493
+ `/:id/frame-image/:itemType/:itemId/:directionCode`,
494
+ options.authMiddleware,
495
+ moderatorGuard,
496
+ async (req, res) => {
497
+ /*
489
498
  #swagger.auto = false
490
499
  #swagger.tags = ['object-layer']
491
500
  #swagger.summary = 'Update frame image'
@@ -547,9 +556,10 @@ class ObjectLayerRouter {
547
556
  }
548
557
  }
549
558
  */
550
- return await ObjectLayerController.put(req, res, options);
551
- });
552
- router.put(`/:id/metadata/:itemType/:itemId`, options.authMiddleware, async (req, res) => {
559
+ return await ObjectLayerController.put(req, res, options);
560
+ },
561
+ );
562
+ router.put(`/:id/metadata/:itemType/:itemId`, options.authMiddleware, moderatorGuard, async (req, res) => {
553
563
  /*
554
564
  #swagger.auto = false
555
565
  #swagger.tags = ['object-layer']
@@ -608,7 +618,7 @@ class ObjectLayerRouter {
608
618
  */
609
619
  return await ObjectLayerController.put(req, res, options);
610
620
  });
611
- router.put(`/:id`, options.authMiddleware, async (req, res) => {
621
+ router.put(`/:id`, options.authMiddleware, moderatorGuard, async (req, res) => {
612
622
  /*
613
623
  #swagger.auto = false
614
624
  #swagger.tags = ['object-layer']
@@ -653,7 +663,7 @@ class ObjectLayerRouter {
653
663
  */
654
664
  return await ObjectLayerController.put(req, res, options);
655
665
  });
656
- router.put(`/`, options.authMiddleware, async (req, res) => {
666
+ router.put(`/`, options.authMiddleware, moderatorGuard, async (req, res) => {
657
667
  /*
658
668
  #swagger.ignore = true
659
669
  */
@@ -4,7 +4,7 @@
4
4
  * including frame image management, metadata processing, and WebP animation generation.
5
5
  *
6
6
  * Delegates shared object layer creation and update logic to {@link ObjectLayerEngine} in
7
- * `src/server/object-layer.js` to keep a single source of truth shared with the Cyberia CLI.
7
+ * `src/projects/cyberia/object-layer.js` to keep a single source of truth shared with the Cyberia CLI.
8
8
  *
9
9
  * @module src/api/object-layer/object-layer.service.js
10
10
  * @namespace CyberiaObjectLayerService
@@ -16,11 +16,11 @@ import { ObjectLayerRenderFramesDto } from '../object-layer-render-frames/object
16
16
  import { FileFactory } from '../file/file.service.js';
17
17
  import fs from 'fs-extra';
18
18
  import { ObjectLayerDto } from './object-layer.model.js';
19
- import { ObjectLayerEngine } from '../../server/object-layer.js';
19
+ import { ObjectLayerEngine } from '../../projects/cyberia/object-layer.js';
20
20
  import { shellExec } from '../../server/process.js';
21
21
  import { DataQuery } from '../../server/data-query.js';
22
22
  import { AtlasSpriteSheetService } from '../atlas-sprite-sheet/atlas-sprite-sheet.service.js';
23
- import { IpfsClient } from '../../server/ipfs-client.js';
23
+ import { IpfsClient } from '../../projects/cyberia/ipfs-client.js';
24
24
  import { createPinRecord, removePinRecordsAndUnpin } from '../ipfs/ipfs.service.js';
25
25
 
26
26
  /**
@@ -149,9 +149,8 @@ class ObjectLayerService {
149
149
  fs.writeFileSync(`${publicFolder}/metadata.json`, metadataContent);
150
150
 
151
151
  // Build object layer data from the asset directory
152
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
153
- const ObjectLayerRenderFrames =
154
- DataBaseProviderService.getModel("ObjectLayerRenderFrames", options);
152
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
153
+ const ObjectLayerRenderFrames = DataBaseProviderService.getModel('ObjectLayerRenderFrames', options);
155
154
 
156
155
  const { objectLayerRenderFramesData, objectLayerData } =
157
156
  await ObjectLayerEngine.buildObjectLayerDataFromDirectory({
@@ -183,9 +182,8 @@ class ObjectLayerService {
183
182
  }
184
183
 
185
184
  // create object layer from body – cut-over consistency: stage all CIDs before writing to DB
186
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
187
- const ObjectLayerRenderFrames =
188
- DataBaseProviderService.getModel("ObjectLayerRenderFrames", options);
185
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
186
+ const ObjectLayerRenderFrames = DataBaseProviderService.getModel('ObjectLayerRenderFrames', options);
189
187
 
190
188
  const bodyData = { ...req.body };
191
189
  if (!bodyData.data) bodyData.data = {};
@@ -270,7 +268,7 @@ class ObjectLayerService {
270
268
  */
271
269
  static get = async (req, res, options) => {
272
270
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
273
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
271
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
274
272
 
275
273
  // GET /search-item-ids?q=<partial> - Fast partial match search on data.item.id
276
274
  if (req.path.startsWith('/search-item-ids')) {
@@ -359,9 +357,8 @@ class ObjectLayerService {
359
357
  // If the atlas or its file is missing, clear the reference so the UI can offer to generate a new atlas.
360
358
  if (objectLayer.atlasSpriteSheetId) {
361
359
  try {
362
- const AtlasSpriteSheet =
363
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
364
- const File = DataBaseProviderService.getModel("File", options);
360
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
361
+ const File = DataBaseProviderService.getModel('File', options);
365
362
 
366
363
  const atlasDoc = await AtlasSpriteSheet.findById(objectLayer.atlasSpriteSheetId);
367
364
 
@@ -451,7 +448,7 @@ class ObjectLayerService {
451
448
  */
452
449
  static generateWebp = async (req, res, options) => {
453
450
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
454
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
451
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
455
452
 
456
453
  // GET /generate-webp/:itemType/:itemId/:directionCode - Generate webp animation from PNG frames
457
454
  const itemType = req.params.itemType;
@@ -589,7 +586,7 @@ class ObjectLayerService {
589
586
  */
590
587
  static put = async (req, res, options) => {
591
588
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
592
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
589
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
593
590
 
594
591
  // PUT /:id/frame-image/:itemType/:itemId/:directionCode - Update frame images for specific direction
595
592
  if (req.path.includes('/frame-image/')) {
@@ -688,8 +685,7 @@ class ObjectLayerService {
688
685
  fs.writeFileSync(`${folder}/metadata.json`, metadataContent);
689
686
  fs.writeFileSync(`${publicFolder}/metadata.json`, metadataContent);
690
687
 
691
- const ObjectLayerRenderFrames =
692
- DataBaseProviderService.getModel("ObjectLayerRenderFrames", options);
688
+ const ObjectLayerRenderFrames = DataBaseProviderService.getModel('ObjectLayerRenderFrames', options);
693
689
 
694
690
  // Build object layer data from the asset directory
695
691
  const { objectLayerRenderFramesData, objectLayerData } =
@@ -806,9 +802,8 @@ class ObjectLayerService {
806
802
  */
807
803
  static delete = async (req, res, options) => {
808
804
  /** @type {import('./object-layer.model.js').ObjectLayerModel} */
809
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
810
- const ObjectLayerRenderFrames =
811
- DataBaseProviderService.getModel("ObjectLayerRenderFrames", options);
805
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
806
+ const ObjectLayerRenderFrames = DataBaseProviderService.getModel('ObjectLayerRenderFrames', options);
812
807
 
813
808
  if (req.params.id) {
814
809
  // Load the full object layer so we can access all references
@@ -1,6 +1,7 @@
1
1
  import { loggerFactory } from '../../server/logger.js';
2
2
  import { ObjectLayerRenderFramesController } from './object-layer-render-frames.controller.js';
3
3
  import express from 'express';
4
+ import { moderatorGuard, adminGuard } from '../../server/auth.js';
4
5
 
5
6
  const logger = loggerFactory(import.meta);
6
7
 
@@ -11,17 +12,48 @@ class ObjectLayerRenderFramesRouter {
11
12
  */
12
13
  static router(options) {
13
14
  const router = express.Router();
14
- router.post(`/:id`, async (req, res) => await ObjectLayerRenderFramesController.post(req, res, options));
15
- router.post(`/`, async (req, res) => await ObjectLayerRenderFramesController.post(req, res, options));
16
- router.get(`/:id`,
15
+ router.post(
16
+ `/:id`,
17
+ options.authMiddleware,
18
+ moderatorGuard,
19
+ async (req, res) => await ObjectLayerRenderFramesController.post(req, res, options),
20
+ );
21
+ router.post(
22
+ `/`,
23
+ options.authMiddleware,
24
+ moderatorGuard,
25
+ async (req, res) => await ObjectLayerRenderFramesController.post(req, res, options),
26
+ );
27
+ router.get(
28
+ `/:id`,
17
29
  // options.authMiddleware,
18
30
  async (req, res) => await ObjectLayerRenderFramesController.get(req, res, options),
19
31
  );
20
32
  router.get(`/`, async (req, res) => await ObjectLayerRenderFramesController.get(req, res, options));
21
- router.put(`/:id`, async (req, res) => await ObjectLayerRenderFramesController.put(req, res, options));
22
- router.put(`/`, async (req, res) => await ObjectLayerRenderFramesController.put(req, res, options));
23
- router.delete(`/:id`, async (req, res) => await ObjectLayerRenderFramesController.delete(req, res, options));
24
- router.delete(`/`, async (req, res) => await ObjectLayerRenderFramesController.delete(req, res, options));
33
+ router.put(
34
+ `/:id`,
35
+ options.authMiddleware,
36
+ moderatorGuard,
37
+ async (req, res) => await ObjectLayerRenderFramesController.put(req, res, options),
38
+ );
39
+ router.put(
40
+ `/`,
41
+ options.authMiddleware,
42
+ moderatorGuard,
43
+ async (req, res) => await ObjectLayerRenderFramesController.put(req, res, options),
44
+ );
45
+ router.delete(
46
+ `/:id`,
47
+ options.authMiddleware,
48
+ moderatorGuard,
49
+ async (req, res) => await ObjectLayerRenderFramesController.delete(req, res, options),
50
+ );
51
+ router.delete(
52
+ `/`,
53
+ options.authMiddleware,
54
+ adminGuard,
55
+ async (req, res) => await ObjectLayerRenderFramesController.delete(req, res, options),
56
+ );
25
57
  return router;
26
58
  }
27
59
  }