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
@@ -1,56 +1,32 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- # Purpose: enable required repos (CRB, EPEL, RPM Fusion) and attempt to install ffmpeg on Rocky/Alma/RHEL-9 compatible systems.
4
+ echo "1) Ensure dnf-plugins-core is installed"
5
+ dnf -y install dnf-plugins-core
5
6
 
6
- if [ "${EUID:-$(id -u)}" -ne 0 ]; then
7
- echo "This script must be run as root or with sudo. Exiting."
8
- exit 1
9
- fi
7
+ echo "2) Enable CRB"
8
+ dnf config-manager --set-enabled crb || true
10
9
 
11
- echo "1) Ensure dnf-plugins-core is available (for config-manager)"
12
- dnf -y install dnf-plugins-core
10
+ echo "3) Install EPEL"
11
+ dnf -y install epel-release \
12
+ || dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
13
+
14
+ echo "4) Install RPM Fusion repositories"
15
+ dnf -y install \
16
+ https://download1.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm \
17
+ https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm
18
+
19
+
20
+ echo "5) Install libwebp-tools (for ffmpeg to support WebP)"
21
+ dnf -y install libwebp-tools
22
+
23
+ echo "6) Refresh metadata"
24
+ dnf clean all
25
+ dnf makecache --refresh
26
+
27
+ echo "7) Install ffmpeg"
28
+ dnf -y install ffmpeg ffmpeg-devel --allowerasing
13
29
 
14
- echo "2) Enable CodeReady / CRB (needed for some deps, e.g. ladspa)"
15
- # On RHEL you'd use subscription-manager; on CentOS/Rocky/Alma use config-manager
16
- dnf config-manager --set-enabled crb
17
-
18
- echo "3) Install EPEL release (required by some ffmpeg deps)"
19
- dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
20
-
21
- echo "4) Add RPM Fusion (free + nonfree) repositories"
22
- # Using mirrors.rpmfusion.org recommended links
23
- dnf -y install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm \
24
- https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm
25
-
26
- echo "5) Refresh metadata and update system"
27
- dnf -y makecache
28
- # Optional: update system packages (comment out if you don't want a full update)
29
- # dnf -y update
30
-
31
- echo "6) Try to install audio helper packages that sometimes block ffmpeg (ladspa, rubberband)"
32
- # These may be provided by CRB/EPEL or other compatible repos
33
- dnf -y install ladspa || echo "ladspa not available from enabled repos (will try later)"
34
- dnf -y install rubberband || echo "rubberband not available from enabled repos (will try later)"
35
- dnf -y install libwebp-tools || echo "libwebp-tools not available from enabled repos (will try later)"
36
-
37
- echo "7) Try installing ffmpeg (several fallbacks tried)"
38
- if dnf -y install ffmpeg ffmpeg-devel --allowerasing; then
39
- echo "ffmpeg installed successfully (used --allowerasing)."
40
- elif dnf -y install ffmpeg ffmpeg-devel --nobest; then
41
- echo "ffmpeg installed successfully (used --nobest)."
42
- elif dnf -y install ffmpeg ffmpeg-devel --skip-broken; then
43
- echo "ffmpeg installed (skip-broken). Some optional packages may have been skipped."
44
- else
45
- echo "Automatic install failed."
46
- echo "Helpful troubleshooting steps:"
47
- echo " - Check which repo provides ladspa: dnf repoquery --whatprovides 'ladspa'"
48
- echo " - Check which package provides librubberband: dnf repoquery --whatprovides 'librubberband.so.2'"
49
- echo " - Try enabling CRB and EPEL (we already attempted that). If ladspa/rubberband are still missing you can fetch their EL9 rpm from a trusted mirror or build them."
50
- echo " - Example manual install (ONLY if you trust the source): sudo dnf install /path/to/ladspa-*.el9.rpm /path/to/rubberband-*.el9.rpm"
51
- echo " - After satisfying ladspa/rubberband, rerun: sudo dnf install ffmpeg ffmpeg-devel"
52
- exit 2
53
- fi
54
-
55
- echo "\nInstallation finished. Verify with: ffmpeg -version"
56
- exit 0
30
+ echo
31
+ echo "Done."
32
+ ffmpeg -version | head -n 1
@@ -2,9 +2,7 @@
2
2
  #
3
3
  # test-monitor.sh — end-to-end deploy + two-phase monitor smoke test.
4
4
  #
5
- # Two deployment shapes are supported (see
6
- # src/client/public/nexodev/docs/references/Deploy-Monitor-PRD.md and
7
- # 'Deploy custom instance to K8S.md'):
5
+ # Two deployment shapes are supported:
8
6
  #
9
7
  # --mode runtime `underpost start` deploy (e.g. dd-test). Monitored with the
10
8
  # HTTP gate: /_internal/ready probes + port-forward status.
@@ -26,11 +24,11 @@ MODE=runtime # runtime | instance
26
24
  ENV=development # development | production
27
25
  DEPLOY_ID=dd-test # deploy id (instance mode: parent of conf.instances.json)
28
26
  INSTANCE_IDS= # instance mode: csv of ids (default: all in conf.instances.json)
29
- IMAGE=underpost/wp:v3.2.14 # runtime mode image (instance mode reads image from conf)
27
+ IMAGE=underpost/wp:v3.2.70 # runtime mode image (instance mode reads image from conf)
30
28
  VERSIONS=green # csv of blue/green versions
31
29
  REPLICAS=1 # replicas per deployment
32
30
  NAMESPACE=default # k8s namespace
33
- CLUSTER= # kind | kubeadm | k3s | "" (auto/none)
31
+ CLUSTER=kind # kind | kubeadm | k3s | "" (auto/none)
34
32
  TIMEOUT_RESPONSE=300000ms # HTTPProxy per-route response timeout
35
33
  TEMPLATE_REPO=underpostnet/pwa-microservices-template-private # runtime mode link repo
36
34
  ENVOY_NAMESPACE=projectcontour # ingress namespace (instance TLS exposure)
@@ -1,6 +1,7 @@
1
1
  import { loggerFactory } from '../../server/logger.js';
2
2
  import { AtlasSpriteSheetController } from './atlas-sprite-sheet.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
 
@@ -14,19 +15,34 @@ class AtlasSpriteSheetRouter {
14
15
  router.post(
15
16
  `/generate/:id`,
16
17
  options.authMiddleware,
18
+ moderatorGuard,
17
19
  async (req, res) => await AtlasSpriteSheetController.generate(req, res, options),
18
20
  );
19
21
  router.delete(
20
22
  `/object-layer/:id`,
21
23
  options.authMiddleware,
24
+ moderatorGuard,
22
25
  async (req, res) => await AtlasSpriteSheetController.deleteByObjectLayerId(req, res, options),
23
26
  );
24
- router.post(`/:id`, options.authMiddleware, async (req, res) => await AtlasSpriteSheetController.post(req, res, options));
25
- router.post(`/`, options.authMiddleware, async (req, res) => await AtlasSpriteSheetController.post(req, res, options));
27
+ router.post(
28
+ `/:id`,
29
+ options.authMiddleware,
30
+ moderatorGuard,
31
+ async (req, res) => await AtlasSpriteSheetController.post(req, res, options),
32
+ );
33
+ router.post(
34
+ `/`,
35
+ options.authMiddleware,
36
+ moderatorGuard,
37
+ async (req, res) => await AtlasSpriteSheetController.post(req, res, options),
38
+ );
26
39
  router.get(`/blob/:itemKey`, async (req, res) => await AtlasSpriteSheetController.blob(req, res, options));
27
40
  // Metadata endpoints: returns itemKey, atlasWidth, atlasHeight, cellPixelDim, frames (no fileId).
28
41
  // Client fetches /metadata/:itemKey once, caches it, then fetches /blob/:itemKey for the PNG.
29
- router.get(`/metadata/:itemKey`, async (req, res) => await AtlasSpriteSheetController.getMetadata(req, res, options));
42
+ router.get(
43
+ `/metadata/:itemKey`,
44
+ async (req, res) => await AtlasSpriteSheetController.getMetadata(req, res, options),
45
+ );
30
46
  router.get(`/metadata`, async (req, res) => await AtlasSpriteSheetController.getMetadata(req, res, options));
31
47
  router.get(
32
48
  `/:id`,
@@ -34,10 +50,30 @@ class AtlasSpriteSheetRouter {
34
50
  async (req, res) => await AtlasSpriteSheetController.get(req, res, options),
35
51
  );
36
52
  router.get(`/`, async (req, res) => await AtlasSpriteSheetController.get(req, res, options));
37
- router.put(`/:id`, options.authMiddleware, async (req, res) => await AtlasSpriteSheetController.put(req, res, options));
38
- router.put(`/`, options.authMiddleware, async (req, res) => await AtlasSpriteSheetController.put(req, res, options));
39
- router.delete(`/:id`, options.authMiddleware, async (req, res) => await AtlasSpriteSheetController.delete(req, res, options));
40
- router.delete(`/`, options.authMiddleware, async (req, res) => await AtlasSpriteSheetController.delete(req, res, options));
53
+ router.put(
54
+ `/:id`,
55
+ options.authMiddleware,
56
+ moderatorGuard,
57
+ async (req, res) => await AtlasSpriteSheetController.put(req, res, options),
58
+ );
59
+ router.put(
60
+ `/`,
61
+ options.authMiddleware,
62
+ moderatorGuard,
63
+ async (req, res) => await AtlasSpriteSheetController.put(req, res, options),
64
+ );
65
+ router.delete(
66
+ `/:id`,
67
+ options.authMiddleware,
68
+ moderatorGuard,
69
+ async (req, res) => await AtlasSpriteSheetController.delete(req, res, options),
70
+ );
71
+ router.delete(
72
+ `/`,
73
+ options.authMiddleware,
74
+ adminGuard,
75
+ async (req, res) => await AtlasSpriteSheetController.delete(req, res, options),
76
+ );
41
77
  return router;
42
78
  }
43
79
  }
@@ -1,10 +1,10 @@
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 { AtlasSpriteSheetGenerator } from '../../server/atlas-sprite-sheet-generator.js';
4
+ import { AtlasSpriteSheetGenerator } from '../../projects/cyberia/atlas-sprite-sheet-generator.js';
5
5
  import { FileFactory } from '../file/file.service.js';
6
6
  import { AtlasSpriteSheetDto } from './atlas-sprite-sheet.model.js';
7
- import { IpfsClient } from '../../server/ipfs-client.js';
7
+ import { IpfsClient } from '../../projects/cyberia/ipfs-client.js';
8
8
  import { createPinRecord, removePinRecordsAndUnpin } from '../ipfs/ipfs.service.js';
9
9
 
10
10
  const logger = loggerFactory(import.meta);
@@ -54,10 +54,9 @@ async function withResolvedAtlasFrameDuration(doc, ObjectLayer) {
54
54
  class AtlasSpriteSheetService {
55
55
  static blob = async (req, res, options) => {
56
56
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
57
- const AtlasSpriteSheet =
58
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
57
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
59
58
  /** @type {import('../file/file.model.js').FileModel} */
60
- const File = DataBaseProviderService.getModel("File", options);
59
+ const File = DataBaseProviderService.getModel('File', options);
61
60
 
62
61
  const itemKey = req.params.itemKey;
63
62
  const atlasDoc = await AtlasSpriteSheet.findOne({ 'metadata.itemKey': itemKey }).lean();
@@ -70,12 +69,11 @@ class AtlasSpriteSheetService {
70
69
  };
71
70
  static generate = async (req, res, options, generateOptions = {}) => {
72
71
  /** @type {import('../object-layer/object-layer.model.js').ObjectLayerModel} */
73
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
72
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
74
73
  /** @type {import('../file/file.model.js').FileModel} */
75
- const File = DataBaseProviderService.getModel("File", options);
74
+ const File = DataBaseProviderService.getModel('File', options);
76
75
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
77
- const AtlasSpriteSheet =
78
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
76
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
79
77
 
80
78
  let objectLayer = req.objectLayer;
81
79
 
@@ -195,12 +193,11 @@ class AtlasSpriteSheetService {
195
193
  };
196
194
  static deleteByObjectLayerId = async (req, res, options) => {
197
195
  /** @type {import('../object-layer/object-layer.model.js').ObjectLayerModel} */
198
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
196
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
199
197
  /** @type {import('../file/file.model.js').FileModel} */
200
- const File = DataBaseProviderService.getModel("File", options);
198
+ const File = DataBaseProviderService.getModel('File', options);
201
199
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
202
- const AtlasSpriteSheet =
203
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
200
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
204
201
 
205
202
  const objectLayer = await ObjectLayer.findById(req.params.id);
206
203
  if (!objectLayer) {
@@ -254,14 +251,12 @@ class AtlasSpriteSheetService {
254
251
  };
255
252
  static post = async (req, res, options) => {
256
253
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
257
- const AtlasSpriteSheet =
258
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
254
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
259
255
  return await new AtlasSpriteSheet(req.body).save();
260
256
  };
261
257
  static get = async (req, res, options) => {
262
258
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
263
- const AtlasSpriteSheet =
264
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
259
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
265
260
  if (req.params.id)
266
261
  return await AtlasSpriteSheet.findById(req.params.id)
267
262
  .select(AtlasSpriteSheetDto.select.get())
@@ -287,10 +282,9 @@ class AtlasSpriteSheetService {
287
282
  // Client fetches this once per itemKey, caches it, then fetches the PNG blob.
288
283
  static getMetadata = async (req, res, options) => {
289
284
  /** @type {import('../object-layer/object-layer.model.js').ObjectLayerModel} */
290
- const ObjectLayer = DataBaseProviderService.getModel("ObjectLayer", options);
285
+ const ObjectLayer = DataBaseProviderService.getModel('ObjectLayer', options);
291
286
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
292
- const AtlasSpriteSheet =
293
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
287
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
294
288
 
295
289
  if (req.params.itemKey) {
296
290
  const doc = await AtlasSpriteSheet.findOne({ 'metadata.itemKey': req.params.itemKey })
@@ -328,16 +322,14 @@ class AtlasSpriteSheetService {
328
322
  };
329
323
  static put = async (req, res, options) => {
330
324
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
331
- const AtlasSpriteSheet =
332
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
325
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
333
326
  return await AtlasSpriteSheet.findByIdAndUpdate(req.params.id, req.body);
334
327
  };
335
328
  static delete = async (req, res, options) => {
336
329
  /** @type {import('./atlas-sprite-sheet.model.js').AtlasSpriteSheetModel} */
337
- const AtlasSpriteSheet =
338
- DataBaseProviderService.getModel("AtlasSpriteSheet", options);
330
+ const AtlasSpriteSheet = DataBaseProviderService.getModel('AtlasSpriteSheet', options);
339
331
  /** @type {import('../file/file.model.js').FileModel} */
340
- const File = DataBaseProviderService.getModel("File", options);
332
+ const File = DataBaseProviderService.getModel('File', options);
341
333
 
342
334
  if (req.params.id) {
343
335
  const atlasDoc = await AtlasSpriteSheet.findById(req.params.id);
@@ -39,6 +39,25 @@ class CyberiaActionController {
39
39
  });
40
40
  }
41
41
  };
42
+ static getByCode = async (req, res, options) => {
43
+ try {
44
+ if (req && req.headers && req.headers.origin) {
45
+ res.set('Access-Control-Allow-Origin', req.headers.origin);
46
+ } else res.setHeader('Access-Control-Allow-Origin', '*');
47
+ res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
48
+ const result = await CyberiaActionService.getByCode(req, res, options);
49
+ return res.status(200).json({
50
+ status: 'success',
51
+ data: result,
52
+ });
53
+ } catch (error) {
54
+ logger.error(error, error.stack);
55
+ return res.status(404).json({
56
+ status: 'error',
57
+ message: error.message,
58
+ });
59
+ }
60
+ };
42
61
  static put = async (req, res, options) => {
43
62
  try {
44
63
  const result = await CyberiaActionService.put(req, res, options);
@@ -1,48 +1,42 @@
1
1
  import { Schema, model } from 'mongoose';
2
- import { CYBERIA_ACTION_TYPES } from '../../client/components/cyberia/SharedDefaultsCyberia.js';
3
2
 
4
3
  // https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
5
4
 
6
5
  const CyberiaActionSchema = new Schema(
7
6
  {
8
- // Spatial origin: the NPC/entity cell that provides this action.
9
- // Matched against map entity initCellX/initCellY during instance init
10
- // and assignable from ObjectLayerEngineModal.
7
+ // Spatial origin: the cell whose matching bot entity provides this action.
8
+ // An action has NO type its capabilities are whatever payloads are
9
+ // populated (questDialogueCodes / shopItems / craftRecipes / storageSlots),
10
+ // resolved per player. The quest-provider capability is active when there
11
+ // are CyberiaQuests bound to this same (sourceMapCode, sourceCellX,
12
+ // sourceCellY).
11
13
  sourceMapCode: { type: String, trim: true },
12
14
  sourceCellX: { type: Number },
13
15
  sourceCellY: { type: Number },
14
16
 
15
17
  // ── Identity ──────────────────────────────────────────────────────────
18
+ // `code` is a generic, location-scoped slug (it associates the action with
19
+ // its cell, not a single behavior). `label` is the name shown on the bot's
20
+ // overhead nameplate (the client fetches it by code via REST).
16
21
  code: { type: String, required: true, trim: true },
17
- type: {
18
- type: String,
19
- required: true,
20
- trim: true,
21
- enum: CYBERIA_ACTION_TYPES,
22
- },
23
22
  label: { type: String, trim: true, default: '' },
24
23
 
25
- // The item ID of the NPC/entity that provides this action.
26
- // Used to match 'talk' quest objectives: a step with { type: 'talk', itemId: X }
27
- // is satisfied when the player triggers an action where provideItemId === X.
28
- // Typically the entity's active skin ObjectLayer item ID (e.g. 'wason', 'alex').
29
- provideItemId: { type: String, trim: true, default: '' },
30
-
31
- // Quest code granted to the player on their first interaction with this action.
32
- // Used by 'quest-talk' NPCs to start a quest chain on first contact.
33
- // Empty string = no quest granted.
34
- grantQuestCode: { type: String, trim: true, default: '' },
35
-
36
24
  // ── Dialogue ──────────────────────────────────────────────────────────
37
- // General greeting/intro dialogue shown when the action button is tapped.
25
+ // General greeting shown when the interaction modal opens. Empty = client
26
+ // falls back to /code/default-<skin> from the entity's active skin.
38
27
  dialogCode: { type: String, trim: true, default: '' },
39
28
 
40
- // Ordered list of CyberiaDialogue codes the player must view to satisfy
41
- // a 'talk' quest objective linked to this action via provideItemId.
42
- // For simple actions this may match dialogCode; for multi-stage NPCs it can diverge.
43
- questDialogueCodes: [{ type: String, trim: true }],
29
+ // Per-quest dialogue map: the CyberiaDialogue code to display for each quest
30
+ // this NPC handles. The server validates a `talk` objective only when the
31
+ // viewed dialogCode matches the entry for that quest.
32
+ questDialogueCodes: [
33
+ {
34
+ questCode: { type: String, required: true, trim: true },
35
+ dialogCode: { type: String, required: true, trim: true },
36
+ },
37
+ ],
44
38
 
45
- // ── Shop payload (type="shop") ─────────────────────────────────────────
39
+ // ── Shop payload ──────────────────────────────────────────────────────
46
40
  shopItems: [
47
41
  {
48
42
  itemId: { type: String, required: true, trim: true },
@@ -76,8 +70,6 @@ const CyberiaActionSchema = new Schema(
76
70
  );
77
71
 
78
72
  CyberiaActionSchema.index({ code: 1 }, { unique: true });
79
- CyberiaActionSchema.index({ provideItemId: 1 });
80
- CyberiaActionSchema.index({ grantQuestCode: 1 }, { sparse: true });
81
73
  CyberiaActionSchema.index({ sourceMapCode: 1, sourceCellX: 1, sourceCellY: 1 });
82
74
 
83
75
  const CyberiaActionModel = model('CyberiaAction', CyberiaActionSchema);
@@ -1,6 +1,7 @@
1
1
  import { loggerFactory } from '../../server/logger.js';
2
2
  import { CyberiaActionController } from './cyberia-action.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,51 @@ class CyberiaActionRouter {
11
12
  */
12
13
  static router(options) {
13
14
  const router = express.Router();
14
- router.post(`/:id`, async (req, res) => await CyberiaActionController.post(req, res, options));
15
- router.post(`/`, async (req, res) => await CyberiaActionController.post(req, res, options));
16
- router.get(`/:id`,
15
+ router.post(
16
+ `/:id`,
17
+ options.authMiddleware,
18
+ moderatorGuard,
19
+ async (req, res) => await CyberiaActionController.post(req, res, options),
20
+ );
21
+ router.post(
22
+ `/`,
23
+ options.authMiddleware,
24
+ moderatorGuard,
25
+ async (req, res) => await CyberiaActionController.post(req, res, options),
26
+ );
27
+ // Direct lookup by code — the client fetches an NPC's action metadata
28
+ // (label, dialogue map) by the action code the Go server sends over AOI.
29
+ router.get(`/code/:code`, async (req, res) => await CyberiaActionController.getByCode(req, res, options));
30
+ router.get(
31
+ `/:id`,
17
32
  // options.authMiddleware,
18
33
  async (req, res) => await CyberiaActionController.get(req, res, options),
19
34
  );
20
35
  router.get(`/`, async (req, res) => await CyberiaActionController.get(req, res, options));
21
- router.put(`/:id`, async (req, res) => await CyberiaActionController.put(req, res, options));
22
- router.put(`/`, async (req, res) => await CyberiaActionController.put(req, res, options));
23
- router.delete(`/:id`, async (req, res) => await CyberiaActionController.delete(req, res, options));
24
- router.delete(`/`, async (req, res) => await CyberiaActionController.delete(req, res, options));
36
+ router.put(
37
+ `/:id`,
38
+ options.authMiddleware,
39
+ moderatorGuard,
40
+ async (req, res) => await CyberiaActionController.put(req, res, options),
41
+ );
42
+ router.put(
43
+ `/`,
44
+ options.authMiddleware,
45
+ moderatorGuard,
46
+ async (req, res) => await CyberiaActionController.put(req, res, options),
47
+ );
48
+ router.delete(
49
+ `/:id`,
50
+ options.authMiddleware,
51
+ moderatorGuard,
52
+ async (req, res) => await CyberiaActionController.delete(req, res, options),
53
+ );
54
+ router.delete(
55
+ `/`,
56
+ options.authMiddleware,
57
+ adminGuard,
58
+ async (req, res) => await CyberiaActionController.delete(req, res, options),
59
+ );
25
60
  return router;
26
61
  }
27
62
  }
@@ -1,18 +1,19 @@
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 { DefaultCyberiaActions } from '../cyberia-server-defaults/cyberia-server-defaults.js';
4
5
 
5
6
  const logger = loggerFactory(import.meta);
6
7
 
7
8
  class CyberiaActionService {
8
9
  static post = async (req, res, options) => {
9
10
  /** @type {import('./cyberia-action.model.js').CyberiaActionModel} */
10
- const CyberiaAction = DataBaseProviderService.getModel("CyberiaAction", options);
11
+ const CyberiaAction = DataBaseProviderService.getModel('CyberiaAction', options);
11
12
  return await new CyberiaAction(req.body).save();
12
13
  };
13
14
  static get = async (req, res, options) => {
14
15
  /** @type {import('./cyberia-action.model.js').CyberiaActionModel} */
15
- const CyberiaAction = DataBaseProviderService.getModel("CyberiaAction", options);
16
+ const CyberiaAction = DataBaseProviderService.getModel('CyberiaAction', options);
16
17
  if (req.params.id) return await CyberiaAction.findById(req.params.id);
17
18
 
18
19
  // Parse query parameters using DataQuery helper
@@ -26,14 +27,29 @@ class CyberiaActionService {
26
27
  const totalPages = Math.ceil(total / limit);
27
28
  return { data, total, page, totalPages };
28
29
  };
30
+ static getByCode = async (req, res, options) => {
31
+ /** @type {import('./cyberia-action.model.js').CyberiaActionModel} */
32
+ const CyberiaAction = DataBaseProviderService.getModel('CyberiaAction', options);
33
+ const { code } = req.params;
34
+ if (!code) throw new Error('code parameter is required');
35
+ const data = await CyberiaAction.findOne({ code }).lean();
36
+ if (data) return data;
37
+ // Fallback world delivers actions to the Go server from the canonical
38
+ // defaults without persisting them; serve those so the client can fetch the
39
+ // action's label + dialogue map by code. Quest OFFERS are NOT resolved here —
40
+ // the client locates offered quests via the cyberia-quest API by cell.
41
+ const fallback = DefaultCyberiaActions.find((a) => a.code === code);
42
+ if (fallback) return fallback;
43
+ throw new Error(`No action found for code: ${code}`);
44
+ };
29
45
  static put = async (req, res, options) => {
30
46
  /** @type {import('./cyberia-action.model.js').CyberiaActionModel} */
31
- const CyberiaAction = DataBaseProviderService.getModel("CyberiaAction", options);
47
+ const CyberiaAction = DataBaseProviderService.getModel('CyberiaAction', options);
32
48
  return await CyberiaAction.findByIdAndUpdate(req.params.id, req.body);
33
49
  };
34
50
  static delete = async (req, res, options) => {
35
51
  /** @type {import('./cyberia-action.model.js').CyberiaActionModel} */
36
- const CyberiaAction = DataBaseProviderService.getModel("CyberiaAction", options);
52
+ const CyberiaAction = DataBaseProviderService.getModel('CyberiaAction', options);
37
53
  if (req.params.id) return await CyberiaAction.findByIdAndDelete(req.params.id);
38
54
  else return await CyberiaAction.deleteMany();
39
55
  };