cyberia 3.2.22 → 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 (185) 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 +33 -24
  11. package/.github/workflows/engine-cyberia.ci.yml +13 -3
  12. package/.github/workflows/ghpkg.ci.yml +88 -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 +10 -7
  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 +301 -1
  21. package/CLI-HELP.md +71 -6
  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 +31 -0
  28. package/bin/cyberia.js +1080 -184
  29. package/bin/deploy.js +2 -2
  30. package/bin/index.js +1080 -184
  31. package/bump.config.js +1 -0
  32. package/compose.env +131 -0
  33. package/conf.js +18 -1
  34. package/deployment.yaml +2 -2
  35. package/docker-compose.yml +316 -0
  36. package/hardhat/hardhat.config.js +2 -2
  37. package/hardhat/package-lock.json +620 -2041
  38. package/hardhat/package.json +7 -5
  39. package/hardhat/scripts/deployObjectLayerToken.js +18 -18
  40. package/hardhat/test/ObjectLayerToken.js +378 -274
  41. package/ipfs/configure-ipfs.sh +13 -0
  42. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  43. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  44. package/manifests/deployment/dd-cyberia-development/deployment.yaml +2 -2
  45. package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
  46. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +32 -0
  47. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  48. package/mongodb/entrypoint.sh +76 -0
  49. package/nginx.conf +87 -0
  50. package/package.json +31 -19
  51. package/pv-pvc.yaml +32 -0
  52. package/scripts/disk-clean.sh +85 -60
  53. package/scripts/kubeadm-node-setup.sh +317 -0
  54. package/scripts/rocky-kickstart.sh +877 -185
  55. package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
  56. package/scripts/test-monitor.sh +3 -5
  57. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +43 -7
  58. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +17 -25
  59. package/src/api/cyberia-action/cyberia-action.controller.js +19 -0
  60. package/src/api/cyberia-action/cyberia-action.model.js +21 -29
  61. package/src/api/cyberia-action/cyberia-action.router.js +42 -7
  62. package/src/api/cyberia-action/cyberia-action.service.js +20 -4
  63. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +58 -57
  64. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +37 -6
  65. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +8 -2
  66. package/src/api/cyberia-entity/cyberia-entity.router.js +39 -7
  67. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +74 -0
  68. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
  69. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +63 -0
  70. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
  71. package/src/api/cyberia-instance/cyberia-fallback-world.js +62 -10
  72. package/src/api/cyberia-instance/cyberia-instance.model.js +32 -2
  73. package/src/api/cyberia-instance/cyberia-instance.router.js +6 -6
  74. package/src/api/cyberia-instance/cyberia-world-generator.js +116 -3
  75. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +3 -0
  76. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +39 -7
  77. package/src/api/cyberia-map/cyberia-map.router.js +21 -6
  78. package/src/api/cyberia-quest/cyberia-quest.controller.js +38 -0
  79. package/src/api/cyberia-quest/cyberia-quest.router.js +47 -7
  80. package/src/api/cyberia-quest/cyberia-quest.service.js +59 -4
  81. package/src/api/cyberia-saga/cyberia-saga.controller.js +74 -0
  82. package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
  83. package/src/api/cyberia-saga/cyberia-saga.router.js +63 -0
  84. package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
  85. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +551 -129
  86. package/src/api/cyberia-skill/cyberia-skill.controller.js +74 -0
  87. package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
  88. package/src/api/cyberia-skill/cyberia-skill.router.js +63 -0
  89. package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
  90. package/src/api/ipfs/ipfs.service.js +28 -15
  91. package/src/api/object-layer/object-layer.router.js +25 -15
  92. package/src/api/object-layer/object-layer.service.js +15 -20
  93. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +39 -7
  94. package/src/cli/baremetal.js +717 -16
  95. package/src/cli/cluster.js +80 -5
  96. package/src/cli/deploy.js +127 -11
  97. package/src/cli/docker-compose.js +648 -0
  98. package/src/cli/env.js +11 -2
  99. package/src/cli/fs.js +75 -30
  100. package/src/cli/image.js +129 -51
  101. package/src/cli/index.js +110 -6
  102. package/src/cli/kickstart.js +142 -20
  103. package/src/cli/release.js +46 -4
  104. package/src/cli/repository.js +238 -33
  105. package/src/cli/run.js +520 -114
  106. package/src/cli/secrets.js +82 -48
  107. package/src/cli/ssh.js +234 -0
  108. package/src/cli/static.js +2 -2
  109. package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
  110. package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
  111. package/src/client/components/cyberia/InstanceEngineCyberia.js +219 -13
  112. package/src/client/components/cyberia/MapEngineCyberia.js +154 -71
  113. package/src/client/components/cyberia/ObjectLayerEngineModal.js +40 -63
  114. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +34 -20
  115. package/src/client/components/cyberia/SharedDefaultsCyberia.js +195 -4
  116. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +66 -0
  117. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +8 -0
  118. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -0
  119. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +45 -27
  120. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +3 -3
  121. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +39 -22
  122. package/src/client/public/cyberia-docs/CYBERIA-LORE.md +88 -0
  123. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
  124. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +8 -1
  125. package/src/client/public/cyberia-docs/CYBERIA.md +1 -1
  126. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +5 -5
  127. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  128. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  129. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
  130. package/src/client/services/cyberia-instance/cyberia-instance.management.js +2 -2
  131. package/src/client/services/cyberia-map/cyberia-map.management.js +2 -2
  132. package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
  133. package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
  134. package/src/client/services/object-layer/object-layer.management.js +6 -6
  135. package/src/{server → client-builder}/client-build-docs.js +15 -5
  136. package/src/{server → client-builder}/client-build-live.js +3 -3
  137. package/src/{server → client-builder}/client-build.js +25 -22
  138. package/src/{server → client-builder}/client-dev-server.js +3 -3
  139. package/src/{server → client-builder}/client-icons.js +2 -2
  140. package/src/{server → client-builder}/ssr.js +5 -5
  141. package/src/client.build.js +1 -3
  142. package/src/client.dev.js +1 -1
  143. package/src/db/mongo/MongoBootstrap.js +12 -12
  144. package/src/grpc/cyberia/grpc-server.js +255 -70
  145. package/src/index.js +12 -1
  146. package/src/mailer/EmailRender.js +1 -1
  147. package/src/{server → projects/cyberia}/atlas-sprite-sheet-generator.js +2 -2
  148. package/src/{server → projects/cyberia}/besu-genesis-generator.js +3 -3
  149. package/src/projects/cyberia/catalog-cyberia.js +81 -0
  150. package/src/projects/cyberia/gemini-client.js +175 -0
  151. package/src/projects/cyberia/generate-saga.js +2107 -0
  152. package/src/{server → projects/cyberia}/ipfs-client.js +2 -2
  153. package/src/{server → projects/cyberia}/object-layer.js +12 -108
  154. package/src/{server → projects/cyberia}/semantic-layer-generator-floor.js +1 -1
  155. package/src/{server → projects/cyberia}/semantic-layer-generator-resource.js +1 -1
  156. package/src/{server → projects/cyberia}/semantic-layer-generator-skin.js +1 -1
  157. package/src/{server → projects/cyberia}/semantic-layer-generator.js +2 -2
  158. package/src/{server → projects/cyberia}/shape-generator.js +2 -2
  159. package/src/{server → projects/underpost}/catalog-underpost.js +1 -2
  160. package/src/runtime/cyberia-client/Dockerfile +27 -61
  161. package/src/runtime/cyberia-client/Dockerfile.dev +20 -12
  162. package/src/runtime/cyberia-server/Dockerfile +21 -20
  163. package/src/runtime/cyberia-server/Dockerfile.dev +17 -8
  164. package/src/runtime/engine-cyberia/Dockerfile +143 -0
  165. package/src/runtime/engine-cyberia/Dockerfile.dev +143 -0
  166. package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
  167. package/src/runtime/engine-cyberia/compose.env +131 -0
  168. package/src/runtime/engine-cyberia/docker-compose.yml +316 -0
  169. package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
  170. package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
  171. package/src/runtime/engine-cyberia/nginx.conf +87 -0
  172. package/src/runtime/express/Express.js +2 -2
  173. package/src/runtime/nginx/Nginx.js +250 -0
  174. package/src/server/catalog.js +9 -14
  175. package/src/server/conf.js +3 -6
  176. package/src/server/runtime-status.js +18 -1
  177. package/src/server/start.js +12 -2
  178. package/src/server.js +6 -2
  179. package/test/cyberia-instance-conf-defaults.test.js +140 -0
  180. package/test/deploy-monitor.test.js +26 -10
  181. package/test/shape-generator.test.js +7 -1
  182. package/typedoc.dd-cyberia.json +3 -1
  183. package/typedoc.json +3 -1
  184. /package/src/client/ssr/{Render.js → RootDocument.js} +0 -0
  185. /package/src/{server → client-builder}/client-formatted.js +0 -0
@@ -18,82 +18,83 @@
18
18
  import { Schema, model } from 'mongoose';
19
19
 
20
20
  const ColorRgbaSchema = new Schema(
21
- {
22
- r: { type: Number, default: 0 },
23
- g: { type: Number, default: 0 },
24
- b: { type: Number, default: 0 },
25
- a: { type: Number, default: 255 },
26
- },
27
- { _id: false },
21
+ {
22
+ r: { type: Number, default: 0 },
23
+ g: { type: Number, default: 0 },
24
+ b: { type: Number, default: 0 },
25
+ a: { type: Number, default: 255 },
26
+ },
27
+ { _id: false },
28
28
  );
29
29
 
30
30
  const PaletteEntrySchema = new Schema(
31
- {
32
- key: { type: String, required: true },
33
- r: { type: Number, default: 0 },
34
- g: { type: Number, default: 0 },
35
- b: { type: Number, default: 0 },
36
- a: { type: Number, default: 255 },
37
- },
38
- { _id: false },
31
+ {
32
+ key: { type: String, required: true },
33
+ r: { type: Number, default: 0 },
34
+ g: { type: Number, default: 0 },
35
+ b: { type: Number, default: 0 },
36
+ a: { type: Number, default: 255 },
37
+ },
38
+ { _id: false },
39
39
  );
40
40
 
41
41
  const StatusIconHintSchema = new Schema(
42
- {
43
- id: { type: Number, required: true },
44
- iconId: { type: String, default: '' },
45
- bounce: { type: Boolean, default: false },
46
- borderColor: { type: ColorRgbaSchema, default: () => ({ r: 100, g: 100, b: 100, a: 200 }) },
47
- },
48
- { _id: false },
42
+ {
43
+ id: { type: Number, required: true },
44
+ iconId: { type: String, default: '' },
45
+ bounce: { type: Boolean, default: false },
46
+ borderColor: { type: ColorRgbaSchema, default: () => ({ r: 100, g: 100, b: 100, a: 200 }) },
47
+ },
48
+ { _id: false },
49
49
  );
50
50
 
51
51
  const EntityColorKeySchema = new Schema(
52
- {
53
- entityType: { type: String, required: true },
54
- colorKey: { type: String, required: true },
55
- },
56
- { _id: false },
52
+ {
53
+ entityType: { type: String, required: true },
54
+ colorKey: { type: String, required: true },
55
+ },
56
+ { _id: false },
57
57
  );
58
58
 
59
59
  const CyberiaClientHintsSchema = new Schema(
60
- {
61
- // Instance code this hint set is scoped to. Matches CyberiaInstance.code
62
- // and CyberiaInstanceConf.instanceCode. Indexed and unique to make the
63
- // service-layer cache a 1-to-1 keyed lookup.
64
- code: { type: String, required: true, unique: true, index: true },
60
+ {
61
+ // Instance code this hint set is scoped to. Matches CyberiaInstance.code
62
+ // and CyberiaInstanceConf.instanceCode. Indexed and unique to make the
63
+ // service-layer cache a 1-to-1 keyed lookup.
64
+ code: { type: String, required: true, unique: true, index: true },
65
65
 
66
- // Optional palette overrides. Keys not present here fall back to the
67
- // client's compile-time defaults.
68
- palette: { type: [PaletteEntrySchema], default: [] },
66
+ // Optional palette overrides. Keys not present here fall back to the
67
+ // client's compile-time defaults.
68
+ palette: { type: [PaletteEntrySchema], default: [] },
69
69
 
70
- // Optional per-entity-type color-key overrides.
71
- entityColorKeys: { type: [EntityColorKeySchema], default: [] },
70
+ // Optional per-entity-type color-key overrides.
71
+ entityColorKeys: { type: [EntityColorKeySchema], default: [] },
72
72
 
73
- // Optional status-icon visual overrides (id → iconId + borderColor).
74
- statusIcons: { type: [StatusIconHintSchema], default: [] },
73
+ // Optional status-icon visual overrides (id → iconId + borderColor).
74
+ statusIcons: { type: [StatusIconHintSchema], default: [] },
75
75
 
76
- // Camera, viewport, and cell-sizing tunings — null/undefined means
77
- // "use the SharedDefaultsCyberia.RENDER_DEFAULTS value".
78
- cellSize: { type: Number, default: null },
79
- defaultObjWidth: { type: Number, default: null },
80
- defaultObjHeight: { type: Number, default: null },
81
- cameraSmoothing: { type: Number, default: null },
82
- cameraZoom: { type: Number, default: null },
83
- defaultWidthScreenFactor: { type: Number, default: null },
84
- defaultHeightScreenFactor: { type: Number, default: null },
85
- interpolationMs: { type: Number, default: null },
86
- devUi: { type: Boolean, default: null },
87
- },
88
- { timestamps: true },
76
+ // Camera, viewport, and cell-sizing tunings — null/undefined means
77
+ // "use the SharedDefaultsCyberia.RENDER_DEFAULTS value".
78
+ cellSize: { type: Number, default: null },
79
+ defaultObjWidth: { type: Number, default: null },
80
+ defaultObjHeight: { type: Number, default: null },
81
+ cameraSmoothing: { type: Number, default: null },
82
+ cameraZoom: { type: Number, default: null },
83
+ defaultWidthScreenFactor: { type: Number, default: null },
84
+ defaultHeightScreenFactor: { type: Number, default: null },
85
+ interpolationMs: { type: Number, default: null },
86
+ devUi: { type: Boolean, default: null },
87
+
88
+ // Main UI font: TTF file name under engine assets/fonts/ (null = built-in
89
+ // raylib font) and a uniform text-size multiplier.
90
+ fontFamily: { type: String, default: null },
91
+ fontFactorSize: { type: Number, default: null },
92
+ },
93
+ { timestamps: true },
89
94
  );
90
95
 
91
96
  const CyberiaClientHintsModel = model('CyberiaClientHints', CyberiaClientHintsSchema);
92
97
 
93
98
  const ProviderSchema = CyberiaClientHintsSchema;
94
99
 
95
- export {
96
- CyberiaClientHintsSchema,
97
- CyberiaClientHintsModel,
98
- ProviderSchema,
99
- };
100
+ export { CyberiaClientHintsSchema, CyberiaClientHintsModel, ProviderSchema };
@@ -1,6 +1,7 @@
1
1
  import { loggerFactory } from '../../server/logger.js';
2
2
  import { CyberiaDialogueController } from './cyberia-dialogue.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,8 +12,18 @@ class CyberiaDialogueRouter {
11
12
  */
12
13
  static router(options) {
13
14
  const router = express.Router();
14
- router.post(`/:id`, async (req, res) => await CyberiaDialogueController.post(req, res, options));
15
- router.post(`/`, async (req, res) => await CyberiaDialogueController.post(req, res, options));
15
+ router.post(
16
+ `/:id`,
17
+ options.authMiddleware,
18
+ moderatorGuard,
19
+ async (req, res) => await CyberiaDialogueController.post(req, res, options),
20
+ );
21
+ router.post(
22
+ `/`,
23
+ options.authMiddleware,
24
+ moderatorGuard,
25
+ async (req, res) => await CyberiaDialogueController.post(req, res, options),
26
+ );
16
27
  // Direct lookup by code — C client fetches dialogue by code (e.g. "default-lain")
17
28
  router.get(`/code/:code`, async (req, res) => await CyberiaDialogueController.getByCode(req, res, options));
18
29
  router.get(
@@ -21,10 +32,30 @@ class CyberiaDialogueRouter {
21
32
  async (req, res) => await CyberiaDialogueController.get(req, res, options),
22
33
  );
23
34
  router.get(`/`, async (req, res) => await CyberiaDialogueController.get(req, res, options));
24
- router.put(`/:id`, async (req, res) => await CyberiaDialogueController.put(req, res, options));
25
- router.put(`/`, async (req, res) => await CyberiaDialogueController.put(req, res, options));
26
- router.delete(`/:id`, async (req, res) => await CyberiaDialogueController.delete(req, res, options));
27
- router.delete(`/`, async (req, res) => await CyberiaDialogueController.delete(req, res, options));
35
+ router.put(
36
+ `/:id`,
37
+ options.authMiddleware,
38
+ moderatorGuard,
39
+ async (req, res) => await CyberiaDialogueController.put(req, res, options),
40
+ );
41
+ router.put(
42
+ `/`,
43
+ options.authMiddleware,
44
+ moderatorGuard,
45
+ async (req, res) => await CyberiaDialogueController.put(req, res, options),
46
+ );
47
+ router.delete(
48
+ `/:id`,
49
+ options.authMiddleware,
50
+ moderatorGuard,
51
+ async (req, res) => await CyberiaDialogueController.delete(req, res, options),
52
+ );
53
+ router.delete(
54
+ `/`,
55
+ options.authMiddleware,
56
+ adminGuard,
57
+ async (req, res) => await CyberiaDialogueController.delete(req, res, options),
58
+ );
28
59
  return router;
29
60
  }
30
61
  }
@@ -1,6 +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 { DefaultCyberiaDialogues } from '../cyberia-server-defaults/cyberia-server-defaults.js';
4
5
 
5
6
  const logger = loggerFactory(import.meta);
6
7
 
@@ -43,8 +44,13 @@ class CyberiaDialogueService {
43
44
  const { code } = req.params;
44
45
  if (!code) throw new Error('code parameter is required');
45
46
  const data = await CyberiaDialogue.find({ code }).sort({ order: 1 }).lean();
46
- if (!data.length) throw new Error(`No dialogue found for code: ${code}`);
47
- return data;
47
+ if (data.length) return data;
48
+ // Fallback world greetings/quest dialogue come from the canonical defaults
49
+ // without persisting them; serve those so action NPCs always have lines
50
+ // (and thus the dlg_complete grant handshake fires).
51
+ const fallback = DefaultCyberiaDialogues.filter((d) => d.code === code).sort((a, b) => a.order - b.order);
52
+ if (fallback.length) return fallback;
53
+ throw new Error(`No dialogue found for code: ${code}`);
48
54
  };
49
55
  }
50
56
 
@@ -1,6 +1,7 @@
1
1
  import { loggerFactory } from '../../server/logger.js';
2
2
  import { CyberiaEntityController } from './cyberia-entity.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 CyberiaEntityRouter {
11
12
  */
12
13
  static router(options) {
13
14
  const router = express.Router();
14
- router.post(`/:id`, async (req, res) => await CyberiaEntityController.post(req, res, options));
15
- router.post(`/`, async (req, res) => await CyberiaEntityController.post(req, res, options));
16
- router.get(`/:id`,
15
+ router.post(
16
+ `/:id`,
17
+ options.authMiddleware,
18
+ moderatorGuard,
19
+ async (req, res) => await CyberiaEntityController.post(req, res, options),
20
+ );
21
+ router.post(
22
+ `/`,
23
+ options.authMiddleware,
24
+ moderatorGuard,
25
+ async (req, res) => await CyberiaEntityController.post(req, res, options),
26
+ );
27
+ router.get(
28
+ `/:id`,
17
29
  // options.authMiddleware,
18
30
  async (req, res) => await CyberiaEntityController.get(req, res, options),
19
31
  );
20
32
  router.get(`/`, async (req, res) => await CyberiaEntityController.get(req, res, options));
21
- router.put(`/:id`, async (req, res) => await CyberiaEntityController.put(req, res, options));
22
- router.put(`/`, async (req, res) => await CyberiaEntityController.put(req, res, options));
23
- router.delete(`/:id`, async (req, res) => await CyberiaEntityController.delete(req, res, options));
24
- router.delete(`/`, async (req, res) => await CyberiaEntityController.delete(req, res, options));
33
+ router.put(
34
+ `/:id`,
35
+ options.authMiddleware,
36
+ moderatorGuard,
37
+ async (req, res) => await CyberiaEntityController.put(req, res, options),
38
+ );
39
+ router.put(
40
+ `/`,
41
+ options.authMiddleware,
42
+ moderatorGuard,
43
+ async (req, res) => await CyberiaEntityController.put(req, res, options),
44
+ );
45
+ router.delete(
46
+ `/:id`,
47
+ options.authMiddleware,
48
+ moderatorGuard,
49
+ async (req, res) => await CyberiaEntityController.delete(req, res, options),
50
+ );
51
+ router.delete(
52
+ `/`,
53
+ options.authMiddleware,
54
+ adminGuard,
55
+ async (req, res) => await CyberiaEntityController.delete(req, res, options),
56
+ );
25
57
  return router;
26
58
  }
27
59
  }
@@ -0,0 +1,74 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { CyberiaEntityTypeDefaultService } from './cyberia-entity-type-default.service.js';
3
+
4
+ const logger = loggerFactory(import.meta);
5
+
6
+ class CyberiaEntityTypeDefaultController {
7
+ static post = async (req, res, options) => {
8
+ try {
9
+ const result = await CyberiaEntityTypeDefaultService.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 CyberiaEntityTypeDefaultService.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 CyberiaEntityTypeDefaultService.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 CyberiaEntityTypeDefaultService.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 { CyberiaEntityTypeDefaultController };
@@ -0,0 +1,67 @@
1
+ import { Schema, model } from 'mongoose';
2
+
3
+ // https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
4
+
5
+ // CyberiaEntityTypeDefault — DB-backed, editable mirror of the per-entity-type
6
+ // item defaults that ship in cyberia-server-defaults.js (ENTITY_TYPE_DEFAULTS).
7
+ // A document binds an entity category (entityType) to the item ids the runtime
8
+ // rotates through by lifecycle state:
9
+ // liveItemIds — ObjectLayer item ids while the entity is alive.
10
+ // deadItemIds — ids swapped in on death / ghost state.
11
+ // dropItemIds — ids granted to the killer on depletion (resources).
12
+ // defaultObjectLayers — seed inventory rows ({ itemId, active, quantity }).
13
+ //
14
+ // Resolution rule (authoritative): defaults are looked up by the entity's ACTIVE
15
+ // itemId (usually the skin) — the system finds the document whose `liveItemIds`
16
+ // contains that itemId, then applies the document's deadItemIds / dropItemIds /
17
+ // defaultObjectLayers to drive what is shown as the entity's state changes.
18
+ //
19
+ // Resolution (subset matching): a document matches an entity when ALL of its
20
+ // `liveItemIds` are present in the entity's active item ids, and the MOST SPECIFIC
21
+ // match wins — the document requiring the largest item set. This lets the same
22
+ // skin map to different defaults by its full active set, e.g.
23
+ // { bot, liveItemIds:[purple, atlas_pistol_mk2], behavior:hostile }
24
+ // { bot, liveItemIds:[purple], behavior:passive }
25
+ // where a purple bot carrying the pistol is hostile and a bare purple bot is
26
+ // passive. The Go simulation (game/entity_defaults.go) implements the same rule.
27
+ //
28
+ // Invariants:
29
+ // - `entityType` is a label, not a unique key — a category appears in many
30
+ // documents.
31
+ // - There is NO per-itemId uniqueness: the same itemId may appear in the
32
+ // `liveItemIds` of many documents (different entity types, or the same type
33
+ // at different specificity levels). `liveItemIds` is indexed (non-unique
34
+ // multikey) only for fast membership lookups.
35
+
36
+ const ObjectLayerDefaultSchema = new Schema(
37
+ {
38
+ itemId: { type: String, required: true, trim: true },
39
+ active: { type: Boolean, default: false },
40
+ quantity: { type: Number, default: 0 },
41
+ },
42
+ { _id: false },
43
+ );
44
+
45
+ const CyberiaEntityTypeDefaultSchema = new Schema(
46
+ {
47
+ entityType: { type: String, required: true, trim: true },
48
+ liveItemIds: { type: [{ type: String, trim: true }], index: true },
49
+ deadItemIds: [{ type: String, trim: true }],
50
+ dropItemIds: [{ type: String, trim: true }],
51
+ defaultObjectLayers: [ObjectLayerDefaultSchema],
52
+ // Canonical entity behavior bound to entities matched by liveItemIds (see
53
+ // SharedDefaultsCyberia.ENTITY_BEHAVIORS). Empty = let the runtime derive it
54
+ // (armed → hostile, else passive). The Go simulation resolves this with the
55
+ // same liveItemIds matching used for the live/dead/drop sets.
56
+ behavior: { type: String, trim: true },
57
+ },
58
+ {
59
+ timestamps: true,
60
+ },
61
+ );
62
+
63
+ const CyberiaEntityTypeDefaultModel = model('CyberiaEntityTypeDefault', CyberiaEntityTypeDefaultSchema);
64
+
65
+ const ProviderSchema = CyberiaEntityTypeDefaultSchema;
66
+
67
+ export { CyberiaEntityTypeDefaultSchema, CyberiaEntityTypeDefaultModel, ProviderSchema };
@@ -0,0 +1,63 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { CyberiaEntityTypeDefaultController } from './cyberia-entity-type-default.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 CyberiaEntityTypeDefaultRouter {
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 CyberiaEntityTypeDefaultController.post(req, res, options),
20
+ );
21
+ router.post(
22
+ `/`,
23
+ options.authMiddleware,
24
+ moderatorGuard,
25
+ async (req, res) => await CyberiaEntityTypeDefaultController.post(req, res, options),
26
+ );
27
+ router.get(
28
+ `/:id`,
29
+ // options.authMiddleware,
30
+ async (req, res) => await CyberiaEntityTypeDefaultController.get(req, res, options),
31
+ );
32
+ router.get(`/`, async (req, res) => await CyberiaEntityTypeDefaultController.get(req, res, options));
33
+ router.put(
34
+ `/:id`,
35
+ options.authMiddleware,
36
+ moderatorGuard,
37
+ async (req, res) => await CyberiaEntityTypeDefaultController.put(req, res, options),
38
+ );
39
+ router.put(
40
+ `/`,
41
+ options.authMiddleware,
42
+ moderatorGuard,
43
+ async (req, res) => await CyberiaEntityTypeDefaultController.put(req, res, options),
44
+ );
45
+ router.delete(
46
+ `/:id`,
47
+ options.authMiddleware,
48
+ moderatorGuard,
49
+ async (req, res) => await CyberiaEntityTypeDefaultController.delete(req, res, options),
50
+ );
51
+ router.delete(
52
+ `/`,
53
+ options.authMiddleware,
54
+ adminGuard,
55
+ async (req, res) => await CyberiaEntityTypeDefaultController.delete(req, res, options),
56
+ );
57
+ return router;
58
+ }
59
+ }
60
+
61
+ const ApiRouter = (options) => CyberiaEntityTypeDefaultRouter.router(options);
62
+
63
+ export { ApiRouter, CyberiaEntityTypeDefaultRouter };
@@ -0,0 +1,46 @@
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 CyberiaEntityTypeDefaultService {
8
+ // No per-itemId uniqueness: resolution is by subset containment (most-specific
9
+ // match wins), so the same itemId may appear in many documents — e.g.
10
+ // [purple, atlas_pistol_mk2]→hostile alongside [purple]→passive. See the model.
11
+
12
+ static post = async (req, res, options) => {
13
+ /** @type {import('./cyberia-entity-type-default.model.js').CyberiaEntityTypeDefaultModel} */
14
+ const CyberiaEntityTypeDefault = DataBaseProviderService.getModel('CyberiaEntityTypeDefault', options);
15
+ return await new CyberiaEntityTypeDefault(req.body).save();
16
+ };
17
+ static get = async (req, res, options) => {
18
+ /** @type {import('./cyberia-entity-type-default.model.js').CyberiaEntityTypeDefaultModel} */
19
+ const CyberiaEntityTypeDefault = DataBaseProviderService.getModel('CyberiaEntityTypeDefault', options);
20
+ if (req.params.id) return await CyberiaEntityTypeDefault.findById(req.params.id);
21
+
22
+ // Parse query parameters using DataQuery helper
23
+ const { query, sort, skip, limit, page } = DataQuery.parse(req.query);
24
+
25
+ const [data, total] = await Promise.all([
26
+ CyberiaEntityTypeDefault.find(query).sort(sort).limit(limit).skip(skip),
27
+ CyberiaEntityTypeDefault.countDocuments(query),
28
+ ]);
29
+
30
+ const totalPages = Math.ceil(total / limit);
31
+ return { data, total, page, totalPages };
32
+ };
33
+ static put = async (req, res, options) => {
34
+ /** @type {import('./cyberia-entity-type-default.model.js').CyberiaEntityTypeDefaultModel} */
35
+ const CyberiaEntityTypeDefault = DataBaseProviderService.getModel('CyberiaEntityTypeDefault', options);
36
+ return await CyberiaEntityTypeDefault.findByIdAndUpdate(req.params.id, req.body);
37
+ };
38
+ static delete = async (req, res, options) => {
39
+ /** @type {import('./cyberia-entity-type-default.model.js').CyberiaEntityTypeDefaultModel} */
40
+ const CyberiaEntityTypeDefault = DataBaseProviderService.getModel('CyberiaEntityTypeDefault', options);
41
+ if (req.params.id) return await CyberiaEntityTypeDefault.findByIdAndDelete(req.params.id);
42
+ else return await CyberiaEntityTypeDefault.deleteMany();
43
+ };
44
+ }
45
+
46
+ export { CyberiaEntityTypeDefaultService };