@underpostnet/cyberia 3.2.90 → 3.3.73
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.
- package/.dockerignore +1 -0
- package/.env.example +16 -0
- package/.github/workflows/coverall.cyberia.ci.yml +107 -0
- package/.github/workflows/cyberia-client.cd.yml +6 -18
- package/.github/workflows/cyberia-server.cd.yml +6 -18
- package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
- package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
- package/.github/workflows/engine-cyberia.cd.yml +6 -78
- package/.github/workflows/engine-cyberia.ci.yml +4 -5
- package/.github/workflows/ghpkg.ci.yml +42 -21
- package/.github/workflows/hardhat.ci.yml +12 -11
- package/.github/workflows/npmpkg.ci.yml +17 -15
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
- package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
- package/.github/workflows/release.cd.yml +2 -9
- package/.prettierignore +1 -0
- package/AGENTS.md +47 -0
- package/CHANGELOG.md +581 -2417
- package/CLI-HELP.md +416 -127
- package/Dockerfile +25 -9
- package/Dockerfile.dev +25 -9
- package/Dockerfile.test +4 -4
- package/README.md +21 -1
- package/bin/build.js +70 -43
- package/bin/build.template.js +8 -3
- package/bin/cyberia.js +372 -135
- package/bin/deploy.js +18 -104
- package/bin/index.js +372 -135
- package/compose.env +16 -0
- package/conf.js +93 -4
- package/deploy/cyberia-client/deploy.sh +47 -0
- package/deploy/cyberia-client/package.sh +18 -0
- package/deploy/cyberia-client/state.sh +14 -0
- package/deploy/cyberia-server/deploy.sh +47 -0
- package/deploy/cyberia-server/package.sh +18 -0
- package/deploy/cyberia-server/state.sh +14 -0
- package/deploy/dd-cyberia/deploy.sh +22 -0
- package/deploy/dd-cyberia/init.sh +55 -0
- package/deploy/dd-cyberia/package.sh +17 -0
- package/deploy/dd-cyberia/state.sh +14 -0
- package/deploy/dd-cyberia/sync-deploy.sh +116 -0
- package/deploy/lib/github-actions-logging.sh +594 -0
- package/deploy/lib/host.sh +185 -0
- package/deploy/lib/state.sh +62 -0
- package/deploy/pwa-microservices-template/deploy.sh +45 -0
- package/deploy/release/deploy.sh +32 -0
- package/deployment.yaml +7 -2
- package/docker-compose.yml +31 -37
- package/examples/static-page/README.md +19 -19
- package/examples/static-page/ssr-components/CustomPage.js +2 -2
- package/hardhat/hardhat.config.js +1 -6
- package/hardhat/package-lock.json +104 -43
- package/hardhat/package.json +3 -3
- package/manifests/alertmanager/deployment.yaml +81 -0
- package/manifests/blackbox-exporter/deployment.yaml +75 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/grafana/deployment.yaml +26 -7
- package/manifests/grafana/kustomization.yaml +1 -0
- package/manifests/grafana/service.yaml +6 -1
- package/manifests/mariadb/pv.yaml +1 -0
- package/manifests/mongodb/statefulset.yaml +9 -2
- package/manifests/mysql/pv-pvc.yaml +14 -1
- package/manifests/postgresql/pv.yaml +12 -1
- package/manifests/postgresql/pvc.yaml +1 -0
- package/manifests/prometheus/deployment.yaml +18 -22
- package/package.json +83 -10
- package/scripts/audit-selinux.sh +64 -0
- package/scripts/event-monitor.sh +56 -0
- package/scripts/gpu-diag.sh +0 -0
- package/scripts/ip-info.sh +0 -0
- package/scripts/k3s-node-setup.sh +30 -14
- package/scripts/kubeadm-node-setup.sh +40 -31
- package/scripts/lxd-vm-setup.sh +0 -0
- package/scripts/maas-nat-firewalld.sh +0 -0
- package/scripts/maas-setup.sh +8 -8
- package/scripts/nat-iptables.sh +2 -0
- package/scripts/rhel-grpc-setup.sh +0 -0
- package/scripts/rocky-kickstart.sh +25 -9
- package/scripts/selinux-normalize.sh +907 -0
- package/scripts/shutdown-machine.sh +843 -0
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
- package/src/api/core/core.controller.js +1 -1
- package/src/api/core/core.router.js +2 -2
- package/src/api/core/core.service.js +2 -2
- package/src/api/crypto/crypto.controller.js +1 -1
- package/src/api/crypto/crypto.service.js +1 -1
- package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +1 -1
- package/src/api/cyberia-action/cyberia-action.service.js +2 -2
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
- package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
- package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
- package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
- package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
- package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
- package/src/api/cyberia-map/cyberia-map.router.js +1 -1
- package/src/api/cyberia-map/cyberia-map.service.js +2 -2
- package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
- package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -29
- package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
- package/src/api/default/default.controller.js +1 -1
- package/src/api/default/default.router.js +1 -1
- package/src/api/default/default.service.js +2 -2
- package/src/api/document/document.controller.js +1 -1
- package/src/api/document/document.router.js +1 -1
- package/src/api/document/document.service.js +2 -2
- package/src/api/file/file.controller.js +1 -1
- package/src/api/file/file.router.js +1 -1
- package/src/api/file/file.service.js +2 -2
- package/src/api/instance/instance.controller.js +1 -1
- package/src/api/instance/instance.router.js +1 -1
- package/src/api/instance/instance.service.js +2 -2
- package/src/api/ipfs/ipfs.controller.js +1 -1
- package/src/api/ipfs/ipfs.router.js +2 -2
- package/src/api/ipfs/ipfs.service.js +2 -2
- package/src/api/object-layer/object-layer.controller.js +1 -1
- package/src/api/object-layer/object-layer.model.js +204 -3
- package/src/api/object-layer/object-layer.router.js +2 -2
- package/src/api/object-layer/object-layer.service.js +4 -17
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
- package/src/api/test/test.controller.js +1 -1
- package/src/api/test/test.service.js +1 -1
- package/src/api/user/guest.service.js +3 -3
- package/src/api/user/user.controller.js +1 -1
- package/src/api/user/user.router.js +2 -2
- package/src/api/user/user.service.js +4 -4
- package/src/api.js +5 -9
- package/src/cli/app.js +391 -0
- package/src/cli/baremetal.js +30 -36
- package/src/cli/client.js +306 -0
- package/src/cli/cloud-init.js +3 -3
- package/src/cli/cluster.js +242 -135
- package/src/cli/db.js +126 -67
- package/src/cli/deploy.js +158 -60
- package/src/cli/docker-compose.js +5 -5
- package/src/cli/domains.js +184 -0
- package/src/cli/dotenv-store.js +143 -0
- package/src/cli/event.js +2281 -0
- package/src/cli/fs.js +3 -3
- package/src/cli/host.js +672 -0
- package/src/cli/image.js +4 -7
- package/src/cli/index.js +426 -134
- package/src/cli/ipfs.js +34 -30
- package/src/cli/kickstart.js +1 -1
- package/src/cli/kubectl.js +218 -41
- package/src/cli/lxd.js +3 -3
- package/src/cli/monitor.js +1359 -26
- package/src/cli/package.js +90 -0
- package/src/cli/release.js +73 -34
- package/src/cli/repository.js +564 -367
- package/src/cli/run.js +362 -654
- package/src/cli/secrets.js +2158 -964
- package/src/cli/ssh.js +651 -331
- package/src/cli/state.js +394 -0
- package/src/cli/static.js +2 -2
- package/src/cli/system.js +26 -13
- package/src/cli/test.js +199 -125
- package/src/cli/vultr.js +623 -0
- package/src/cli/wireguard.js +2930 -0
- package/src/client/components/core/CalendarCore.js +53 -96
- package/src/client/components/core/Docs.js +258 -211
- package/src/client/components/core/FileExplorer.js +0 -21
- package/src/client/components/core/PanelForm.js +4 -4
- package/src/client/components/core/Repository.js +56 -0
- package/src/client/components/core/Translate.js +7 -0
- package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
- package/src/client/components/core/Wallet.js +0 -11
- package/src/client/components/core/Worker.js +7 -1
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- package/src/client/components/default/AppShellDefault.js +1 -1
- package/src/client/components/default/SettingsDefault.js +2 -2
- package/src/client/components/itemledger/SettingsItemledger.js +2 -2
- package/src/client/components/underpost/AppShellUnderpost.js +3 -2
- package/src/client/components/underpost/SettingsUnderpost.js +2 -2
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
- package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-384x384.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-512x512.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/default/assets/background/white.jpg +0 -0
- package/src/client/public/default/browserconfig.xml +1 -1
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon-48x48.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/manifest.webmanifest +5 -5
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/yandex-browser-50x50.png +0 -0
- package/src/client/public/default/yandex-browser-manifest.json +1 -1
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
- package/src/client/services/object-layer/object-layer.management.js +4 -4
- package/src/client/ssr/RootDocument.js +1 -1
- package/src/client/ssr/body/404.js +1 -1
- package/src/client/ssr/body/500.js +1 -1
- package/src/client/ssr/body/CacheControl.js +1 -1
- package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
- package/src/client/ssr/head/CryptokoynScripts.js +1 -1
- package/src/client/ssr/head/Css.js +1 -1
- package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +1 -1
- package/src/client/ssr/head/ItemledgerScripts.js +1 -1
- package/src/client/ssr/head/Microdata.js +1 -1
- package/src/client/ssr/head/Production.js +1 -1
- package/src/client/ssr/head/Pwa.js +1 -1
- package/src/client/ssr/head/PwaItemledger.js +1 -1
- package/src/client/ssr/head/Seo.js +1 -1
- package/src/client/ssr/head/UnderpostScripts.js +1 -1
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
- package/src/client/ssr/views/Cyberia404.js +7 -5
- package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/views/Maintenance.js +1 -1
- package/src/client/ssr/views/NoNetworkConnection.js +1 -1
- package/src/client/ssr/views/Test.js +1 -1
- package/src/client/sw/core.sw.js +20 -14
- package/src/client-builder/client-build-docs.js +61 -46
- package/src/client-builder/client-build-live.js +2 -2
- package/src/client-builder/client-build.js +58 -44
- package/src/client-builder/client-dev-server.js +3 -3
- package/src/client-builder/client-icons.js +2 -2
- package/src/client-builder/ssr.js +3 -3
- package/src/client.build.js +3 -6
- package/src/client.dev.js +3 -6
- package/src/db/DataBaseProvider.js +186 -3
- package/src/db/mariadb/MariaDB.js +3 -2
- package/src/db/mongo/MongoBootstrap.js +273 -101
- package/src/db/mongo/MongooseDB.js +11 -8
- package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
- package/src/grpc/cyberia/grpc-server.js +1 -1
- package/src/index.js +103 -23
- package/src/mailer/EmailRender.js +2 -2
- package/src/mailer/MailerInterceptor.js +87 -0
- package/src/mailer/MailerProvider.js +50 -6
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
- package/src/projects/cyberia/besu-genesis-generator.js +3 -3
- package/src/projects/cyberia/catalog-cyberia.js +54 -6
- package/src/projects/cyberia/gemini-client.js +1 -1
- package/src/projects/cyberia/generate-saga.js +15 -24
- package/src/projects/cyberia/hot-reload-trigger.js +1 -1
- package/src/projects/cyberia/instance-data.js +22 -3
- package/src/projects/cyberia/ipfs-client.js +4 -4
- package/src/projects/cyberia/map-preview-generator.js +1 -1
- package/src/projects/cyberia/object-layer.js +12 -22
- package/src/projects/cyberia/semantic-layer-generator.js +1 -1
- package/src/projects/underpost/catalog-underpost.js +13 -2
- package/src/proxy.js +4 -7
- package/src/runtime/cyberia-client/Dockerfile +9 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -4
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
- package/src/runtime/engine-cyberia/Dockerfile +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
- package/src/runtime/engine-cyberia/compose.env +16 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
- package/src/runtime/express/Express.js +32 -27
- package/src/runtime/lampp/Lampp.js +22 -70
- package/src/runtime/nginx/Nginx.js +1 -1
- package/src/runtime/wp/Wp.js +16 -48
- package/src/server/{catalog.js → build/catalog.js} +15 -5
- package/src/server/build/coverage.js +117 -0
- package/src/server/build/execution.js +402 -0
- package/src/server/build/package.js +465 -0
- package/src/server/build/testing.js +528 -0
- package/src/server/{dns.js → network/dns.js} +241 -14
- package/src/server/network/forward-proxy.js +541 -0
- package/src/server/{middlewares.js → network/middlewares.js} +59 -4
- package/src/server/network/node-capability.js +98 -0
- package/src/server/{peer.js → network/peer.js} +3 -3
- package/src/server/{proxy.js → network/proxy.js} +7 -13
- package/src/server/network/router.js +356 -0
- package/src/server/{tls.js → network/tls.js} +2 -2
- package/src/server/network/underpost-compression.js +186 -0
- package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
- package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
- package/src/server/{cri.js → ops/cri.js} +2 -2
- package/src/server/ops/cron.js +949 -0
- package/src/server/ops/event-notification.js +284 -0
- package/src/server/{logger.js → ops/logger.js} +108 -23
- package/src/server/ops/monitoring.js +1724 -0
- package/src/server/ops/systemd.js +259 -0
- package/src/server/{conf.js → runtime/conf.js} +521 -520
- package/src/server/runtime/config-scope.js +215 -0
- package/src/server/runtime/environment.js +149 -0
- package/src/server/{process.js → runtime/process.js} +153 -13
- package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
- package/src/server/{runtime.js → runtime/runtime.js} +12 -8
- package/src/server/{start.js → runtime/start.js} +128 -39
- package/src/server/{auth.js → security/auth.js} +7 -8
- package/src/server/security/container-storage.js +382 -0
- package/src/server/{crypto.js → security/crypto.js} +1 -1
- package/src/server/security/selinux.js +185 -0
- package/src/server/{backup.js → storage/backup.js} +17 -8
- package/src/server/{data-query.js → storage/data-query.js} +1 -1
- package/src/server/{downloader.js → storage/downloader.js} +2 -2
- package/src/server/storage/repository.js +68 -0
- package/src/server.js +4 -7
- package/src/ws/IoInterface.js +1 -1
- package/src/ws/IoServer.js +1 -1
- package/src/ws/core/core.ws.connection.js +1 -1
- package/src/ws/core/core.ws.emit.js +1 -1
- package/src/ws/core/core.ws.server.js +1 -1
- package/src/ws/default/default.ws.connection.js +1 -1
- package/src/ws/default/default.ws.emit.js +1 -1
- package/src/ws/default/default.ws.server.js +1 -1
- package/test/e2e/event-e2e-public-ingress-down.js +45 -0
- package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
- package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
- package/test/{api.test.js → integration/app/api.test.js} +33 -14
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
- package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
- package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
- package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
- package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
- package/test/integration/infra/1-security/config-scope.test.js +305 -0
- package/test/integration/infra/1-security/container-storage.test.js +356 -0
- package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
- package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
- package/test/integration/infra/1-security/selinux.test.js +69 -0
- package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
- package/test/integration/infra/1-security/systemd-service.test.js +70 -0
- package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
- package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
- package/test/integration/infra/2-network/node-capability.test.js +182 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
- package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
- package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
- package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
- package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
- package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
- package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
- package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
- package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +47 -6
- package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -4
- package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
- package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
- package/test/integration/infra/5-observability/event-notification.test.js +197 -0
- package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
- package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
- package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
- package/test/support/shell-harness.js +73 -0
- package/test/unit/build-template.test.js +97 -0
- package/test/unit/build-workflow-offline.test.js +132 -0
- package/test/unit/catalog.test.js +71 -0
- package/test/unit/client-build-docs.test.js +334 -0
- package/test/unit/conf-loading.test.js +303 -0
- package/test/unit/conf-resolution.test.js +979 -0
- package/test/unit/coverage-artifact.test.js +130 -0
- package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
- package/test/unit/deploy-env-resolution.test.js +38 -0
- package/test/unit/deploy-log-table.test.js +447 -0
- package/test/unit/execution-profiles.test.js +219 -0
- package/test/unit/fleet-sync-source.test.js +149 -0
- package/test/unit/logger-redaction.test.js +112 -0
- package/test/unit/package.test.js +403 -0
- package/test/unit/prepare-host.test.js +299 -0
- package/test/unit/process-environment.test.js +18 -0
- package/test/unit/propagation-message.test.js +78 -0
- package/test/unit/redeploy-plan.test.js +24 -0
- package/test/unit/release-bump.test.js +474 -0
- package/test/unit/ssh-output-redaction.test.js +28 -0
- package/test/unit/start-options.test.js +46 -0
- package/test/unit/test-tiers.test.js +193 -0
- package/vitest.config.js +58 -0
- package/.nycrc +0 -9
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
- package/manifests/mongodb/pv-pvc.yaml +0 -59
- package/scripts/link-local-underpost-cli.sh +0 -6
- package/src/api/user/user.build.js +0 -16
- package/src/cli/env.js +0 -177
- package/src/client/components/core/Blockchain.js +0 -41
- package/src/client/components/core/Blog.js +0 -9
- package/src/client/components/core/KeyboardAvoidance.js +0 -145
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/white0-min.jpg +0 -0
- package/src/client/public/default/assets/background/white0.jpg +0 -0
- package/src/client/public/doc/favicon.ico +0 -0
- package/src/client/public/doc/sitemap +0 -148
- package/src/server/cron.js +0 -476
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback-world capture — materialise the in-memory procedural world into
|
|
3
|
+
* MongoDB so it can be exported, versioned, and re-imported like any authored
|
|
4
|
+
* instance.
|
|
5
|
+
*
|
|
6
|
+
* The fallback world (cyberia-fallback-world.js) is never persisted: every
|
|
7
|
+
* engine process rebuilds it from code defaults at boot and serves it whenever
|
|
8
|
+
* a requested instance is absent. Capturing it means writing everything that
|
|
9
|
+
* in-memory world serves under a real instance code:
|
|
10
|
+
*
|
|
11
|
+
* - CyberiaInstance — map graph, portal edges, player spawn, item ids
|
|
12
|
+
* - CyberiaMap — one document per generated map (entities included)
|
|
13
|
+
* - CyberiaInstanceConf — the world's simulation config
|
|
14
|
+
* - CyberiaSkill / CyberiaEntityTypeDefault / CyberiaDialogue /
|
|
15
|
+
* CyberiaAction / CyberiaQuest — the content collections the fallback path
|
|
16
|
+
* reads from code defaults INSTEAD of Mongo; a persisted instance reads
|
|
17
|
+
* them from Mongo, so they must exist there for the capture to serve the
|
|
18
|
+
* same world (see instance-data.js#fetchFullInstance).
|
|
19
|
+
*
|
|
20
|
+
* ObjectLayer/atlas assets are NOT generated here — they come from the asset
|
|
21
|
+
* pipeline (`bin/cyberia ol <ids> --import`). The capture reports the missing
|
|
22
|
+
* ids so the caller can stop before writing an incomplete backup.
|
|
23
|
+
*
|
|
24
|
+
* Map and content codes are namespaced under the instance code by default, so
|
|
25
|
+
* two captures never overwrite each other's documents (map/action/quest codes
|
|
26
|
+
* are globally unique). `keepFallbackCodes` preserves the raw
|
|
27
|
+
* `fallback-map-*` / canonical action-quest codes instead.
|
|
28
|
+
*
|
|
29
|
+
* @module src/api/cyberia-instance/cyberia-fallback-capture
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { loggerFactory } from '../../server/ops/logger.js';
|
|
33
|
+
import { collectReferencedItemIds } from './cyberia-fallback-world.js';
|
|
34
|
+
import {
|
|
35
|
+
DefaultCyberiaActions,
|
|
36
|
+
DefaultCyberiaQuests,
|
|
37
|
+
DefaultCyberiaDialogues,
|
|
38
|
+
DefaultSkillConfig,
|
|
39
|
+
ENTITY_TYPE_DEFAULTS,
|
|
40
|
+
fillInstanceConfDefaults,
|
|
41
|
+
} from '../cyberia-server-defaults/cyberia-server-defaults.js';
|
|
42
|
+
|
|
43
|
+
const logger = loggerFactory(import.meta);
|
|
44
|
+
|
|
45
|
+
const FALLBACK_MAP_CODE_PREFIX = 'fallback-map-';
|
|
46
|
+
|
|
47
|
+
/** Mongo document keys that must never travel inside a `$set` payload. */
|
|
48
|
+
const DOC_METADATA_KEYS = ['_id', '__v', 'createdAt', 'updatedAt'];
|
|
49
|
+
|
|
50
|
+
const stripDocMetadata = (doc, extraKeys = []) => {
|
|
51
|
+
const out = { ...doc };
|
|
52
|
+
for (const key of [...DOC_METADATA_KEYS, ...extraKeys]) delete out[key];
|
|
53
|
+
return out;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const escapeRegExp = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
57
|
+
|
|
58
|
+
/** Namespaced map code for a captured fallback map (`fallback-map-2` → `X-map-2`). */
|
|
59
|
+
function captureMapCode(mapCode, instanceCode) {
|
|
60
|
+
const suffix = mapCode.startsWith(FALLBACK_MAP_CODE_PREFIX)
|
|
61
|
+
? mapCode.slice(FALLBACK_MAP_CODE_PREFIX.length)
|
|
62
|
+
: mapCode;
|
|
63
|
+
return `${instanceCode}-map-${suffix}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Namespaced action/quest code for a captured world. */
|
|
67
|
+
const captureContentCode = (code, instanceCode) => `${instanceCode}-${code}`;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Build the code translation tables for one capture.
|
|
71
|
+
*
|
|
72
|
+
* @param {object} world Result of `generateFallbackWorld()`.
|
|
73
|
+
* @param {string} instanceCode
|
|
74
|
+
* @param {boolean} keepFallbackCodes
|
|
75
|
+
* @returns {{ mapCodes: Map<string,string>, questCodes: Map<string,string>, actionCodes: Map<string,string> }}
|
|
76
|
+
*/
|
|
77
|
+
function buildCaptureCodeMaps({ world, instanceCode, keepFallbackCodes, actions, quests }) {
|
|
78
|
+
const mapCodes = new Map();
|
|
79
|
+
const rememberMapCode = (code) => {
|
|
80
|
+
if (!code || mapCodes.has(code)) return;
|
|
81
|
+
mapCodes.set(code, keepFallbackCodes ? code : captureMapCode(code, instanceCode));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
for (const code of world.instance?.cyberiaMapCodes || []) rememberMapCode(code);
|
|
85
|
+
for (const map of world.maps || []) rememberMapCode(map.code);
|
|
86
|
+
for (const portal of world.instance?.portals || []) {
|
|
87
|
+
rememberMapCode(portal.sourceMapCode);
|
|
88
|
+
rememberMapCode(portal.targetMapCode);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const contentCodes = (docs) =>
|
|
92
|
+
new Map(
|
|
93
|
+
(docs || [])
|
|
94
|
+
.filter((doc) => doc?.code)
|
|
95
|
+
.map((doc) => [doc.code, keepFallbackCodes ? doc.code : captureContentCode(doc.code, instanceCode)]),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return { mapCodes, actionCodes: contentCodes(actions), questCodes: contentCodes(quests) };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Translate one default action into its captured form. Returns `null` when the
|
|
103
|
+
* action lives on a map this world does not contain — a persisted instance
|
|
104
|
+
* only ever serves actions bound to its own maps.
|
|
105
|
+
*/
|
|
106
|
+
function captureAction(action, { mapCodes, actionCodes, questCodes }) {
|
|
107
|
+
const sourceMapCode = mapCodes.get(action.sourceMapCode);
|
|
108
|
+
if (!sourceMapCode) return null;
|
|
109
|
+
return {
|
|
110
|
+
...action,
|
|
111
|
+
code: actionCodes.get(action.code) || action.code,
|
|
112
|
+
sourceMapCode,
|
|
113
|
+
questDialogueCodes: (action.questDialogueCodes || []).map((entry) => ({
|
|
114
|
+
...entry,
|
|
115
|
+
questCode: questCodes.get(entry.questCode) || entry.questCode,
|
|
116
|
+
})),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Translate one default quest into its captured form (`null` = foreign map). */
|
|
121
|
+
function captureQuest(quest, { mapCodes, questCodes }) {
|
|
122
|
+
const sourceMapCode = mapCodes.get(quest.sourceMapCode);
|
|
123
|
+
if (!sourceMapCode) return null;
|
|
124
|
+
const translate = (codes) => (codes || []).map((code) => questCodes.get(code) || code);
|
|
125
|
+
return {
|
|
126
|
+
...quest,
|
|
127
|
+
code: questCodes.get(quest.code) || quest.code,
|
|
128
|
+
sourceMapCode,
|
|
129
|
+
prerequisiteCodes: translate(quest.prerequisiteCodes),
|
|
130
|
+
unlocksQuestCodes: translate(quest.unlocksQuestCodes),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Pure planner: turn an in-memory fallback world into the exact set of
|
|
136
|
+
* documents a capture writes. No I/O — the whole translation is testable
|
|
137
|
+
* without a database.
|
|
138
|
+
*
|
|
139
|
+
* @param {object} params
|
|
140
|
+
* @param {object} params.world Result of `generateFallbackWorld()`.
|
|
141
|
+
* @param {string} params.instanceCode Code the capture is stored under.
|
|
142
|
+
* @param {boolean} [params.keepFallbackCodes=false]
|
|
143
|
+
* @param {Array} [params.actions=DefaultCyberiaActions]
|
|
144
|
+
* @param {Array} [params.quests=DefaultCyberiaQuests]
|
|
145
|
+
* @returns {{
|
|
146
|
+
* instance: object, conf: object, maps: object[], actions: object[], quests: object[],
|
|
147
|
+
* codeMaps: object, skippedActionCodes: string[], skippedQuestCodes: string[], itemIds: string[]
|
|
148
|
+
* }}
|
|
149
|
+
*/
|
|
150
|
+
function planFallbackCapture({
|
|
151
|
+
world,
|
|
152
|
+
instanceCode,
|
|
153
|
+
keepFallbackCodes = false,
|
|
154
|
+
actions = DefaultCyberiaActions,
|
|
155
|
+
quests = DefaultCyberiaQuests,
|
|
156
|
+
}) {
|
|
157
|
+
if (!world?.instance || !Array.isArray(world.maps)) throw new Error('planFallbackCapture: invalid world');
|
|
158
|
+
if (!instanceCode) throw new Error('planFallbackCapture: instanceCode is required');
|
|
159
|
+
|
|
160
|
+
const codeMaps = buildCaptureCodeMaps({ world, instanceCode, keepFallbackCodes, actions, quests });
|
|
161
|
+
const { mapCodes } = codeMaps;
|
|
162
|
+
|
|
163
|
+
const maps = world.maps.map((map) => ({
|
|
164
|
+
code: mapCodes.get(map.code) || map.code,
|
|
165
|
+
name: map.name || mapCodes.get(map.code) || map.code,
|
|
166
|
+
description: map.description || '',
|
|
167
|
+
gridX: map.gridX,
|
|
168
|
+
gridY: map.gridY,
|
|
169
|
+
cellWidth: map.cellWidth,
|
|
170
|
+
cellHeight: map.cellHeight,
|
|
171
|
+
entities: (map.entities || []).map((entity) => ({ ...entity })),
|
|
172
|
+
tags: ['fallback', 'procedural', 'captured'],
|
|
173
|
+
}));
|
|
174
|
+
|
|
175
|
+
const spawn = world.instance.playerSpawn || {};
|
|
176
|
+
const instance = {
|
|
177
|
+
code: instanceCode,
|
|
178
|
+
name: instanceCode,
|
|
179
|
+
description: 'Captured procedural fallback world',
|
|
180
|
+
tags: ['fallback', 'procedural', 'captured'],
|
|
181
|
+
cyberiaMapCodes: (world.instance.cyberiaMapCodes || []).map((code) => mapCodes.get(code) || code),
|
|
182
|
+
portals: (world.instance.portals || []).map((portal) => ({
|
|
183
|
+
...portal,
|
|
184
|
+
sourceMapCode: mapCodes.get(portal.sourceMapCode) || portal.sourceMapCode,
|
|
185
|
+
targetMapCode: mapCodes.get(portal.targetMapCode) || portal.targetMapCode,
|
|
186
|
+
})),
|
|
187
|
+
playerSpawn: {
|
|
188
|
+
...spawn,
|
|
189
|
+
...(spawn.sourceMapCode ? { sourceMapCode: mapCodes.get(spawn.sourceMapCode) || spawn.sourceMapCode } : {}),
|
|
190
|
+
},
|
|
191
|
+
topologyMode: 'procedural',
|
|
192
|
+
itemIds: (world.instance.itemIds || []).map((entry) => ({ ...entry })),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const conf = { ...fillInstanceConfDefaults(world.config || {}), instanceCode };
|
|
196
|
+
|
|
197
|
+
const capturedActions = [];
|
|
198
|
+
const skippedActionCodes = [];
|
|
199
|
+
for (const action of actions) {
|
|
200
|
+
const captured = captureAction(action, codeMaps);
|
|
201
|
+
if (captured) capturedActions.push(captured);
|
|
202
|
+
else skippedActionCodes.push(action.code);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const capturedQuests = [];
|
|
206
|
+
const skippedQuestCodes = [];
|
|
207
|
+
for (const quest of quests) {
|
|
208
|
+
const captured = captureQuest(quest, codeMaps);
|
|
209
|
+
if (captured) capturedQuests.push(captured);
|
|
210
|
+
else skippedQuestCodes.push(quest.code);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
instance,
|
|
215
|
+
conf,
|
|
216
|
+
maps,
|
|
217
|
+
actions: capturedActions,
|
|
218
|
+
quests: capturedQuests,
|
|
219
|
+
codeMaps,
|
|
220
|
+
skippedActionCodes,
|
|
221
|
+
skippedQuestCodes,
|
|
222
|
+
itemIds: collectCaptureItemIds({ instance, conf, maps, actions: capturedActions, quests: capturedQuests }),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Every ObjectLayer item id the captured instance needs an atlas for: what the
|
|
228
|
+
* maps place, what the instance and conf declare, what the seeded skills and
|
|
229
|
+
* entity-type defaults reference, and what the vendor/assembler/quest catalogs
|
|
230
|
+
* draw icons for.
|
|
231
|
+
*
|
|
232
|
+
* @returns {string[]} Sorted, de-duplicated item ids.
|
|
233
|
+
*/
|
|
234
|
+
function collectCaptureItemIds({ instance, conf, maps, actions, quests }) {
|
|
235
|
+
const ids = collectReferencedItemIds();
|
|
236
|
+
const push = (id) => {
|
|
237
|
+
if (typeof id === 'string' && id.length > 0 && !id.startsWith('$')) ids.add(id);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
for (const map of maps || []) {
|
|
241
|
+
for (const entity of map.entities || []) (entity.objectLayerItemIds || []).forEach(push);
|
|
242
|
+
}
|
|
243
|
+
for (const entry of instance?.itemIds || []) push(typeof entry === 'string' ? entry : entry?.id);
|
|
244
|
+
|
|
245
|
+
for (const entityDefault of conf?.entityDefaults || []) {
|
|
246
|
+
(entityDefault.liveItemIds || []).forEach(push);
|
|
247
|
+
(entityDefault.deadItemIds || []).forEach(push);
|
|
248
|
+
(entityDefault.dropItemIds || []).forEach(push);
|
|
249
|
+
for (const slot of entityDefault.defaultObjectLayers || []) push(slot.itemId);
|
|
250
|
+
}
|
|
251
|
+
for (const skillConfig of conf?.skillConfig || []) {
|
|
252
|
+
push(skillConfig.triggerItemId);
|
|
253
|
+
for (const skill of skillConfig.skills || []) push(skill.summonedEntityItemId);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
for (const action of actions || []) {
|
|
257
|
+
for (const shopItem of action.shopItems || []) {
|
|
258
|
+
push(shopItem.itemId);
|
|
259
|
+
push(shopItem.priceItemId);
|
|
260
|
+
}
|
|
261
|
+
for (const recipe of action.craftRecipes || []) {
|
|
262
|
+
(recipe.ingredients || []).forEach((ingredient) => push(ingredient.itemId));
|
|
263
|
+
(recipe.outputItems || []).forEach((output) => push(output.itemId));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
for (const quest of quests || []) {
|
|
267
|
+
for (const step of quest.steps || []) {
|
|
268
|
+
for (const objective of step.objectives || []) push(objective.itemId);
|
|
269
|
+
}
|
|
270
|
+
for (const reward of quest.rewards || []) push(reward.itemId);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return [...ids].sort();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Insert the content collections the fallback path serves from code defaults.
|
|
278
|
+
*
|
|
279
|
+
* Insert-only: an existing document is left exactly as the operator (or an
|
|
280
|
+
* earlier import) left it, so a capture never silently rewrites content shared
|
|
281
|
+
* with other instances. Returns per-collection insert counts.
|
|
282
|
+
*/
|
|
283
|
+
async function seedMissingContentDefaults({ CyberiaSkill, CyberiaEntityTypeDefault, CyberiaDialogue }) {
|
|
284
|
+
const inserted = { skills: 0, entityTypeDefaults: 0, dialogues: 0 };
|
|
285
|
+
|
|
286
|
+
const insertIfMissing = async (Model, filter, doc, counterKey) => {
|
|
287
|
+
if (!Model) return;
|
|
288
|
+
const existing = await Model.findOne(filter).lean();
|
|
289
|
+
if (existing) return;
|
|
290
|
+
await Model.create(doc);
|
|
291
|
+
inserted[counterKey]++;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
for (const skill of DefaultSkillConfig) {
|
|
295
|
+
await insertIfMissing(
|
|
296
|
+
CyberiaSkill,
|
|
297
|
+
{ triggerItemId: skill.triggerItemId },
|
|
298
|
+
{ triggerItemId: skill.triggerItemId, logicEventIds: skill.logicEventIds || [], skills: skill.skills || [] },
|
|
299
|
+
'skills',
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
for (const entityDefault of ENTITY_TYPE_DEFAULTS) {
|
|
304
|
+
await insertIfMissing(
|
|
305
|
+
CyberiaEntityTypeDefault,
|
|
306
|
+
{ entityType: entityDefault.entityType, liveItemIds: entityDefault.liveItemIds || [] },
|
|
307
|
+
{
|
|
308
|
+
entityType: entityDefault.entityType,
|
|
309
|
+
liveItemIds: entityDefault.liveItemIds || [],
|
|
310
|
+
deadItemIds: entityDefault.deadItemIds || [],
|
|
311
|
+
dropItemIds: entityDefault.dropItemIds || [],
|
|
312
|
+
defaultObjectLayers: entityDefault.defaultObjectLayers || [],
|
|
313
|
+
behavior: entityDefault.behavior || '',
|
|
314
|
+
},
|
|
315
|
+
'entityTypeDefaults',
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
for (const dialogue of DefaultCyberiaDialogues) {
|
|
320
|
+
await insertIfMissing(
|
|
321
|
+
CyberiaDialogue,
|
|
322
|
+
{ code: dialogue.code, order: dialogue.order },
|
|
323
|
+
{ ...dialogue },
|
|
324
|
+
'dialogues',
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return inserted;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Remove documents left over in this capture's own namespace by a previous,
|
|
333
|
+
* larger capture (e.g. a world that used to have more maps). Only ever touches
|
|
334
|
+
* codes prefixed with the instance code, and never runs in `keepFallbackCodes`
|
|
335
|
+
* mode where the codes are the globally shared canonical ones.
|
|
336
|
+
*/
|
|
337
|
+
async function pruneStaleCaptureDocs({ models, instanceCode, plan }) {
|
|
338
|
+
const namespace = new RegExp(`^${escapeRegExp(instanceCode)}-`);
|
|
339
|
+
const pruned = { maps: 0, actions: 0, quests: 0 };
|
|
340
|
+
|
|
341
|
+
const prune = async (Model, keepCodes, counterKey) => {
|
|
342
|
+
if (!Model) return;
|
|
343
|
+
const result = await Model.deleteMany({ code: { $regex: namespace, $nin: keepCodes } });
|
|
344
|
+
pruned[counterKey] = result?.deletedCount || 0;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
await prune(
|
|
348
|
+
models.CyberiaMap,
|
|
349
|
+
plan.maps.map((map) => map.code),
|
|
350
|
+
'maps',
|
|
351
|
+
);
|
|
352
|
+
await prune(
|
|
353
|
+
models.CyberiaAction,
|
|
354
|
+
plan.actions.map((action) => action.code),
|
|
355
|
+
'actions',
|
|
356
|
+
);
|
|
357
|
+
await prune(
|
|
358
|
+
models.CyberiaQuest,
|
|
359
|
+
plan.quests.map((quest) => quest.code),
|
|
360
|
+
'quests',
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
return pruned;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Materialise an in-memory fallback world into MongoDB under `instanceCode`.
|
|
368
|
+
*
|
|
369
|
+
* Idempotent: every write is an upsert keyed by the document's natural code,
|
|
370
|
+
* so re-running a capture converges on the same state. Nothing is deleted
|
|
371
|
+
* except stale documents inside this capture's own code namespace.
|
|
372
|
+
*
|
|
373
|
+
* @param {object} params
|
|
374
|
+
* @param {object} params.models `{ CyberiaInstance, CyberiaInstanceConf, CyberiaMap, CyberiaAction,
|
|
375
|
+
* CyberiaQuest, CyberiaSkill, CyberiaEntityTypeDefault,
|
|
376
|
+
* CyberiaDialogue, ObjectLayer }`
|
|
377
|
+
* @param {object} params.world Result of `generateFallbackWorld()`.
|
|
378
|
+
* @param {string} params.instanceCode
|
|
379
|
+
* @param {boolean} [params.keepFallbackCodes=false]
|
|
380
|
+
* @returns {Promise<{plan: object, inserted: object, pruned: object, missingObjectLayerItemIds: string[]}>}
|
|
381
|
+
*/
|
|
382
|
+
async function captureFallbackWorld({ models, world, instanceCode, keepFallbackCodes = false }) {
|
|
383
|
+
const plan = planFallbackCapture({ world, instanceCode, keepFallbackCodes });
|
|
384
|
+
|
|
385
|
+
// Conf first: the instance document carries the ObjectId ref to it.
|
|
386
|
+
const confDoc = await models.CyberiaInstanceConf.findOneAndUpdate(
|
|
387
|
+
{ instanceCode },
|
|
388
|
+
{ $set: stripDocMetadata(plan.conf, ['instanceCode']) },
|
|
389
|
+
{ upsert: true, returnDocument: 'after' },
|
|
390
|
+
);
|
|
391
|
+
logger.info('Captured CyberiaInstanceConf', { instanceCode });
|
|
392
|
+
|
|
393
|
+
for (const map of plan.maps) {
|
|
394
|
+
await models.CyberiaMap.findOneAndUpdate(
|
|
395
|
+
{ code: map.code },
|
|
396
|
+
{ $set: stripDocMetadata(map, ['code']) },
|
|
397
|
+
{ upsert: true },
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
logger.info(`Captured ${plan.maps.length} CyberiaMap document(s)`, { codes: plan.maps.map((m) => m.code) });
|
|
401
|
+
|
|
402
|
+
await models.CyberiaInstance.findOneAndUpdate(
|
|
403
|
+
{ code: instanceCode },
|
|
404
|
+
{
|
|
405
|
+
$set: {
|
|
406
|
+
...stripDocMetadata(plan.instance, ['code']),
|
|
407
|
+
...(confDoc?._id ? { conf: confDoc._id } : {}),
|
|
408
|
+
},
|
|
409
|
+
$setOnInsert: { status: 'unlisted' },
|
|
410
|
+
},
|
|
411
|
+
{ upsert: true },
|
|
412
|
+
);
|
|
413
|
+
logger.info('Captured CyberiaInstance', { code: instanceCode, maps: plan.instance.cyberiaMapCodes.length });
|
|
414
|
+
|
|
415
|
+
for (const action of plan.actions) {
|
|
416
|
+
await models.CyberiaAction.findOneAndUpdate(
|
|
417
|
+
{ code: action.code },
|
|
418
|
+
{ $set: stripDocMetadata(action, ['code']) },
|
|
419
|
+
{ upsert: true },
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
for (const quest of plan.quests) {
|
|
423
|
+
await models.CyberiaQuest.findOneAndUpdate(
|
|
424
|
+
{ code: quest.code },
|
|
425
|
+
{ $set: stripDocMetadata(quest, ['code']) },
|
|
426
|
+
{ upsert: true },
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
logger.info(`Captured ${plan.actions.length} CyberiaAction and ${plan.quests.length} CyberiaQuest document(s)`);
|
|
430
|
+
if (plan.skippedActionCodes.length > 0 || plan.skippedQuestCodes.length > 0) {
|
|
431
|
+
logger.warn('Skipped mission content bound to maps outside the captured world', {
|
|
432
|
+
actions: plan.skippedActionCodes,
|
|
433
|
+
quests: plan.skippedQuestCodes,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const inserted = await seedMissingContentDefaults(models);
|
|
438
|
+
logger.info('Seeded missing content defaults', inserted);
|
|
439
|
+
|
|
440
|
+
// `keepFallbackCodes` reuses the globally shared canonical codes, so nothing
|
|
441
|
+
// in that namespace belongs exclusively to this capture.
|
|
442
|
+
const pruned = keepFallbackCodes
|
|
443
|
+
? { maps: 0, actions: 0, quests: 0 }
|
|
444
|
+
: await pruneStaleCaptureDocs({ models, instanceCode, plan });
|
|
445
|
+
if (pruned.maps || pruned.actions || pruned.quests)
|
|
446
|
+
logger.info('Pruned stale documents from a previous capture', pruned);
|
|
447
|
+
|
|
448
|
+
const presentItemIds = new Set(
|
|
449
|
+
(await models.ObjectLayer.find({ 'data.item.id': { $in: plan.itemIds } }, { 'data.item.id': 1 }).lean()).map(
|
|
450
|
+
(doc) => doc.data?.item?.id,
|
|
451
|
+
),
|
|
452
|
+
);
|
|
453
|
+
const missingObjectLayerItemIds = plan.itemIds.filter((id) => !presentItemIds.has(id));
|
|
454
|
+
|
|
455
|
+
return { plan, inserted, pruned, missingObjectLayerItemIds };
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export {
|
|
459
|
+
planFallbackCapture,
|
|
460
|
+
captureFallbackWorld,
|
|
461
|
+
collectCaptureItemIds,
|
|
462
|
+
captureMapCode,
|
|
463
|
+
captureContentCode,
|
|
464
|
+
seedMissingContentDefaults,
|
|
465
|
+
FALLBACK_MAP_CODE_PREFIX,
|
|
466
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback-world default items — process-local override store.
|
|
3
|
+
*
|
|
4
|
+
* The procedural fallback world is never persisted, so its default item set
|
|
5
|
+
* has no collection to live in. This module holds the set the FallbackWorldEngine
|
|
6
|
+
* view composed, in memory, for the lifetime of the engine process:
|
|
7
|
+
*
|
|
8
|
+
* - written by POST /api/cyberia-instance/fallback-world/hot-reload
|
|
9
|
+
* - read by fetchFullInstance()'s fallback branch (instance-data.js) and
|
|
10
|
+
* GET /api/cyberia-instance/fallback-world[/default-items]
|
|
11
|
+
*
|
|
12
|
+
* Deliberately NOT persisted: an engine restart drops back to the code defaults,
|
|
13
|
+
* so a stale editor session can never become the permanent shape of the world.
|
|
14
|
+
* This keeps the fallback path's "code defaults are authoritative" invariant —
|
|
15
|
+
* the only thing an operator can layer on top is this explicit, volatile list.
|
|
16
|
+
*
|
|
17
|
+
* @module src/api/cyberia-instance/cyberia-fallback-default-items.js
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** @typedef {{ id: string, defaultPlayerInventory: boolean }} FallbackDefaultItem */
|
|
21
|
+
|
|
22
|
+
/** @type {FallbackDefaultItem[]} */
|
|
23
|
+
let defaultItems = [];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Coerce a caller-supplied list into the canonical `{ id, defaultPlayerInventory }`
|
|
27
|
+
* shape. Accepts the legacy `string[]` form and drops blank/duplicate ids so the
|
|
28
|
+
* world generator never sees a malformed entry.
|
|
29
|
+
*
|
|
30
|
+
* @param {Array<string|FallbackDefaultItem>} entries
|
|
31
|
+
* @returns {FallbackDefaultItem[]}
|
|
32
|
+
*/
|
|
33
|
+
function normalizeFallbackDefaultItems(entries) {
|
|
34
|
+
if (!Array.isArray(entries)) return [];
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
const normalized = [];
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const raw = typeof entry === 'string' ? { id: entry } : entry;
|
|
39
|
+
const id = typeof raw?.id === 'string' ? raw.id.trim() : '';
|
|
40
|
+
if (!id || seen.has(id)) continue;
|
|
41
|
+
seen.add(id);
|
|
42
|
+
normalized.push({ id, defaultPlayerInventory: !!raw.defaultPlayerInventory });
|
|
43
|
+
}
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Current override set. Returns a copy so callers cannot mutate the store.
|
|
49
|
+
* @returns {FallbackDefaultItem[]}
|
|
50
|
+
*/
|
|
51
|
+
const getFallbackDefaultItems = () => defaultItems.map((entry) => ({ ...entry }));
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Replace the override set. An empty list clears it, restoring pure code defaults.
|
|
55
|
+
* @param {Array<string|FallbackDefaultItem>} entries
|
|
56
|
+
* @returns {FallbackDefaultItem[]} The stored set.
|
|
57
|
+
*/
|
|
58
|
+
function setFallbackDefaultItems(entries) {
|
|
59
|
+
defaultItems = normalizeFallbackDefaultItems(entries);
|
|
60
|
+
return getFallbackDefaultItems();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { getFallbackDefaultItems, setFallbackDefaultItems, normalizeFallbackDefaultItems };
|
|
@@ -66,6 +66,13 @@ const DEFAULT_GRID_SIZE = 64;
|
|
|
66
66
|
|
|
67
67
|
const KNOWN_DEFAULT_ITEM_IDS = new Set(DefaultCyberiaItems.map((e) => e.item.id));
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Every item id the canonical defaults can place, equip, summon, sell, or
|
|
71
|
+
* craft. Shared with the fallback-world capture, which must resolve an atlas
|
|
72
|
+
* for each of them before writing a backup.
|
|
73
|
+
*
|
|
74
|
+
* @returns {Set<string>}
|
|
75
|
+
*/
|
|
69
76
|
function collectReferencedItemIds() {
|
|
70
77
|
const ids = new Set();
|
|
71
78
|
const push = (id) => {
|
|
@@ -179,7 +186,7 @@ function generateFallbackMap(mapCode, colors, opts = {}) {
|
|
|
179
186
|
const portalEntities = generatePortalEntities(mapDims, colors, { grid });
|
|
180
187
|
|
|
181
188
|
// 6. Bots — placed on walkable cells (avoids obstacles, portals, NPCs)
|
|
182
|
-
const bots = generateBots(mapDims, colors, { count: opts.botCount, grid });
|
|
189
|
+
const bots = mapCode === 'fallback-map-0' ? [] : generateBots(mapDims, colors, { count: opts.botCount, grid });
|
|
183
190
|
|
|
184
191
|
// 7. Resources — static exploitable entities placed on walkable cells
|
|
185
192
|
const resources = generateResources(mapDims, colors, { count: opts.resourceCount, grid });
|
|
@@ -232,6 +239,11 @@ function generateFallbackMap(mapCode, colors, opts = {}) {
|
|
|
232
239
|
* @param {number} [opts.resourceCount] Resources per map (random if omitted).
|
|
233
240
|
* @param {number} [opts.staticCount] Static decorators per map (random if omitted).
|
|
234
241
|
* @param {Array} [opts.colors] Override palette.
|
|
242
|
+
* @param {Array<{id: string, defaultPlayerInventory: boolean}>} [opts.itemIds=[]]
|
|
243
|
+
* Instance-level default items, mirroring `CyberiaInstance.itemIds`. Entries
|
|
244
|
+
* flagged `defaultPlayerInventory` are merged into the player entity default
|
|
245
|
+
* by `applyInstanceDefaultPlayerInventory`; every id is also resolved to an
|
|
246
|
+
* atlas at boot. Layout is unaffected, so this stays outside the world seed.
|
|
235
247
|
* @returns {{
|
|
236
248
|
* instance: object,
|
|
237
249
|
* maps: object[],
|
|
@@ -256,6 +268,7 @@ function generateFallbackWorld(opts = {}) {
|
|
|
256
268
|
// fallback before atlases load. The C client resolves real colours
|
|
257
269
|
// through domain/presentation_runtime — it does not read this value.
|
|
258
270
|
colors = PALETTE,
|
|
271
|
+
itemIds = [],
|
|
259
272
|
} = opts;
|
|
260
273
|
|
|
261
274
|
// Surface item-id drift loudly on the very first build, so a missing
|
|
@@ -314,6 +327,7 @@ function generateFallbackWorld(opts = {}) {
|
|
|
314
327
|
portals,
|
|
315
328
|
topologyMode: 'procedural',
|
|
316
329
|
playerSpawn: { ...DEFAULT_PLAYER_SPAWN },
|
|
330
|
+
itemIds: itemIds.map((entry) => ({ ...entry })),
|
|
317
331
|
};
|
|
318
332
|
|
|
319
333
|
return {
|
|
@@ -359,6 +373,7 @@ export {
|
|
|
359
373
|
generateFallbackWorld,
|
|
360
374
|
generateFallbackMap,
|
|
361
375
|
auditFallbackItemIds,
|
|
376
|
+
collectReferencedItemIds,
|
|
362
377
|
fallbackListInstance,
|
|
363
378
|
DEFAULT_FALLBACK_INSTANCE_CODE,
|
|
364
379
|
};
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
renderMapPreviewPng,
|
|
26
26
|
} from '../../projects/cyberia/map-preview-generator.js';
|
|
27
27
|
import { FileFactory } from '../file/file.service.js';
|
|
28
|
-
import { loggerFactory } from '../../server/logger.js';
|
|
28
|
+
import { loggerFactory } from '../../server/ops/logger.js';
|
|
29
29
|
import {
|
|
30
30
|
CYBERIA_INSTANCE_CONF_DEFAULTS,
|
|
31
31
|
DefaultCyberiaActions,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
sendBlob,
|
|
5
5
|
serviceHandler,
|
|
6
6
|
setCrossOriginHeaders,
|
|
7
|
-
} from '../../server/middlewares.js';
|
|
7
|
+
} from '../../server/network/middlewares.js';
|
|
8
8
|
import { CyberiaInstanceService } from './cyberia-instance.service.js';
|
|
9
9
|
import { CyberiaInstanceMapService } from './cyberia-instance-map.service.js';
|
|
10
10
|
import { CyberiaInstanceBootService } from './cyberia-instance-boot.service.js';
|
|
@@ -30,6 +30,9 @@ const CyberiaInstanceController = buildCrudController(CyberiaInstanceService, {
|
|
|
30
30
|
portalConnect: serviceHandler(CyberiaInstanceService.portalConnect),
|
|
31
31
|
// Moderator/admin-triggered world reload on a running cyberia-server.
|
|
32
32
|
hotReload: serviceHandler(CyberiaInstanceService.hotReload, { errorStatus: 502 }),
|
|
33
|
+
// Fallback-world default items (volatile) + its own reload trigger.
|
|
34
|
+
fallbackDefaultItems: serviceHandler(CyberiaInstanceService.fallbackDefaultItems),
|
|
35
|
+
fallbackHotReload: serviceHandler(CyberiaInstanceService.fallbackHotReload, { errorStatus: 502 }),
|
|
33
36
|
// Boot transport (REST fallback of the gRPC CyberiaDataService).
|
|
34
37
|
bootPing: serviceHandler(CyberiaInstanceBootService.ping),
|
|
35
38
|
bootObjectLayerBatch: serviceHandler(CyberiaInstanceBootService.objectLayerBatch, { errorStatus: 500 }),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import { registerCrudRoutes } from '../../server/middlewares.js';
|
|
3
|
-
import { userGuard, moderatorGuard } from '../../server/auth.js';
|
|
2
|
+
import { registerCrudRoutes } from '../../server/network/middlewares.js';
|
|
3
|
+
import { userGuard, moderatorGuard } from '../../server/security/auth.js';
|
|
4
4
|
import { CyberiaInstanceController } from './cyberia-instance.controller.js';
|
|
5
5
|
|
|
6
6
|
class CyberiaInstanceRouter {
|
|
@@ -38,6 +38,19 @@ class CyberiaInstanceRouter {
|
|
|
38
38
|
async (req, res) => await CyberiaInstanceController.bootFullInstance(req, res, options),
|
|
39
39
|
);
|
|
40
40
|
router.get(`/fallback-world`, async (req, res) => await CyberiaInstanceController.fallbackWorld(req, res, options));
|
|
41
|
+
// Fallback-world default items — volatile, process-local (never persisted).
|
|
42
|
+
// The read is open (same as /fallback-world); staging them and triggering a
|
|
43
|
+
// rebuild is elevated privilege, like every other hot-reload path.
|
|
44
|
+
router.get(
|
|
45
|
+
`/fallback-world/default-items`,
|
|
46
|
+
async (req, res) => await CyberiaInstanceController.fallbackDefaultItems(req, res, options),
|
|
47
|
+
);
|
|
48
|
+
router.post(
|
|
49
|
+
`/fallback-world/hot-reload`,
|
|
50
|
+
options.authMiddleware,
|
|
51
|
+
moderatorGuard,
|
|
52
|
+
async (req, res) => await CyberiaInstanceController.fallbackHotReload(req, res, options),
|
|
53
|
+
);
|
|
41
54
|
// Instance Map — static topology/presence plus dynamic player capability activity.
|
|
42
55
|
router.get(
|
|
43
56
|
`/instance-map/:instanceCode/static`,
|