@underpostnet/cyberia 3.3.73 → 3.3.77

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 (269) hide show
  1. package/.env.example +17 -5
  2. package/.github/workflows/coverall.cyberia.ci.yml +10 -0
  3. package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
  4. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
  5. package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
  6. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
  7. package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
  8. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
  9. package/.github/workflows/engine-cyberia.ci.yml +1 -1
  10. package/.github/workflows/publish.cyberia.ci.yml +44 -0
  11. package/AGENTS.md +61 -12
  12. package/CHANGELOG.md +159 -161
  13. package/CLI-HELP.md +20 -13
  14. package/Dockerfile +1 -1
  15. package/Dockerfile.dev +1 -1
  16. package/Dockerfile.test +2 -2
  17. package/README.md +28 -28
  18. package/bin/build.js +96 -21
  19. package/bin/cyberia.js +1247 -1373
  20. package/bin/index.js +1247 -1373
  21. package/compose.env +17 -5
  22. package/conf.js +7 -4
  23. package/deploy/cyberia-client/deploy.sh +10 -11
  24. package/deploy/cyberia-client/package.sh +0 -1
  25. package/deploy/cyberia-client/state.sh +3 -2
  26. package/deploy/cyberia-server/deploy.sh +10 -11
  27. package/deploy/cyberia-server/package.sh +0 -1
  28. package/deploy/cyberia-server/state.sh +3 -2
  29. package/deploy/dd-cyberia/deploy.sh +5 -5
  30. package/deploy/dd-cyberia/init.sh +15 -14
  31. package/deploy/dd-cyberia/package.sh +0 -1
  32. package/deploy/dd-cyberia/state.sh +2 -2
  33. package/deploy/dd-cyberia/sync-deploy.sh +139 -75
  34. package/deploy/lib/config.sh +29 -0
  35. package/deploy/lib/github-actions-logging.sh +92 -76
  36. package/deploy/lib/host.sh +28 -19
  37. package/deploy/lib/state.sh +4 -1
  38. package/deploy/pwa-microservices-template/deploy.sh +10 -8
  39. package/deploy/release/deploy.sh +0 -2
  40. package/deployment.yaml +1 -1
  41. package/docker-compose.yml +23 -17
  42. package/docs/coverage/cyberia/api/cyberia-instance/cyberia-fallback-capture.js.html +1591 -0
  43. package/docs/coverage/cyberia/api/cyberia-instance/index.html +116 -0
  44. package/docs/coverage/cyberia/api/cyberia-server-defaults/cyberia-server-defaults.js.html +4138 -0
  45. package/docs/coverage/cyberia/api/cyberia-server-defaults/index.html +116 -0
  46. package/docs/coverage/cyberia/api/object-layer/index.html +116 -0
  47. package/docs/coverage/cyberia/api/object-layer/object-layer.model.js.html +1393 -0
  48. package/docs/coverage/cyberia/base.css +362 -0
  49. package/docs/coverage/cyberia/block-navigation.js +82 -0
  50. package/docs/coverage/cyberia/favicon.png +0 -0
  51. package/docs/coverage/cyberia/index.html +161 -0
  52. package/docs/coverage/cyberia/prettify.css +101 -0
  53. package/docs/coverage/cyberia/prettify.js +937 -0
  54. package/docs/coverage/cyberia/projects/cyberia/atlas-sprite-sheet-generator.js.html +1315 -0
  55. package/docs/coverage/cyberia/projects/cyberia/index.html +176 -0
  56. package/docs/coverage/cyberia/projects/cyberia/instance-backup.js.html +715 -0
  57. package/docs/coverage/cyberia/projects/cyberia/instance-data.js.html +2182 -0
  58. package/docs/coverage/cyberia/projects/cyberia/shape-generator.js.html +3265 -0
  59. package/docs/coverage/cyberia/projects/cyberia/stat-balance.js.html +328 -0
  60. package/docs/coverage/cyberia/sort-arrow-sprite.png +0 -0
  61. package/docs/coverage/cyberia/sorter.js +205 -0
  62. package/hardhat/package-lock.json +2 -2
  63. package/hardhat/package.json +1 -1
  64. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  65. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
  66. package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
  67. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  68. package/manifests/deployment/mongo-express/deployment.yaml +46 -27
  69. package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
  70. package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
  71. package/manifests/deployment/mongo-express/service.yaml +16 -0
  72. package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
  73. package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
  74. package/package.json +19 -17
  75. package/scripts/test-monitor.sh +3 -3
  76. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
  77. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
  78. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
  79. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
  80. package/src/api/cyberia-action/cyberia-action.router.js +2 -2
  81. package/src/api/cyberia-action/cyberia-action.service.js +3 -4
  82. package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
  83. package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
  84. package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
  85. package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
  86. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -3
  87. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
  88. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
  89. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
  90. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
  91. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  92. package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
  93. package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
  94. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
  95. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
  96. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +16 -1
  97. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
  98. package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
  99. package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -40
  100. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
  101. package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
  102. package/src/api/cyberia-instance/cyberia-instance-map.service.js +34 -141
  103. package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
  104. package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
  105. package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
  106. package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
  107. package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
  108. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
  109. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
  110. package/src/api/cyberia-map/cyberia-map.service.js +6 -2
  111. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
  112. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
  113. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
  114. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
  115. package/src/api/cyberia-quest/cyberia-quest.router.js +3 -3
  116. package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
  117. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
  118. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
  119. package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
  120. package/src/api/file/file.ref.js +153 -0
  121. package/src/api/file/file.ref.json +11 -2
  122. package/src/api/object-layer/object-layer.model.js +47 -12
  123. package/src/api/object-layer/object-layer.router.js +10 -3
  124. package/src/api/object-layer/object-layer.service.js +113 -120
  125. package/src/cli/app.js +12 -1
  126. package/src/cli/client.js +2 -2
  127. package/src/cli/cluster.js +80 -18
  128. package/src/cli/deploy.js +215 -34
  129. package/src/cli/docker-compose.js +1 -1
  130. package/src/cli/fs-selection.js +115 -0
  131. package/src/cli/fs.js +158 -342
  132. package/src/cli/index.js +22 -10
  133. package/src/cli/release.js +3 -1
  134. package/src/cli/repository.js +35 -9
  135. package/src/cli/run.js +80 -199
  136. package/src/cli/test.js +4 -0
  137. package/src/cli/wireguard.js +32 -31
  138. package/src/client/components/core/Badge.js +0 -1
  139. package/src/client/components/core/CssCore.js +8 -1
  140. package/src/client/components/core/Docs.js +77 -100
  141. package/src/client/components/core/Modal.js +77 -23
  142. package/src/client/components/core/ToolTip.js +15 -0
  143. package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +0 -2
  144. package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
  145. package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
  146. package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
  147. package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
  148. package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
  149. package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
  150. package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
  151. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
  152. package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
  153. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +0 -34
  154. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
  155. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
  156. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +0 -4
  157. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
  158. package/src/client/components/default/AppShellDefault.js +1 -4
  159. package/src/client/components/itemledger/AppShellItemledger.js +0 -2
  160. package/src/client/components/underpost/AppShellUnderpost.js +1 -1
  161. package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
  162. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
  163. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
  164. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
  165. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
  166. package/src/client/public/cyberia-docs/CYBERIA.md +28 -28
  167. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
  168. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  169. package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
  170. package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
  171. package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
  172. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
  173. package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
  174. package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
  175. package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
  176. package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
  177. package/src/client/services/object-layer/object-layer.management.js +6 -10
  178. package/src/client/services/object-layer/object-layer.service.js +3 -1
  179. package/src/client/ssr/views/Cyberia404.js +3 -3
  180. package/src/client-builder/client-build-docs.js +52 -52
  181. package/src/client-builder/client-build.js +67 -44
  182. package/src/client-builder/client-bundle.js +347 -0
  183. package/src/db/mongo/MongoExpress.js +187 -0
  184. package/src/grpc/cyberia/grpc-server.js +5 -7
  185. package/src/index.js +1 -1
  186. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
  187. package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
  188. package/src/projects/cyberia/besu-genesis-generator.js +5 -14
  189. package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
  190. package/src/projects/cyberia/catalog-cyberia.js +3 -2
  191. package/src/projects/cyberia/gemini-client.js +3 -3
  192. package/src/projects/cyberia/generate-saga.js +4 -11
  193. package/src/projects/cyberia/hot-reload-trigger.js +17 -28
  194. package/src/projects/cyberia/instance-backup.js +210 -0
  195. package/src/projects/cyberia/instance-data.js +177 -257
  196. package/src/projects/cyberia/map-preview-generator.js +32 -68
  197. package/src/projects/cyberia/object-layer.js +152 -319
  198. package/src/projects/cyberia/seed-audio.js +139 -0
  199. package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
  200. package/src/projects/cyberia/semantic-layer-generator.js +2 -18
  201. package/src/projects/cyberia/stat-balance.js +81 -0
  202. package/src/projects/cyberia/stat-commands.js +23 -0
  203. package/src/projects/cyberia/stat-contract-generator.js +101 -0
  204. package/src/runtime/cyberia-client/Dockerfile +8 -4
  205. package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
  206. package/src/runtime/cyberia-server/Dockerfile +9 -2
  207. package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
  208. package/src/runtime/engine-cyberia/Dockerfile +1 -1
  209. package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
  210. package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
  211. package/src/runtime/engine-cyberia/compose.env +17 -5
  212. package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
  213. package/src/server/build/coverage.js +113 -42
  214. package/src/server/build/package.js +55 -12
  215. package/src/server/build/testing.js +59 -9
  216. package/src/server/network/middlewares.js +8 -2
  217. package/src/server/network/underpost-gateway.js +113 -14
  218. package/src/server/ops/logger.js +70 -35
  219. package/src/server/runtime/conf.js +40 -9
  220. package/src/server/runtime/start.js +11 -2
  221. package/src/server/storage/data-query.js +16 -0
  222. package/src/server/storage/downloader.js +62 -14
  223. package/src/server/storage/zip.js +153 -0
  224. package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
  225. package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
  226. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +34 -0
  227. package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
  228. package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
  229. package/test/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
  230. package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
  231. package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
  232. package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
  233. package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
  234. package/test/integration/app/cyberia/fallback-world-capture.test.js +87 -2
  235. package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
  236. package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
  237. package/test/integration/app/cyberia/seed-audio.test.js +275 -0
  238. package/test/integration/infra/2-network/wireguard-cli.test.js +33 -9
  239. package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
  240. package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
  241. package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
  242. package/test/integration/infra/4-ingress/underpost-ingress.test.js +1 -1
  243. package/test/unit/catalog.test.js +13 -2
  244. package/test/unit/client-build-docs.test.js +97 -70
  245. package/test/unit/client-bundle.test.js +313 -0
  246. package/test/unit/conf-resolution.test.js +58 -7
  247. package/test/unit/coverage-artifact.test.js +120 -29
  248. package/test/unit/cyberia/instance-backup.test.js +183 -0
  249. package/test/unit/cyberia/instance-data.test.js +314 -0
  250. package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
  251. package/test/unit/cyberia/publish-workflow.test.js +22 -0
  252. package/test/unit/cyberia/stat-balance.test.js +69 -0
  253. package/test/unit/deploy-legacy-gateway-sweep.test.js +63 -0
  254. package/test/unit/deploy-log-table.test.js +76 -5
  255. package/test/unit/downloader-integrity.test.js +98 -0
  256. package/test/unit/file-reference-registry.test.js +141 -0
  257. package/test/unit/fs-storage-paths.test.js +596 -0
  258. package/test/unit/gateway-pod-fetch.test.js +95 -0
  259. package/test/unit/letsencrypt-issuer.test.js +101 -0
  260. package/test/unit/logger-redaction.test.js +29 -0
  261. package/test/unit/package.test.js +70 -16
  262. package/test/unit/prepare-host.test.js +84 -1
  263. package/test/unit/release-bump.test.js +3 -1
  264. package/test/unit/start-options.test.js +12 -0
  265. package/test/unit/test-tiers.test.js +27 -0
  266. package/test/unit/zip-archive.test.js +142 -0
  267. package/vitest.config.js +11 -3
  268. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
  269. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
@@ -173,10 +173,7 @@ class Docs {
173
173
 
174
174
  Modal.Data[ModalId].onObserverListener[ModalId] = () => {
175
175
  resizeIframe();
176
- if (type.match('coverage')) {
177
- simpleIconsRender(`.doc-icon-coverage`);
178
- simpleIconsRender(`.doc-icon-coverage-link`);
179
- }
176
+ if (type.match('coverage')) simpleIconsRender(`.doc-icon-coverage`);
180
177
  };
181
178
  Modal.Data[ModalId].onObserverListener[ModalId]();
182
179
  // The observer fires on modal mutations, not on viewport changes; a rotate
@@ -189,105 +186,87 @@ class Docs {
189
186
  closeModalRouteChangeEvent({ closedId: ModalId });
190
187
  };
191
188
  }
192
- static Data = [
193
- {
194
- type: 'repo',
195
- icon: html`<i class="fab fa-github"></i>`,
196
- text: `Last Release`,
197
- url: function () {
198
- const tokenOpts = Docs.Tokens['modal-docs'];
199
- if (tokenOpts && tokenOpts.lastReleaseUrl) return tokenOpts.lastReleaseUrl();
200
- return githubUrl(packageRepository());
201
- },
202
- },
203
- {
204
- type: 'demo',
205
- icon: html`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 32 32">
206
- <path fill="currentColor" d="M20 2v12l10-6z" />
207
- <path
208
- fill="currentColor"
209
- d="M28 14v8H4V6h10V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-8zM18 28h-4v-4h4z"
210
- />
211
- </svg>`,
212
- text: html`Demo`,
213
- url: function () {
214
- const tokenOpts = Docs.Tokens['modal-docs'];
215
- if (tokenOpts && tokenOpts.demoUrl) return tokenOpts.demoUrl();
216
- return githubPagesUrl(packageRepository());
217
- },
218
- },
219
- {
220
- type: 'src',
221
- icon: html`<i class="fa-brands fa-osi"></i>`,
222
- text: 'Source Docs',
223
- url: function () {
224
- return `${getProxyPath()}docs/engine/${window.renderPayload.version.replace('v', '')}`;
225
- },
226
- },
227
- {
228
- type: 'api',
229
- icon: html`<i class="fa-solid fa-arrows-turn-to-dots"></i>`,
230
- text: `Api Docs`,
231
- url: function () {
232
- return `${getProxyPath()}api-docs`;
233
- },
234
- },
235
- {
236
- type: 'coverage',
189
+ // One entry per coverage report the build declared, each framed from /docs/coverage/<id>.
190
+ static coverageReports = () =>
191
+ (window.renderPayload.coverage ?? []).map(({ id, label }) => ({
192
+ type: `coverage-${id}`,
237
193
  icon: html`<img height="20" width="20" class="doc-icon-coverage" />`,
238
- text: `Coverage report`,
239
- url: function () {
240
- const tokenOpts = Docs.Tokens['modal-docs'];
241
- if (tokenOpts && tokenOpts.coverageUrl) return tokenOpts.coverageUrl();
242
- return `${getProxyPath()}docs/coverage`;
194
+ text: label,
195
+ url: () => `${getProxyPath()}docs/coverage/${id}`,
196
+ }));
197
+ static get Data() {
198
+ return [
199
+ {
200
+ type: 'repo',
201
+ external: true,
202
+ icon: html`<i class="fab fa-github"></i>`,
203
+ text: `Last Release`,
204
+ url: function () {
205
+ const tokenOpts = Docs.Tokens['modal-docs'];
206
+ if (tokenOpts && tokenOpts.lastReleaseUrl) return tokenOpts.lastReleaseUrl();
207
+ return githubUrl(packageRepository());
208
+ },
243
209
  },
244
- themeEvent: () => {
245
- if (s(`.doc-icon-coverage`)) setTimeout(() => simpleIconsRender(`.doc-icon-coverage`));
210
+ {
211
+ type: 'demo',
212
+ external: true,
213
+ icon: html`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 32 32">
214
+ <path fill="currentColor" d="M20 2v12l10-6z" />
215
+ <path
216
+ fill="currentColor"
217
+ d="M28 14v8H4V6h10V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-8zM18 28h-4v-4h4z"
218
+ />
219
+ </svg>`,
220
+ text: html`Demo`,
221
+ url: function () {
222
+ const tokenOpts = Docs.Tokens['modal-docs'];
223
+ if (tokenOpts && tokenOpts.demoUrl) return tokenOpts.demoUrl();
224
+ return githubPagesUrl(packageRepository());
225
+ },
246
226
  },
247
- },
248
- {
249
- type: 'coverage-link',
250
- icon: html`<img height="20" width="20" class="doc-icon-coverage-link" />`,
251
- text: `Coverage`,
252
- url: function () {
253
- const tokenOpts = Docs.Tokens['modal-docs'];
254
- if (tokenOpts && tokenOpts.coverageLinkUrl) return tokenOpts.coverageLinkUrl();
255
- return coverallsUrl();
227
+ {
228
+ type: 'src',
229
+ icon: html`<i class="fa-brands fa-osi"></i>`,
230
+ text: 'Source Docs',
231
+ url: function () {
232
+ return `${getProxyPath()}docs/engine/${window.renderPayload.version.replace('v', '')}`;
233
+ },
256
234
  },
257
- themeEvent: () => {
258
- if (s(`.doc-icon-coverage-link`)) setTimeout(() => simpleIconsRender(`.doc-icon-coverage-link`));
235
+ {
236
+ type: 'api',
237
+ icon: html`<i class="fa-solid fa-arrows-turn-to-dots"></i>`,
238
+ text: `Api Docs`,
239
+ url: function () {
240
+ return `${getProxyPath()}api-docs`;
241
+ },
259
242
  },
260
- },
261
- ];
243
+ ...Docs.coverageReports(),
244
+ {
245
+ type: 'coverage-link',
246
+ external: true,
247
+ icon: html`<img height="20" width="20" class="doc-icon-coverage" />`,
248
+ text: `Coverage`,
249
+ url: function () {
250
+ const tokenOpts = Docs.Tokens['modal-docs'];
251
+ if (tokenOpts && tokenOpts.coverageLinkUrl) return tokenOpts.coverageLinkUrl();
252
+ return coverallsUrl();
253
+ },
254
+ },
255
+ ];
256
+ }
262
257
  static Tokens = {};
263
258
  static async instance(options = {}) {
264
259
  const { idModal } = options;
265
260
  Docs.Tokens[idModal] = options;
266
261
  setTimeout(() => {
267
- s(`.btn-docs-src`).onclick = async () => {
268
- setQueryPath({ path: 'docs', queryPath: 'src' });
269
- await Docs.RenderModal('src', idModal);
270
- };
271
- s(`.btn-docs-api`).onclick = async () => {
272
- setQueryPath({ path: 'docs', queryPath: 'api' });
273
- await Docs.RenderModal('api', idModal);
274
- };
275
- s(`.btn-docs-coverage`).onclick = async () => {
276
- setQueryPath({ path: 'docs', queryPath: 'coverage' });
277
- await Docs.RenderModal('coverage', idModal);
278
- };
279
- s(`.btn-docs-coverage-link`).onclick = () => {
280
- const docData = Docs.Data.find((d) => d.type === 'coverage-link');
281
- location.href = docData.url();
282
- };
283
- s(`.btn-docs-repo`).onclick = () => {
284
- const docData = Docs.Data.find((d) => d.type === 'repo');
285
- location.href = docData.url();
286
- };
287
- s(`.btn-docs-demo`).onclick = () => {
288
- const docData = Docs.Data.find((d) => d.type === 'demo');
289
- location.href = docData.url();
290
- };
262
+ // An external entry leaves the app; the rest open in a framed modal on their own route.
263
+ for (const docData of Docs.Data) {
264
+ s(`.btn-docs-${docData.type}`).onclick = async () => {
265
+ if (docData.external) return (location.href = docData.url());
266
+ setQueryPath({ path: 'docs', queryPath: docData.type });
267
+ await Docs.RenderModal(docData.type, idModal);
268
+ };
269
+ }
291
270
  listenQueryPathInstance({
292
271
  id: options.idModal,
293
272
  routeId: 'docs',
@@ -301,13 +280,11 @@ class Docs {
301
280
  },
302
281
  });
303
282
  });
304
- // Register theme events for items that have them (Docs-specific concern)
305
- for (const docData of Docs.Data) {
306
- if (docData.themeEvent) {
307
- ThemeEvents[`doc-icon-${docData.type}`] = docData.themeEvent;
308
- setTimeout(ThemeEvents[`doc-icon-${docData.type}`]);
309
- }
310
- }
283
+ // The coverage icons are tinted to the theme's text colour, so they follow theme changes.
284
+ ThemeEvents['doc-icon-coverage'] = () => {
285
+ if (s(`.doc-icon-coverage`)) setTimeout(() => simpleIconsRender(`.doc-icon-coverage`));
286
+ };
287
+ setTimeout(ThemeEvents['doc-icon-coverage']);
311
288
  // Build submenu items and populate — submenu system is owned by Modal
312
289
  Modal.subMenuPopulate('docs', await Modal.buildSubMenuItemsHtml('docs', Docs.Data, options));
313
290
 
@@ -415,6 +415,19 @@ class Modal {
415
415
  },
416
416
  { key: `slide-menu-${idModal}` },
417
417
  );
418
+ // The fixed hamburger stands in for the top bar's while it is collapsed, opening and
419
+ // closing the menu alike. Its 50px corner is kept clear two ways: the menu content is
420
+ // padded down while it shows, and a view title is padded right only while the menu
421
+ // is closed — an open menu (50px or full) already pushes the views aside.
422
+ const syncFixedMenuButton = () => {
423
+ const fixed = s(`.main-btn-menu-top-fixed-container`);
424
+ if (!fixed) return;
425
+ const collapsed = s(`.main-body-btn-ui-close`) && s(`.main-body-btn-ui-close`).classList.contains('hide');
426
+ const menuClosed = Modal.Data[idModal][options.mode].width === 0;
427
+ fixed.classList[collapsed ? 'remove' : 'add']('hide');
428
+ s('body').classList[collapsed ? 'add' : 'remove']('main-btn-menu-top-fixed-active');
429
+ s('body').classList[collapsed && menuClosed ? 'add' : 'remove']('main-btn-menu-top-fixed-title-offset');
430
+ };
418
431
  barConfig.buttons.menu.onClick = () => {
419
432
  Modal.Data[idModal][options.mode].width = slideMenuWidth;
420
433
  s(`.btn-menu-${idModal}`).classList.add('hide');
@@ -437,6 +450,7 @@ class Modal {
437
450
  } else {
438
451
  s(`.${idModal}`).style.left = `0px`;
439
452
  }
453
+ syncFixedMenuButton();
440
454
  Responsive.triggerChanged(`slide-menu-${idModal}`);
441
455
  };
442
456
  barConfig.buttons.close.onClick = () => {
@@ -460,11 +474,12 @@ class Modal {
460
474
  } else {
461
475
  s(`.${idModal}`).style.left = `-${originSlideMenuWidth}px`;
462
476
  }
477
+ syncFixedMenuButton();
463
478
  Responsive.triggerChanged(`slide-menu-${idModal}`);
464
479
  };
465
480
  transition += `, width 0.3s`;
466
481
 
467
- setTimeout(() => {
482
+ setTimeout(async () => {
468
483
  setTimeout(btnCloseEvent);
469
484
  append(
470
485
  'body',
@@ -517,6 +532,53 @@ class Modal {
517
532
  Modal.actionBtnCenter();
518
533
  };
519
534
 
535
+ // Fixed top-left hamburger, shown only while the top bar is collapsed
536
+ // (main-body-btn-ui-close hidden). Not needed for 'top-bottom-bar' which
537
+ // keeps its own center action button in the bottom bar.
538
+ if (
539
+ idModal === 'modal-menu' &&
540
+ options.mode !== 'slide-menu-right' &&
541
+ options.barMode !== 'top-bottom-bar'
542
+ ) {
543
+ append(
544
+ 'body',
545
+ html`
546
+ <div
547
+ class="fix main-btn-menu-top-fixed-container hide"
548
+ style="top: 0px; left: 0px; z-index: 10; height: ${originHeightTopBar}px; width: ${originHeightTopBar}px"
549
+ >
550
+ ${await BtnIcon.instance({
551
+ style: `height: 100%`,
552
+ class: `in fll main-btn-menu-top action-bar-box action-btn-center-top-fixed`,
553
+ label: html`<div class="abs center">
554
+ <span class="btn-bar-center-icon-close hide">${barConfig.buttons.close.label}</span>
555
+ <span class="btn-bar-center-icon-menu">${barConfig.buttons.menu.label}</span>
556
+ </div>`,
557
+ })}
558
+ </div>
559
+ <style>
560
+ /* The menu content starts below the fixed hamburger while it shows. */
561
+ body.main-btn-menu-top-fixed-active .html-${idModal} {
562
+ padding-top: ${originHeightTopBar}px;
563
+ }
564
+ /* View modals sit at top: 0 while the top bar is collapsed; keep their
565
+ title clear of the fixed hamburger. The padding eases at the same pace
566
+ the views slide so the title moves once, not a jump and a slide back. */
567
+ .title-main-modal {
568
+ transition: padding-left 0.3s;
569
+ }
570
+ body.main-btn-menu-top-fixed-title-offset .title-main-modal {
571
+ padding-left: ${originHeightTopBar}px;
572
+ }
573
+ </style>
574
+ `,
575
+ );
576
+ EventsUI.onClick(`.action-btn-center-top-fixed`, (e) => {
577
+ e.preventDefault();
578
+ Modal.actionBtnCenter();
579
+ });
580
+ }
581
+
520
582
  s(`.main-body-btn-bar-custom`).onclick = () => {
521
583
  if (s(`.main-body-btn-ui-close`).classList.contains('hide')) {
522
584
  s(`.main-body-btn-ui`).click();
@@ -548,6 +610,7 @@ class Modal {
548
610
  options.heightBottomBar = 0;
549
611
  s(`.slide-menu-top-bar`).classList.add('hide');
550
612
  s(`.bottom-bar`).classList.add('hide');
613
+ syncFixedMenuButton();
551
614
  s(`.modal-menu`).style.top = '0px';
552
615
  s(`.main-body-btn-container`).style.top = '50px';
553
616
  s(`.main-body`).style.top = '0px';
@@ -563,6 +626,7 @@ class Modal {
563
626
  s(`.main-body-btn-container`).style.top = `${options.heightTopBar + 50}px`;
564
627
  s(`.slide-menu-top-bar`).classList.remove('hide');
565
628
  s(`.bottom-bar`).classList.remove('hide');
629
+ syncFixedMenuButton();
566
630
  s(`.main-body`).style.top = `${options.heightTopBar}px`;
567
631
  s(`.main-body`).style.height = `${windowGetH() - options.heightTopBar}px`;
568
632
  for (const event of Object.keys(Modal.Data[idModal].onBarUiOpen))
@@ -2829,28 +2893,18 @@ const renderViewTitle = (
2829
2893
  </div>`;
2830
2894
  };
2831
2895
 
2832
- const buildBadgeToolTipMenuOption = (id, sideKey = 'left') => {
2833
- const option = {
2834
- id: `tooltip-content-main-btn-${id}`,
2835
- text: `${Translate.instance(`${id}`)}`,
2836
- classList: 'tooltip-menu',
2837
- style: { top: `-40px` },
2838
- };
2839
- switch (sideKey) {
2840
- case 'left':
2841
- option.style.left = '60px';
2842
-
2843
- break;
2844
-
2845
- case 'right':
2846
- option.style.right = '60px';
2847
- break;
2848
-
2849
- default:
2850
- break;
2851
- }
2852
- return option;
2853
- };
2896
+ /**
2897
+ * Tooltip badge for a collapsed menu button. ToolTip places it beside the button on the side
2898
+ * the menu leaves free, read from the menu mode when it shows — so a shell never pins an
2899
+ * offset that only holds for one of 'slide-menu' or 'slide-menu-right'.
2900
+ * @param {string} id - Translation key and tooltip id suffix.
2901
+ * @param {'left'|'right'} [sideKey] - Forces the side the menu sits on; omit to follow the mode.
2902
+ */
2903
+ const buildBadgeToolTipMenuOption = (id, sideKey) => ({
2904
+ id: `tooltip-content-main-btn-${id}`,
2905
+ text: `${Translate.instance(`${id}`)}`,
2906
+ classList: `tooltip-menu${sideKey ? ` tooltip-menu-side-${sideKey}` : ''}`,
2907
+ });
2854
2908
 
2855
2909
  const isSubMenuOpen = (subMenuId) => {
2856
2910
  return s(`.down-arrow-submenu-${subMenuId}`) && s(`.down-arrow-submenu-${subMenuId}`).style.rotate === '180deg';
@@ -58,6 +58,21 @@ class ToolTip {
58
58
  const tooltipRect = tooltipEl.getBoundingClientRect();
59
59
  let top = containerRect.bottom + window.scrollY + 5;
60
60
  let left = containerRect.left + window.scrollX + containerRect.width / 2 - tooltipRect.width / 2;
61
+ if (options.useMenuBtn) {
62
+ // Beside the collapsed menu button, on the side the menu leaves free: a right-hand menu
63
+ // sits on the window edge, so its tooltips open leftwards. A shell may pin the side.
64
+ const pinned = tooltipEl.querySelector('.tooltip-menu-side-right')
65
+ ? 'right'
66
+ : tooltipEl.querySelector('.tooltip-menu-side-left')
67
+ ? 'left'
68
+ : null;
69
+ const menuSide = pinned || (Modal.Data['modal-menu'].options.mode === 'slide-menu-right' ? 'right' : 'left');
70
+ top = containerRect.top + window.scrollY + (containerRect.height - tooltipRect.height) / 2;
71
+ left =
72
+ menuSide === 'right'
73
+ ? containerRect.left + window.scrollX - tooltipRect.width - 10
74
+ : containerRect.right + window.scrollX + 10;
75
+ }
61
76
  // Adjust if it goes off-screen
62
77
  if (left < 0) left = 5;
63
78
  if (left + tooltipRect.width > window.innerWidth) {
@@ -26,8 +26,6 @@ class AppShellCryptokoyn {
26
26
  const RouterInstance = RouterCryptokoyn.instance();
27
27
 
28
28
  const { barConfig } = await Themes[Css.currentTheme]();
29
-
30
- const badgeNotificationMenuStyle = { top: '-33px', left: '24px' };
31
29
  const barMode = undefined; // 'top-bottom-bar';
32
30
  await Modal.instance({
33
31
  id: 'modal-menu',
@@ -13,7 +13,7 @@ import { CyberiaQuestService } from '../../services/cyberia-quest/cyberia-quest.
13
13
  import { CyberiaActionService } from '../../services/cyberia-action/cyberia-action.service.js';
14
14
  import { CyberiaDialogueService } from '../../services/cyberia-dialogue/cyberia-dialogue.service.js';
15
15
  import { CyberiaSkillService } from '../../services/cyberia-skill/cyberia-skill.service.js';
16
- import { QUEST_STEPS_TYPES, getDefaultCyberiaItemById, SKILL_LOGIC_IDS } from './SharedDefaultsCyberia.js';
16
+ import { QUEST_STEPS_TYPES, SKILL_LOGIC_IDS } from './SharedDefaultsCyberia.js';
17
17
 
18
18
  const textFilter = (filter) => ({ filterType: 'text', type: 'equals', filter });
19
19
  // DropDown invokes optionData.onClick on selection, so every option (including
@@ -90,8 +90,8 @@ class ActionEngineCyberia {
90
90
  containerClass: 'inl',
91
91
  serviceProvider: async (q) => {
92
92
  const result = await ObjectLayerService.searchItemIds({ q });
93
- if (result.status === 'success' && result.data?.itemIds) {
94
- return result.data.itemIds.map((itemId) => dropdownOption(itemId));
93
+ if (result.status === 'success' && result.data?.items) {
94
+ return result.data.items.map(({ id }) => dropdownOption(id));
95
95
  }
96
96
  return [];
97
97
  },
@@ -139,40 +139,16 @@ class ActionEngineCyberia {
139
139
  if (ActionEngineCyberia.imageCache[itemId]) return;
140
140
  ActionEngineCyberia.imageCache[itemId] = { img: null, loaded: false, error: false };
141
141
 
142
- const loadImage = (type, id) => {
143
- const img = new Image();
144
- img.onload = () => {
145
- ActionEngineCyberia.imageCache[itemId].img = img;
146
- ActionEngineCyberia.imageCache[itemId].loaded = true;
147
- if (onLoad) onLoad();
148
- };
149
- img.onerror = () => {
150
- ActionEngineCyberia.imageCache[itemId].error = true;
151
- };
152
- img.src = `${getProxyPath()}assets/${type}/${id}/08/0.png`;
142
+ const img = new Image();
143
+ img.onload = () => {
144
+ ActionEngineCyberia.imageCache[itemId].img = img;
145
+ ActionEngineCyberia.imageCache[itemId].loaded = true;
146
+ if (onLoad) onLoad();
153
147
  };
154
-
155
- const sharedItem = getDefaultCyberiaItemById(itemId)?.item;
156
- if (sharedItem?.type && sharedItem?.id) {
157
- loadImage(sharedItem.type, sharedItem.id);
158
- return;
159
- }
160
-
161
- ObjectLayerService.get({
162
- limit: 1,
163
- filterModel: { 'data.item.id': { filterType: 'text', type: 'equals', filter: itemId } },
164
- })
165
- .then((res) => {
166
- const doc = res?.data?.data?.[0];
167
- if (!doc || !doc.data?.item?.type || !doc.data?.item?.id) {
168
- ActionEngineCyberia.imageCache[itemId].error = true;
169
- return;
170
- }
171
- loadImage(doc.data.item.type, doc.data.item.id);
172
- })
173
- .catch(() => {
174
- ActionEngineCyberia.imageCache[itemId].error = true;
175
- });
148
+ img.onerror = () => {
149
+ ActionEngineCyberia.imageCache[itemId].error = true;
150
+ };
151
+ img.src = `${getProxyPath()}api/atlas-sprite-sheet/idle-preview/${itemId}`;
176
152
  }
177
153
 
178
154
  static preloadMapObjectLayers(onLoad) {