@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
package/bin/index.js
CHANGED
|
@@ -13,11 +13,17 @@ import dotenv from 'dotenv';
|
|
|
13
13
|
import { Command } from 'commander';
|
|
14
14
|
import fs from 'fs-extra';
|
|
15
15
|
import stringify from 'fast-json-stable-stringify';
|
|
16
|
-
import { shellExec } from '../src/server/process.js';
|
|
17
|
-
import {
|
|
16
|
+
import { shellExec } from '../src/server/runtime/process.js';
|
|
17
|
+
import { cli } from '../src/server/build/execution.js';
|
|
18
|
+
import { loggerFactory } from '../src/server/ops/logger.js';
|
|
18
19
|
import { generateBesuManifests, deployBesu, removeBesu } from '../src/projects/cyberia/besu-genesis-generator.js';
|
|
19
20
|
import { DataBaseProviderService } from '../src/db/DataBaseProvider.js';
|
|
20
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
deployEnvFilePath,
|
|
23
|
+
etcHostFactory,
|
|
24
|
+
loadConfServerJson,
|
|
25
|
+
normalizeInstanceTopology,
|
|
26
|
+
} from '../src/server/runtime/conf.js';
|
|
21
27
|
import {
|
|
22
28
|
ObjectLayerEngine,
|
|
23
29
|
resolveCanonicalCid,
|
|
@@ -46,16 +52,22 @@ import {
|
|
|
46
52
|
DefaultCyberiaQuests,
|
|
47
53
|
ENTITY_TYPE_DEFAULTS,
|
|
48
54
|
fillInstanceConfDefaults,
|
|
49
|
-
DOCKER_SCRIPTS,
|
|
50
|
-
CyberiaDependencies,
|
|
51
55
|
} from '../src/api/cyberia-server-defaults/cyberia-server-defaults.js';
|
|
56
|
+
import cyberiaCatalog from '../src/projects/cyberia/catalog-cyberia.js';
|
|
52
57
|
|
|
53
58
|
import {
|
|
54
59
|
DEFAULT_INSTANCE_CODE,
|
|
55
60
|
ITEM_TYPES as itemTypes,
|
|
56
61
|
DefaultCyberiaItems,
|
|
57
62
|
} from '../src/client/components/cyberia/SharedDefaultsCyberia.js';
|
|
58
|
-
import { loadDeployCatalog } from '../src/server/catalog.js';
|
|
63
|
+
import { loadDeployCatalog } from '../src/server/build/catalog.js';
|
|
64
|
+
import {
|
|
65
|
+
DEPLOY_MANIFEST_INDENT,
|
|
66
|
+
STAGED_CLI_PACKAGE,
|
|
67
|
+
buildDeployPackageJson,
|
|
68
|
+
deployPackagePathFactory,
|
|
69
|
+
stageCliPackage,
|
|
70
|
+
} from '../src/server/build/package.js';
|
|
59
71
|
|
|
60
72
|
/**
|
|
61
73
|
* Connect to the project MongoDB instance using the standard env / conf layout.
|
|
@@ -256,6 +268,17 @@ try {
|
|
|
256
268
|
/** @type {import('mongoose').Model} */
|
|
257
269
|
const Ipfs = DataBaseProviderService.getModel('ipfs', { host, path });
|
|
258
270
|
|
|
271
|
+
// Idempotent repair, run only before flows that write: collapses legacy
|
|
272
|
+
// duplicates and upgrades the data.item.id index to unique so every
|
|
273
|
+
// later write has exactly one document to land on. Read-only
|
|
274
|
+
// subcommands stay side-effect free — findByItemId already resolves the
|
|
275
|
+
// same canonical document whether or not duplicates are still present.
|
|
276
|
+
if (options.import || options.importTypes || options.drop || options.generate) {
|
|
277
|
+
const { removedIds, indexUpgraded } = await ObjectLayer.ensureUniqueItemIdIndex();
|
|
278
|
+
if (removedIds.length > 0) logger.warn(`Removed ${removedIds.length} duplicate ObjectLayer document(s)`);
|
|
279
|
+
if (indexUpgraded) logger.info('Upgraded data.item.id index to unique');
|
|
280
|
+
}
|
|
281
|
+
|
|
259
282
|
if (options.drop) {
|
|
260
283
|
// Parse comma-separated item IDs for targeted drop; if none provided, drop everything
|
|
261
284
|
const dropItemIds = itemId
|
|
@@ -355,7 +378,7 @@ try {
|
|
|
355
378
|
`IPFS cleanup: ${unpinCount}/${cidsToUnpin.size} CIDs unpinned, ${mfsCount}/${itemIdsToClean.size} MFS paths removed`,
|
|
356
379
|
);
|
|
357
380
|
if (options.gitClean) {
|
|
358
|
-
shellExec(`cd src/client/public/cyberia &&
|
|
381
|
+
shellExec(`cd src/client/public/cyberia && ${cli()} run clean .`);
|
|
359
382
|
logger.info('Asset directory cleaned');
|
|
360
383
|
}
|
|
361
384
|
|
|
@@ -439,7 +462,7 @@ try {
|
|
|
439
462
|
});
|
|
440
463
|
|
|
441
464
|
// Check if an ObjectLayer with the same item.id already exists (upsert by item ID)
|
|
442
|
-
const existingOL = await ObjectLayer.
|
|
465
|
+
const existingOL = await ObjectLayer.findByItemId(currentItemId);
|
|
443
466
|
let objectLayer;
|
|
444
467
|
|
|
445
468
|
if (existingOL) {
|
|
@@ -457,7 +480,6 @@ try {
|
|
|
457
480
|
let stagingFileDoc = null;
|
|
458
481
|
let stagingAtlasDoc = null;
|
|
459
482
|
let stagingCid = '';
|
|
460
|
-
let stagingSha256 = '';
|
|
461
483
|
try {
|
|
462
484
|
const itemKey = currentItemId;
|
|
463
485
|
|
|
@@ -546,8 +568,7 @@ try {
|
|
|
546
568
|
stagingData.render.cid = importItemCid;
|
|
547
569
|
stagingData.render.metadataCid = importItemMetadataCid;
|
|
548
570
|
|
|
549
|
-
// Pin data JSON to IPFS
|
|
550
|
-
stagingSha256 = ObjectLayerEngine.computeSha256(stagingData);
|
|
571
|
+
// Pin data JSON to IPFS
|
|
551
572
|
try {
|
|
552
573
|
const ipfsDataResult = await IpfsClient.addJsonToIpfs(
|
|
553
574
|
stagingData,
|
|
@@ -585,10 +606,9 @@ try {
|
|
|
585
606
|
// Create the new RenderFrames doc (only now touches DB)
|
|
586
607
|
const newRenderFrames = await ObjectLayerRenderFrames.create(objectLayerRenderFramesData);
|
|
587
608
|
|
|
588
|
-
// Single atomic
|
|
589
|
-
await ObjectLayer.
|
|
609
|
+
// Single atomic upsert on the natural key; empty staged CIDs keep their stored value
|
|
610
|
+
objectLayer = await ObjectLayer.upsertByItemId({
|
|
590
611
|
data: stagingData,
|
|
591
|
-
sha256: stagingSha256,
|
|
592
612
|
cid: stagingCid,
|
|
593
613
|
objectLayerRenderFramesId: newRenderFrames._id,
|
|
594
614
|
atlasSpriteSheetId: stagingAtlasDoc._id,
|
|
@@ -599,14 +619,13 @@ try {
|
|
|
599
619
|
await ObjectLayerRenderFrames.findByIdAndDelete(oldRenderFramesId);
|
|
600
620
|
}
|
|
601
621
|
|
|
602
|
-
logger.info(`[cut-over] Live document ${
|
|
622
|
+
logger.info(`[cut-over] Live document ${objectLayer._id} updated atomically`);
|
|
603
623
|
} else {
|
|
604
624
|
// Rollback: only File/AtlasSpriteSheet were written, clean those up
|
|
605
625
|
if (stagingFileDoc) await File.findByIdAndDelete(stagingFileDoc._id);
|
|
606
626
|
logger.warn(`[cut-over] Staging rolled back for ${currentItemId}, live document preserved`);
|
|
627
|
+
objectLayer = await ObjectLayer.findByItemId(currentItemId);
|
|
607
628
|
}
|
|
608
|
-
|
|
609
|
-
objectLayer = await ObjectLayer.findById(existingOL._id);
|
|
610
629
|
} else {
|
|
611
630
|
// ── New item: stage everything before creating (same cut-over pattern) ──
|
|
612
631
|
logger.info(`ObjectLayer '${currentItemId}' is new, staging creation...`);
|
|
@@ -621,7 +640,6 @@ try {
|
|
|
621
640
|
let stagingFileDoc = null;
|
|
622
641
|
let stagingAtlasDoc = null;
|
|
623
642
|
let stagingCid = '';
|
|
624
|
-
let stagingSha256 = '';
|
|
625
643
|
try {
|
|
626
644
|
const { buffer, metadata } = await AtlasSpriteSheetGenerator.generateAtlas(
|
|
627
645
|
objectLayerRenderFramesData,
|
|
@@ -705,7 +723,6 @@ try {
|
|
|
705
723
|
stagingData.render.cid = importItemCid;
|
|
706
724
|
stagingData.render.metadataCid = importItemMetadataCid;
|
|
707
725
|
|
|
708
|
-
stagingSha256 = ObjectLayerEngine.computeSha256(stagingData);
|
|
709
726
|
try {
|
|
710
727
|
const ipfsDataResult = await IpfsClient.addJsonToIpfs(
|
|
711
728
|
stagingData,
|
|
@@ -738,9 +755,8 @@ try {
|
|
|
738
755
|
|
|
739
756
|
if (cutoverReady) {
|
|
740
757
|
const newRenderFrames = await ObjectLayerRenderFrames.create(objectLayerRenderFramesData);
|
|
741
|
-
objectLayer = await ObjectLayer.
|
|
758
|
+
objectLayer = await ObjectLayer.upsertByItemId({
|
|
742
759
|
data: stagingData,
|
|
743
|
-
sha256: stagingSha256,
|
|
744
760
|
cid: stagingCid,
|
|
745
761
|
objectLayerRenderFramesId: newRenderFrames._id,
|
|
746
762
|
atlasSpriteSheetId: stagingAtlasDoc._id,
|
|
@@ -842,7 +858,7 @@ try {
|
|
|
842
858
|
|
|
843
859
|
if (shouldGenerateAtlas) {
|
|
844
860
|
// Check if an ObjectLayer with the same item.id already exists (upsert by item ID)
|
|
845
|
-
const existingOL = await ObjectLayer.
|
|
861
|
+
const existingOL = await ObjectLayer.findByItemId(objectLayerId);
|
|
846
862
|
let objectLayer;
|
|
847
863
|
|
|
848
864
|
if (existingOL) {
|
|
@@ -860,7 +876,6 @@ try {
|
|
|
860
876
|
let stagingFileDoc = null;
|
|
861
877
|
let stagingAtlasDoc = null;
|
|
862
878
|
let stagingCid = '';
|
|
863
|
-
let stagingSha256 = '';
|
|
864
879
|
try {
|
|
865
880
|
const itemKey = objectLayerId;
|
|
866
881
|
|
|
@@ -948,8 +963,7 @@ try {
|
|
|
948
963
|
stagingData.render.cid = importAtlasCid;
|
|
949
964
|
stagingData.render.metadataCid = importAtlasMetadataCid;
|
|
950
965
|
|
|
951
|
-
// Pin data JSON to IPFS
|
|
952
|
-
stagingSha256 = ObjectLayerEngine.computeSha256(stagingData);
|
|
966
|
+
// Pin data JSON to IPFS
|
|
953
967
|
try {
|
|
954
968
|
const ipfsDataResult = await IpfsClient.addJsonToIpfs(
|
|
955
969
|
stagingData,
|
|
@@ -985,9 +999,8 @@ try {
|
|
|
985
999
|
const oldRenderFramesId = existingOL.objectLayerRenderFramesId;
|
|
986
1000
|
const newRenderFrames = await ObjectLayerRenderFrames.create(entry.objectLayerRenderFramesData);
|
|
987
1001
|
|
|
988
|
-
await ObjectLayer.
|
|
1002
|
+
objectLayer = await ObjectLayer.upsertByItemId({
|
|
989
1003
|
data: stagingData,
|
|
990
|
-
sha256: stagingSha256,
|
|
991
1004
|
cid: stagingCid,
|
|
992
1005
|
objectLayerRenderFramesId: newRenderFrames._id,
|
|
993
1006
|
atlasSpriteSheetId: stagingAtlasDoc._id,
|
|
@@ -996,13 +1009,12 @@ try {
|
|
|
996
1009
|
if (oldRenderFramesId) {
|
|
997
1010
|
await ObjectLayerRenderFrames.findByIdAndDelete(oldRenderFramesId);
|
|
998
1011
|
}
|
|
999
|
-
logger.info(`[cut-over] Live document ${
|
|
1012
|
+
logger.info(`[cut-over] Live document ${objectLayer._id} updated atomically`);
|
|
1000
1013
|
} else {
|
|
1001
1014
|
if (stagingFileDoc) await File.findByIdAndDelete(stagingFileDoc._id);
|
|
1002
1015
|
logger.warn(`[cut-over] Staging rolled back for ${objectLayerId}, live document preserved`);
|
|
1016
|
+
objectLayer = await ObjectLayer.findByItemId(objectLayerId);
|
|
1003
1017
|
}
|
|
1004
|
-
|
|
1005
|
-
objectLayer = await ObjectLayer.findById(existingOL._id);
|
|
1006
1018
|
} else {
|
|
1007
1019
|
// ── New item: stage everything before creating (same cut-over pattern) ──
|
|
1008
1020
|
logger.info(`ObjectLayer '${objectLayerId}' is new, staging creation...`);
|
|
@@ -1017,7 +1029,6 @@ try {
|
|
|
1017
1029
|
let stagingFileDoc = null;
|
|
1018
1030
|
let stagingAtlasDoc = null;
|
|
1019
1031
|
let stagingCid = '';
|
|
1020
|
-
let stagingSha256 = '';
|
|
1021
1032
|
try {
|
|
1022
1033
|
const { buffer, metadata } = await AtlasSpriteSheetGenerator.generateAtlas(
|
|
1023
1034
|
entry.objectLayerRenderFramesData,
|
|
@@ -1101,7 +1112,6 @@ try {
|
|
|
1101
1112
|
stagingData.render.cid = importAtlasCid;
|
|
1102
1113
|
stagingData.render.metadataCid = importAtlasMetadataCid;
|
|
1103
1114
|
|
|
1104
|
-
stagingSha256 = ObjectLayerEngine.computeSha256(stagingData);
|
|
1105
1115
|
try {
|
|
1106
1116
|
const ipfsDataResult = await IpfsClient.addJsonToIpfs(
|
|
1107
1117
|
stagingData,
|
|
@@ -1134,9 +1144,8 @@ try {
|
|
|
1134
1144
|
|
|
1135
1145
|
if (cutoverReady) {
|
|
1136
1146
|
const newRenderFrames = await ObjectLayerRenderFrames.create(entry.objectLayerRenderFramesData);
|
|
1137
|
-
objectLayer = await ObjectLayer.
|
|
1147
|
+
objectLayer = await ObjectLayer.upsertByItemId({
|
|
1138
1148
|
data: stagingData,
|
|
1139
|
-
sha256: stagingSha256,
|
|
1140
1149
|
cid: stagingCid,
|
|
1141
1150
|
objectLayerRenderFramesId: newRenderFrames._id,
|
|
1142
1151
|
atlasSpriteSheetId: stagingAtlasDoc._id,
|
|
@@ -1159,7 +1168,7 @@ try {
|
|
|
1159
1168
|
if (existingItemIds.has(objectLayerId)) continue;
|
|
1160
1169
|
|
|
1161
1170
|
// --import all: create documents without atlas generation
|
|
1162
|
-
const existingOL = await ObjectLayer.
|
|
1171
|
+
const existingOL = await ObjectLayer.findByItemId(objectLayerId);
|
|
1163
1172
|
let objectLayer;
|
|
1164
1173
|
|
|
1165
1174
|
if (existingOL) {
|
|
@@ -1172,15 +1181,13 @@ try {
|
|
|
1172
1181
|
if (!stagingData.render) stagingData.render = {};
|
|
1173
1182
|
stagingData.render.cid = '';
|
|
1174
1183
|
stagingData.render.metadataCid = '';
|
|
1175
|
-
const stagingSha256 = ObjectLayerEngine.computeSha256(stagingData);
|
|
1176
1184
|
|
|
1177
1185
|
// Atomic cut-over: create new RenderFrames, swap live doc, delete old
|
|
1178
1186
|
const newRenderFrames = await ObjectLayerRenderFrames.create(entry.objectLayerRenderFramesData);
|
|
1179
1187
|
const oldRenderFramesId = existingOL.objectLayerRenderFramesId;
|
|
1180
1188
|
|
|
1181
|
-
await ObjectLayer.
|
|
1189
|
+
objectLayer = await ObjectLayer.upsertByItemId({
|
|
1182
1190
|
data: stagingData,
|
|
1183
|
-
sha256: stagingSha256,
|
|
1184
1191
|
objectLayerRenderFramesId: newRenderFrames._id,
|
|
1185
1192
|
});
|
|
1186
1193
|
|
|
@@ -1188,20 +1195,17 @@ try {
|
|
|
1188
1195
|
await ObjectLayerRenderFrames.findByIdAndDelete(oldRenderFramesId);
|
|
1189
1196
|
}
|
|
1190
1197
|
|
|
1191
|
-
objectLayer
|
|
1192
|
-
logger.info(`[cut-over] Live document ${existingOL._id} updated atomically (atlas skipped)`);
|
|
1198
|
+
logger.info(`[cut-over] Live document ${objectLayer._id} updated atomically (atlas skipped)`);
|
|
1193
1199
|
} else {
|
|
1194
|
-
// New item
|
|
1200
|
+
// New item (no atlas for bulk import)
|
|
1195
1201
|
const stagingData = JSON.parse(JSON.stringify(entry.data));
|
|
1196
1202
|
if (!stagingData.render) stagingData.render = {};
|
|
1197
1203
|
stagingData.render.cid = '';
|
|
1198
1204
|
stagingData.render.metadataCid = '';
|
|
1199
|
-
const stagingSha256 = ObjectLayerEngine.computeSha256(stagingData);
|
|
1200
1205
|
|
|
1201
1206
|
const newRenderFrames = await ObjectLayerRenderFrames.create(entry.objectLayerRenderFramesData);
|
|
1202
|
-
objectLayer = await ObjectLayer.
|
|
1207
|
+
objectLayer = await ObjectLayer.upsertByItemId({
|
|
1203
1208
|
data: stagingData,
|
|
1204
|
-
sha256: stagingSha256,
|
|
1205
1209
|
objectLayerRenderFramesId: newRenderFrames._id,
|
|
1206
1210
|
});
|
|
1207
1211
|
}
|
|
@@ -1231,9 +1235,7 @@ try {
|
|
|
1231
1235
|
logger.info(`Showing frame for item: ${itemId}, direction: ${direction}, frame: ${frameIndexNum}`);
|
|
1232
1236
|
|
|
1233
1237
|
// Find ObjectLayer by item-id
|
|
1234
|
-
const objectLayer = await ObjectLayer.
|
|
1235
|
-
'objectLayerRenderFramesId',
|
|
1236
|
-
);
|
|
1238
|
+
const objectLayer = await ObjectLayer.findByItemId(itemId).populate('objectLayerRenderFramesId');
|
|
1237
1239
|
|
|
1238
1240
|
if (!objectLayer) {
|
|
1239
1241
|
logger.error(`ObjectLayer not found for item-id: ${itemId}`);
|
|
@@ -1317,9 +1319,7 @@ try {
|
|
|
1317
1319
|
}
|
|
1318
1320
|
|
|
1319
1321
|
// Find ObjectLayer by item-id
|
|
1320
|
-
const objectLayer = await ObjectLayer.
|
|
1321
|
-
'objectLayerRenderFramesId',
|
|
1322
|
-
);
|
|
1322
|
+
const objectLayer = await ObjectLayer.findByItemId(itemId).populate('objectLayerRenderFramesId');
|
|
1323
1323
|
|
|
1324
1324
|
if (!objectLayer) {
|
|
1325
1325
|
logger.error(`ObjectLayer not found for item-id: ${itemId}`);
|
|
@@ -1453,7 +1453,7 @@ try {
|
|
|
1453
1453
|
logger.info(`Looking up atlas sprite sheet for item: ${itemId}`);
|
|
1454
1454
|
|
|
1455
1455
|
// Find ObjectLayer by item-id
|
|
1456
|
-
const objectLayer = await ObjectLayer.
|
|
1456
|
+
const objectLayer = await ObjectLayer.findByItemId(itemId);
|
|
1457
1457
|
|
|
1458
1458
|
if (!objectLayer) {
|
|
1459
1459
|
logger.error(`ObjectLayer not found for item-id: ${itemId}`);
|
|
@@ -1733,6 +1733,18 @@ try {
|
|
|
1733
1733
|
'When used with --export or --import, only process cyberia-instance.json and cyberia-instance-conf.json',
|
|
1734
1734
|
)
|
|
1735
1735
|
.option('--drop', 'Drop all documents associated with the instance code before importing or as a standalone action')
|
|
1736
|
+
.option(
|
|
1737
|
+
'--export-current-fallbackworld',
|
|
1738
|
+
'Capture the in-memory procedural fallback world as instance [instance-code]: materialize it into MongoDB (maps, conf, actions, quests, missing content defaults) and then export it',
|
|
1739
|
+
)
|
|
1740
|
+
.option(
|
|
1741
|
+
'--keep-fallback-codes',
|
|
1742
|
+
'With --export-current-fallbackworld, keep the raw fallback-map-* / canonical action-quest codes instead of namespacing them under the instance code',
|
|
1743
|
+
)
|
|
1744
|
+
.option(
|
|
1745
|
+
'--fallback-url <url>',
|
|
1746
|
+
'With --export-current-fallbackworld, capture the world a running engine currently serves (e.g. http://localhost:4001) instead of regenerating it locally',
|
|
1747
|
+
)
|
|
1736
1748
|
.option('--env-path <env-path>', 'Env path e.g. ./engine-private/conf/dd-cyberia/.env.development')
|
|
1737
1749
|
.option('--mongo-host <mongo-host>', 'Mongo host override')
|
|
1738
1750
|
.option('--dev', 'Force development environment')
|
|
@@ -1747,16 +1759,40 @@ try {
|
|
|
1747
1759
|
.description('Export/import a Cyberia instance with all related maps, entities and object layers')
|
|
1748
1760
|
.action(async (instanceCode, options = {}) => {
|
|
1749
1761
|
if (options.revert) {
|
|
1750
|
-
|
|
1751
|
-
shellExec(`cd /home/dd/
|
|
1752
|
-
shellExec(`cd /home/dd/engine/cyberia-
|
|
1762
|
+
Underpost.repo.declareSafeDirectory('/home/dd/cyberia-instances');
|
|
1763
|
+
shellExec(`cd /home/dd/cyberia-instances && ${cli()} cmt . reset && ${cli()} run clean .`);
|
|
1764
|
+
shellExec(`cd /home/dd/engine/cyberia-server && ${cli()} cmt . reset && ${cli()} run clean .`);
|
|
1765
|
+
shellExec(`cd /home/dd/engine/cyberia-client && ${cli()} cmt . reset && ${cli()} run clean .`);
|
|
1753
1766
|
return;
|
|
1754
1767
|
}
|
|
1768
|
+
if (options.exportCurrentFallbackworld) {
|
|
1769
|
+
// A capture writes one named instance: no default list, no import in the
|
|
1770
|
+
// same run, and never the reserved code the in-memory world itself uses.
|
|
1771
|
+
if (!instanceCode || instanceCode.includes(',')) {
|
|
1772
|
+
logger.error('--export-current-fallbackworld requires a single [instance-code] to capture the world under');
|
|
1773
|
+
process.exit(1);
|
|
1774
|
+
}
|
|
1775
|
+
if (instanceCode === 'fallback') {
|
|
1776
|
+
logger.error('"fallback" is reserved for the in-memory world — capture it under a different instance code');
|
|
1777
|
+
process.exit(1);
|
|
1778
|
+
}
|
|
1779
|
+
if (options.import !== undefined) {
|
|
1780
|
+
logger.error('--export-current-fallbackworld cannot be combined with --import');
|
|
1781
|
+
process.exit(1);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1755
1785
|
if (!instanceCode) {
|
|
1756
|
-
instanceCode = 'amethyst-strata-expansion,FOREST';
|
|
1786
|
+
instanceCode = 'amethyst-strata-expansion,FOREST,TEST';
|
|
1757
1787
|
logger.warn(`No instance code provided, defaulting to: ${instanceCode}`);
|
|
1758
1788
|
}
|
|
1759
1789
|
|
|
1790
|
+
// An explicitly named env must exist: falling through to the ambient `./.env` resolves the
|
|
1791
|
+
// instance against whatever deployment was loaded last, which is not the one the caller named.
|
|
1792
|
+
if (options.envPath && !fs.existsSync(options.envPath)) {
|
|
1793
|
+
logger.error(`Env file not found: ${options.envPath}`);
|
|
1794
|
+
process.exit(1);
|
|
1795
|
+
}
|
|
1760
1796
|
if (!options.envPath) options.envPath = `./.env`;
|
|
1761
1797
|
if (fs.existsSync(options.envPath)) dotenv.config({ path: options.envPath, override: true });
|
|
1762
1798
|
|
|
@@ -1778,12 +1814,15 @@ try {
|
|
|
1778
1814
|
}
|
|
1779
1815
|
|
|
1780
1816
|
if (options.publish || options.publishBuild || options.publishRemove) {
|
|
1817
|
+
// The instances checkout is cloned by the deploy user and driven by root during a deploy,
|
|
1818
|
+
// and git refuses to touch a tree owned by someone else until it is declared safe.
|
|
1819
|
+
Underpost.repo.declareSafeDirectory('/home/dd/cyberia-instances');
|
|
1781
1820
|
if (options.publishBuild) {
|
|
1782
1821
|
if (!fs.existsSync('/home/dd/cyberia-instances')) {
|
|
1783
|
-
shellExec(
|
|
1822
|
+
shellExec(`cd /home/dd && ${cli()} clone underpostnet/cyberia-instances`);
|
|
1784
1823
|
} else {
|
|
1785
|
-
shellExec(
|
|
1786
|
-
shellExec(`cd /home/dd/cyberia-instances &&
|
|
1824
|
+
shellExec(`${cli()} run clean /home/dd/cyberia-instances`);
|
|
1825
|
+
shellExec(`cd /home/dd/cyberia-instances && ${cli()} pull . underpostnet/cyberia-instances`, {
|
|
1787
1826
|
silentOnError: true,
|
|
1788
1827
|
});
|
|
1789
1828
|
}
|
|
@@ -1810,40 +1849,24 @@ try {
|
|
|
1810
1849
|
`/home/dd/cyberia-instances/conf/dd-cyberia/conf.volume.json`,
|
|
1811
1850
|
);
|
|
1812
1851
|
{
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
);
|
|
1818
|
-
const originPackageJson = JSON.parse(
|
|
1819
|
-
fs.readFileSync(`./engine-private/conf/dd-cyberia/package.json`, 'utf-8'),
|
|
1820
|
-
);
|
|
1821
|
-
const scriptsOrigin = originPackageJson.scripts;
|
|
1822
|
-
const scriptsTarget = JSON.parse(fs.readFileSync(`./package.json`, 'utf-8')).scripts;
|
|
1823
|
-
originPackageJson.name = 'cyberia';
|
|
1824
|
-
originPackageJson.bin = {
|
|
1825
|
-
cyberia: 'bin/index.js',
|
|
1826
|
-
};
|
|
1827
|
-
originPackageJson.keywords = catalog.keywords;
|
|
1828
|
-
originPackageJson.description = catalog.description;
|
|
1852
|
+
// The published manifest is the deploy's, under the product's own identity — one
|
|
1853
|
+
// builder for every generated package.json in the project, so the instances repo
|
|
1854
|
+
// cannot drift from what the deploy and the product CLI declare.
|
|
1855
|
+
const deployPackagePath = deployPackagePathFactory('dd-cyberia');
|
|
1829
1856
|
fs.writeFileSync(
|
|
1830
1857
|
`/home/dd/cyberia-instances/conf/dd-cyberia/package.json`,
|
|
1831
|
-
JSON.stringify(
|
|
1832
|
-
{
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
dependencies: {
|
|
1840
|
-
...originPackageJson.dependencies,
|
|
1841
|
-
...CyberiaDependencies,
|
|
1842
|
-
},
|
|
1843
|
-
},
|
|
1858
|
+
`${JSON.stringify(
|
|
1859
|
+
buildDeployPackageJson({
|
|
1860
|
+
deployId: 'dd-cyberia',
|
|
1861
|
+
enginePackageJson: JSON.parse(fs.readFileSync(`./package.json`, 'utf-8')),
|
|
1862
|
+
catalog: await loadDeployCatalog('dd-cyberia'),
|
|
1863
|
+
currentPackageJson: JSON.parse(fs.readFileSync(deployPackagePath, 'utf-8')),
|
|
1864
|
+
productIdentity: true,
|
|
1865
|
+
}),
|
|
1844
1866
|
null,
|
|
1845
|
-
|
|
1846
|
-
)
|
|
1867
|
+
DEPLOY_MANIFEST_INDENT,
|
|
1868
|
+
)}\n`,
|
|
1869
|
+
'utf8',
|
|
1847
1870
|
);
|
|
1848
1871
|
}
|
|
1849
1872
|
fs.copyFileSync(
|
|
@@ -1860,7 +1883,11 @@ try {
|
|
|
1860
1883
|
);
|
|
1861
1884
|
|
|
1862
1885
|
fs.mkdirpSync(`/home/dd/cyberia-instances/deployments`);
|
|
1863
|
-
|
|
1886
|
+
// The staged CLI package is a local image-build artifact, not a deployment manifest —
|
|
1887
|
+
// it must never be published into the instances repository.
|
|
1888
|
+
fs.copySync(`./src/runtime/engine-cyberia`, `/home/dd/cyberia-instances/deployments/engine-cyberia`, {
|
|
1889
|
+
filter: (src) => nodePath.basename(src) !== STAGED_CLI_PACKAGE,
|
|
1890
|
+
});
|
|
1864
1891
|
fs.copySync(
|
|
1865
1892
|
`./manifests/deployment/dd-cyberia-development/.`,
|
|
1866
1893
|
`/home/dd/cyberia-instances/deployments/engine-cyberia/.`,
|
|
@@ -1875,32 +1902,8 @@ try {
|
|
|
1875
1902
|
`./engine-private/conf/dd-cyberia/instances/mmo-server/build/development/.`,
|
|
1876
1903
|
`/home/dd/cyberia-instances/deployments/cyberia-server/.`,
|
|
1877
1904
|
);
|
|
1878
|
-
fs.removeSync(`/home/dd/cyberia-instances/public/cyberia`);
|
|
1879
|
-
fs.mkdirpSync(`/home/dd/cyberia-instances/public/cyberia`);
|
|
1880
|
-
for (const assetPath of Object.keys(
|
|
1881
|
-
JSON.parse(fs.readFileSync(`./engine-private/conf/dd-cyberia/storage.engine-cyberia.json`, 'utf-8')),
|
|
1882
|
-
)) {
|
|
1883
|
-
const relativePath = assetPath.replace(/^src\/client\/public\/cyberia\//, '');
|
|
1884
|
-
const targetPath = `/home/dd/cyberia-instances/public/cyberia/${relativePath}`;
|
|
1885
|
-
fs.mkdirpSync(nodePath.dirname(targetPath));
|
|
1886
|
-
logger.info(`Copying asset: ${assetPath} → ${targetPath}`);
|
|
1887
|
-
fs.copySync(`./${assetPath}`, targetPath);
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
// Copy default-items asset folders (src/client/public/cyberia/assets/<type>/<id>/ → public/cyberia/assets/<type>/<id>/)
|
|
1891
|
-
for (const entry of DefaultCyberiaItems) {
|
|
1892
|
-
const { id, type } = entry.item;
|
|
1893
|
-
const srcDir = `src/client/public/cyberia/assets/${type}/${id}`;
|
|
1894
|
-
const targetDir = `/home/dd/cyberia-instances/public/cyberia/assets/${type}/${id}`;
|
|
1895
|
-
if (fs.existsSync(srcDir)) {
|
|
1896
|
-
fs.mkdirpSync(nodePath.dirname(targetDir));
|
|
1897
|
-
logger.info(`Copying default-item asset: ${srcDir} → ${targetDir}`);
|
|
1898
|
-
fs.copySync(srcDir, targetDir);
|
|
1899
|
-
} else {
|
|
1900
|
-
logger.warn(`Default-item asset directory not found, skipping: ${srcDir}`);
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1905
|
+
// fs.removeSync(`/home/dd/cyberia-instances/public/cyberia`);
|
|
1906
|
+
// fs.mkdirpSync(`/home/dd/cyberia-instances/public/cyberia`);
|
|
1904
1907
|
fs.mkdirpSync(`/home/dd/cyberia-instances/instances`);
|
|
1905
1908
|
fs.mkdirpSync(`/home/dd/cyberia-instances/sagas`);
|
|
1906
1909
|
for (const _instanceCode of instanceCode.split(',')) {
|
|
@@ -1957,7 +1960,7 @@ try {
|
|
|
1957
1960
|
shellExec(`rm -rf /home/dd/cyberia-instances/sagas/${instanceCode}.json`);
|
|
1958
1961
|
return;
|
|
1959
1962
|
}
|
|
1960
|
-
shellExec(`cd /home/dd/cyberia-instances &&
|
|
1963
|
+
shellExec(`cd /home/dd/cyberia-instances && ${cli()} push . underpostnet/cyberia-instances`);
|
|
1961
1964
|
return;
|
|
1962
1965
|
}
|
|
1963
1966
|
|
|
@@ -2136,6 +2139,89 @@ try {
|
|
|
2136
2139
|
}
|
|
2137
2140
|
};
|
|
2138
2141
|
|
|
2142
|
+
// ── CAPTURE CURRENT FALLBACK WORLD ──────────────────────────────
|
|
2143
|
+
//
|
|
2144
|
+
// The procedural fallback world only exists in engine memory (see
|
|
2145
|
+
// cyberia-fallback-world.js): it is rebuilt from code defaults on every
|
|
2146
|
+
// boot and intercepts any service that asks for an absent instance.
|
|
2147
|
+
// Capturing writes that exact world into MongoDB under [instance-code] —
|
|
2148
|
+
// together with the content collections the fallback path serves from
|
|
2149
|
+
// code defaults rather than the DB — so the export below can back it up
|
|
2150
|
+
// and `--import` can restore it as an ordinary persisted instance.
|
|
2151
|
+
if (options.exportCurrentFallbackworld) {
|
|
2152
|
+
const { generateFallbackWorld } = await import('../src/api/cyberia-instance/cyberia-fallback-world.js');
|
|
2153
|
+
const { captureFallbackWorld } = await import('../src/api/cyberia-instance/cyberia-fallback-capture.js');
|
|
2154
|
+
|
|
2155
|
+
let world;
|
|
2156
|
+
if (options.fallbackUrl) {
|
|
2157
|
+
// Staged fallback default items live only in the serving engine
|
|
2158
|
+
// process, so a faithful capture of a live world must read it back
|
|
2159
|
+
// over REST instead of regenerating it here.
|
|
2160
|
+
const base = options.fallbackUrl.replace(/\/+$/, '');
|
|
2161
|
+
const worldUrl = base.includes('/fallback-world') ? base : `${base}/api/cyberia-instance/fallback-world`;
|
|
2162
|
+
logger.info('Fetching live fallback world', { url: worldUrl });
|
|
2163
|
+
const response = await fetch(worldUrl);
|
|
2164
|
+
if (!response.ok) {
|
|
2165
|
+
logger.error(`Fallback world fetch failed: ${response.status} ${response.statusText}`, { url: worldUrl });
|
|
2166
|
+
await DataBaseProviderService.getProvider({ host, path }, 'mongoose').close();
|
|
2167
|
+
process.exit(1);
|
|
2168
|
+
}
|
|
2169
|
+
const payload = await response.json();
|
|
2170
|
+
world = payload?.data ?? payload;
|
|
2171
|
+
} else {
|
|
2172
|
+
world = generateFallbackWorld();
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
if (!world?.instance || !Array.isArray(world.maps) || world.maps.length === 0) {
|
|
2176
|
+
logger.error('Fallback world payload has no maps — nothing to capture');
|
|
2177
|
+
await DataBaseProviderService.getProvider({ host, path }, 'mongoose').close();
|
|
2178
|
+
process.exit(1);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
const capture = await captureFallbackWorld({
|
|
2182
|
+
models: {
|
|
2183
|
+
CyberiaInstance,
|
|
2184
|
+
CyberiaInstanceConf,
|
|
2185
|
+
CyberiaMap,
|
|
2186
|
+
CyberiaAction,
|
|
2187
|
+
CyberiaQuest,
|
|
2188
|
+
CyberiaSkill,
|
|
2189
|
+
CyberiaEntityTypeDefault,
|
|
2190
|
+
CyberiaDialogue,
|
|
2191
|
+
ObjectLayer,
|
|
2192
|
+
},
|
|
2193
|
+
world,
|
|
2194
|
+
instanceCode,
|
|
2195
|
+
keepFallbackCodes: !!options.keepFallbackCodes,
|
|
2196
|
+
});
|
|
2197
|
+
|
|
2198
|
+
// Sprites are the one thing a capture cannot synthesise: without their
|
|
2199
|
+
// ObjectLayer documents the backup would export atlas-less items and
|
|
2200
|
+
// the restored world would render solid-colour rectangles.
|
|
2201
|
+
if (capture.missingObjectLayerItemIds.length > 0) {
|
|
2202
|
+
logger.error(
|
|
2203
|
+
`Capture aborted: ${capture.missingObjectLayerItemIds.length} referenced item id(s) have no ObjectLayer in MongoDB:`,
|
|
2204
|
+
capture.missingObjectLayerItemIds.join(', '),
|
|
2205
|
+
`— run \`node bin/cyberia ol ${capture.missingObjectLayerItemIds.join(' ')} --import\` (or ` +
|
|
2206
|
+
'`node bin/cyberia run-workflow import-default-items`) first.',
|
|
2207
|
+
);
|
|
2208
|
+
await DataBaseProviderService.getProvider({ host, path }, 'mongoose').close();
|
|
2209
|
+
process.exit(1);
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
logger.info('Captured fallback world into MongoDB', {
|
|
2213
|
+
code: instanceCode,
|
|
2214
|
+
mapCodes: capture.plan.instance.cyberiaMapCodes,
|
|
2215
|
+
actions: capture.plan.actions.length,
|
|
2216
|
+
quests: capture.plan.quests.length,
|
|
2217
|
+
objectLayerItemIds: capture.plan.itemIds.length,
|
|
2218
|
+
});
|
|
2219
|
+
|
|
2220
|
+
// The capture is only half the command — fall through to the export so
|
|
2221
|
+
// it lands in ./engine-private/cyberia-instances/<instance-code>.
|
|
2222
|
+
if (options.export === undefined) options.export = true;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2139
2225
|
// ── EXPORT ──────────────────────────────────────────────────────
|
|
2140
2226
|
if (options.export !== undefined) {
|
|
2141
2227
|
const instance = await CyberiaInstance.findOne({ code: instanceCode }).lean();
|
|
@@ -2307,6 +2393,37 @@ try {
|
|
|
2307
2393
|
}
|
|
2308
2394
|
}
|
|
2309
2395
|
|
|
2396
|
+
// 4c-bis. Add the item ids the instance's vendor / assembler / quest
|
|
2397
|
+
// catalogs name. The interact modal draws an icon for every shop
|
|
2398
|
+
// item, recipe ingredient/output and quest reward, so their atlases
|
|
2399
|
+
// must travel with the backup even when no map entity wears them.
|
|
2400
|
+
// Kept out of contentItemIds: catalogs must not widen the
|
|
2401
|
+
// entity-type-default match surface below.
|
|
2402
|
+
for (const action of actions) {
|
|
2403
|
+
for (const shopItem of action.shopItems || []) {
|
|
2404
|
+
if (shopItem.itemId) objectLayerItemIds.add(shopItem.itemId);
|
|
2405
|
+
if (shopItem.priceItemId) objectLayerItemIds.add(shopItem.priceItemId);
|
|
2406
|
+
}
|
|
2407
|
+
for (const recipe of action.craftRecipes || []) {
|
|
2408
|
+
for (const ingredient of recipe.ingredients || []) {
|
|
2409
|
+
if (ingredient.itemId) objectLayerItemIds.add(ingredient.itemId);
|
|
2410
|
+
}
|
|
2411
|
+
for (const output of recipe.outputItems || []) {
|
|
2412
|
+
if (output.itemId) objectLayerItemIds.add(output.itemId);
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
for (const quest of quests) {
|
|
2417
|
+
for (const step of quest.steps || []) {
|
|
2418
|
+
for (const objective of step.objectives || []) {
|
|
2419
|
+
if (objective.itemId) objectLayerItemIds.add(objective.itemId);
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
for (const reward of quest.rewards || []) {
|
|
2423
|
+
if (reward.itemId) objectLayerItemIds.add(reward.itemId);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2310
2427
|
// 4d. Export skills whose trigger item belongs to this instance (own model:
|
|
2311
2428
|
// CyberiaSkill, keyed by triggerItemId). Their summoned-entity items are
|
|
2312
2429
|
// added to the OL set so those atlases export too. Runs before the
|
|
@@ -2695,6 +2812,12 @@ try {
|
|
|
2695
2812
|
|
|
2696
2813
|
logger.info('Importing instance', { code: instanceCode, backupDir });
|
|
2697
2814
|
|
|
2815
|
+
// Idempotent: a backup restore writes object layers, so collapse any
|
|
2816
|
+
// legacy duplicates and make the data.item.id index unique first.
|
|
2817
|
+
const { removedIds, indexUpgraded } = await ObjectLayer.ensureUniqueItemIdIndex();
|
|
2818
|
+
if (removedIds.length > 0) logger.warn(`Removed ${removedIds.length} duplicate ObjectLayer document(s)`);
|
|
2819
|
+
if (indexUpgraded) logger.info('Upgraded data.item.id index to unique');
|
|
2820
|
+
|
|
2698
2821
|
// Item ids belonging to this instance (collected from imported object
|
|
2699
2822
|
// layers + the instance doc) — used to backfill missing skills from the
|
|
2700
2823
|
// canonical DefaultSkillConfig when the backup predates the skill model.
|
|
@@ -3029,12 +3152,21 @@ try {
|
|
|
3029
3152
|
let olCount = 0;
|
|
3030
3153
|
for (const file of olFiles) {
|
|
3031
3154
|
const olData = fs.readJsonSync(`${olDir}/${file}`);
|
|
3032
|
-
|
|
3033
|
-
if (
|
|
3034
|
-
|
|
3155
|
+
const olItemId = olData.data?.item?.id;
|
|
3156
|
+
if (!olItemId) {
|
|
3157
|
+
logger.warn(`Skipping object-layer file '${file}' — missing data.item.id`);
|
|
3158
|
+
continue;
|
|
3035
3159
|
}
|
|
3036
|
-
|
|
3037
|
-
|
|
3160
|
+
// preserveUUID only applies to items this database does not have yet.
|
|
3161
|
+
// An item that already exists keeps its own _id and simply absorbs the
|
|
3162
|
+
// backup's attribute values, so a restore can never fork data.item.id
|
|
3163
|
+
// into two documents. sha256 needs no separate cleanup: it is derived
|
|
3164
|
+
// from data, so an identical hash implies the same item id.
|
|
3165
|
+
const existingOL = await ObjectLayer.findByItemId(olItemId);
|
|
3166
|
+
if (!existingOL && olData._id) await ObjectLayer.deleteOne({ _id: olData._id });
|
|
3167
|
+
|
|
3168
|
+
await ObjectLayer.upsertByItemId(olData);
|
|
3169
|
+
importedItemIds.add(olItemId);
|
|
3038
3170
|
olCount++;
|
|
3039
3171
|
}
|
|
3040
3172
|
logger.info(`Imported ${olCount} ObjectLayer document(s)`);
|
|
@@ -4827,16 +4959,23 @@ try {
|
|
|
4827
4959
|
shellExec(
|
|
4828
4960
|
`node bin/cyberia generate-saga --import engine-private/cyberia-sagas/${sagaCode}.json${devFlag}${mongoHostFlag}`,
|
|
4829
4961
|
);
|
|
4830
|
-
shellExec(`node bin/cyberia ol ${DefaultCyberiaItems.map((e) => e.item.id)} --import${devFlag}${mongoHostFlag}`);
|
|
4831
|
-
shellExec(`node bin/cyberia run-workflow seed-skills${devFlag}${mongoHostFlag}`);
|
|
4832
|
-
shellExec(`node bin/cyberia run-workflow seed-entities${devFlag}${mongoHostFlag}`);
|
|
4833
|
-
shellExec(`node bin/cyberia run-workflow seed-dialogues${devFlag}${mongoHostFlag}`);
|
|
4834
|
-
shellExec(`node bin/cyberia run-workflow seed-actions-quests${devFlag}${mongoHostFlag}`);
|
|
4835
|
-
shellExec(`node bin/cyberia client-hints ${instanceHintsCode} --seed-defaults${devFlag}${mongoHostFlag}`);
|
|
4962
|
+
// shellExec(`node bin/cyberia ol ${DefaultCyberiaItems.map((e) => e.item.id)} --import${devFlag}${mongoHostFlag}`);
|
|
4963
|
+
// shellExec(`node bin/cyberia run-workflow seed-skills${devFlag}${mongoHostFlag}`);
|
|
4964
|
+
// shellExec(`node bin/cyberia run-workflow seed-entities${devFlag}${mongoHostFlag}`);
|
|
4965
|
+
// shellExec(`node bin/cyberia run-workflow seed-dialogues${devFlag}${mongoHostFlag}`);
|
|
4966
|
+
// shellExec(`node bin/cyberia run-workflow seed-actions-quests${devFlag}${mongoHostFlag}`);
|
|
4967
|
+
// shellExec(`node bin/cyberia client-hints ${instanceHintsCode} --seed-defaults${devFlag}${mongoHostFlag}`);
|
|
4836
4968
|
shellExec(`node bin/cyberia instance ${sagaCode} --import${devFlag}`);
|
|
4837
4969
|
shellExec(`node bin/cyberia instance FOREST --import${devFlag}`);
|
|
4970
|
+
shellExec(`node bin/cyberia instance TEST --import${devFlag}`);
|
|
4838
4971
|
});
|
|
4839
4972
|
|
|
4973
|
+
runner
|
|
4974
|
+
.command('stage-cli')
|
|
4975
|
+
.option('--output-path <output-path>', "Build context to stage the package in (default: '.')")
|
|
4976
|
+
.description('Packs this engine checkout as underpost-cli.tgz for a runtime image build context')
|
|
4977
|
+
.action((options) => stageCliPackage(options.outputPath || '.'));
|
|
4978
|
+
|
|
4840
4979
|
runner.command('sync-src').action(() => {
|
|
4841
4980
|
fs.copyFileSync('./cyberia-server/README.md', './src/client/public/cyberia-docs/CYBERIA-SERVER.md');
|
|
4842
4981
|
fs.copyFileSync('./cyberia-server/Dockerfile', './src/runtime/cyberia-server/Dockerfile');
|
|
@@ -4844,6 +4983,25 @@ try {
|
|
|
4844
4983
|
fs.copyFileSync('./cyberia-client/Dockerfile', './src/runtime/cyberia-client/Dockerfile');
|
|
4845
4984
|
});
|
|
4846
4985
|
|
|
4986
|
+
runner.command('setup-workspace').action(() => {
|
|
4987
|
+
shellExec(`node bin fs src/client/public/cyberia --git --recursive --pull --deploy-id dd-cyberia`);
|
|
4988
|
+
shellExec(`node bin/deploy.js cyberia`);
|
|
4989
|
+
if (!fs.existsSync('./cyberia-server')) shellExec(`${cli()} clone underpostnet/cyberia-server`);
|
|
4990
|
+
if (!fs.existsSync('./cyberia-client')) shellExec(`${cli()} clone underpostnet/cyberia-client`);
|
|
4991
|
+
});
|
|
4992
|
+
|
|
4993
|
+
runner.command('e2e-build').action(() => {
|
|
4994
|
+
shellExec(`node bin run build-cluster-deployment-manifests`);
|
|
4995
|
+
shellExec(`node bin/cyberia run-workflow build-manifest`);
|
|
4996
|
+
shellExec(`node bin/cyberia run-workflow publish --dry-run`);
|
|
4997
|
+
shellExec(`npm run security`);
|
|
4998
|
+
shellExec(`sudo rm -rf ./conf.dd*.js`);
|
|
4999
|
+
});
|
|
5000
|
+
|
|
5001
|
+
runner.command('cluster').action(() => {
|
|
5002
|
+
shellExec(`node bin run cluster --runtime-image express --deploy-id dd-cyberia --instance-id mmo-server --dev`);
|
|
5003
|
+
});
|
|
5004
|
+
|
|
4847
5005
|
runner
|
|
4848
5006
|
.command('dev-env')
|
|
4849
5007
|
.option('--run', 'Run docker:reset, cluster --dev --reset, docker-image, and docker:up after updating compose.env')
|
|
@@ -5026,6 +5184,57 @@ try {
|
|
|
5026
5184
|
shellExec(`gh workflow run ${id}.cd.yml -R underpostnet/${id} -f job=deploy`);
|
|
5027
5185
|
});
|
|
5028
5186
|
|
|
5187
|
+
runner.command('cp-assets').action(() => {
|
|
5188
|
+
for (const assetPath of Object.keys(
|
|
5189
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/dd-cyberia/storage.engine-cyberia.json`, 'utf-8')),
|
|
5190
|
+
)) {
|
|
5191
|
+
const relativePath = assetPath.replace(/^src\/client\/public\/cyberia\//, '');
|
|
5192
|
+
const targetPath = `/home/dd/cyberia-instances/public/cyberia/${relativePath}`;
|
|
5193
|
+
fs.mkdirpSync(nodePath.dirname(targetPath));
|
|
5194
|
+
logger.info(`Copying asset: ${assetPath} → ${targetPath}`);
|
|
5195
|
+
fs.copySync(`./${assetPath}`, targetPath);
|
|
5196
|
+
}
|
|
5197
|
+
|
|
5198
|
+
// Copy default-items asset folders (src/client/public/cyberia/assets/<type>/<id>/ → public/cyberia/assets/<type>/<id>/)
|
|
5199
|
+
for (const entry of DefaultCyberiaItems) {
|
|
5200
|
+
const { id, type } = entry.item;
|
|
5201
|
+
const srcDir = `src/client/public/cyberia/assets/${type}/${id}`;
|
|
5202
|
+
const targetDir = `/home/dd/cyberia-instances/public/cyberia/assets/${type}/${id}`;
|
|
5203
|
+
if (fs.existsSync(srcDir)) {
|
|
5204
|
+
fs.mkdirpSync(nodePath.dirname(targetDir));
|
|
5205
|
+
logger.info(`Copying default-item asset: ${srcDir} → ${targetDir}`);
|
|
5206
|
+
fs.copySync(srcDir, targetDir);
|
|
5207
|
+
} else {
|
|
5208
|
+
logger.warn(`Default-item asset directory not found, skipping: ${srcDir}`);
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
});
|
|
5212
|
+
|
|
5213
|
+
runner
|
|
5214
|
+
.command('sync-cluster')
|
|
5215
|
+
.option('--build')
|
|
5216
|
+
.action((options) => {
|
|
5217
|
+
shellExec(`node bin/build dd-cyberia --update-private`);
|
|
5218
|
+
shellExec(`node bin/build dd-core --update-private`);
|
|
5219
|
+
if (options.build) return;
|
|
5220
|
+
shellExec(
|
|
5221
|
+
`node bin wireguard --sync --repo-engine underpostnet/engine-test-cyberia --repo-engine-private underpostnet/engine-private`,
|
|
5222
|
+
);
|
|
5223
|
+
});
|
|
5224
|
+
|
|
5225
|
+
runner
|
|
5226
|
+
.command('test')
|
|
5227
|
+
.option('--n-con <connections>', 'Number of concurrent WebSocket connections')
|
|
5228
|
+
.option('--duration <ms>', 'Load test duration in milliseconds')
|
|
5229
|
+
.option('--tap-freq <seconds>', 'Frequency of tap events in seconds')
|
|
5230
|
+
.action((options) => {
|
|
5231
|
+
shellExec(`CYBERIA_LOAD_WS_URL=ws://localhost:8081/ws \
|
|
5232
|
+
CYBERIA_LOAD_CONNECTIONS=${options.nCon ?? 40} \
|
|
5233
|
+
CYBERIA_LOAD_TAP_FREQUENCY=${options.tapFreq ?? 5} \
|
|
5234
|
+
CYBERIA_LOAD_DURATION_MS=${options.duration ?? 1000 * 60 * 30} \
|
|
5235
|
+
node bin test cyberia --grep 'Cyberia load'`);
|
|
5236
|
+
});
|
|
5237
|
+
|
|
5029
5238
|
runner
|
|
5030
5239
|
.command('docker-image [id]')
|
|
5031
5240
|
.option('--load-tar', 'Load a pre-built image tar archive into the enabled target(s) without building.')
|
|
@@ -5033,46 +5242,49 @@ try {
|
|
|
5033
5242
|
// no funca
|
|
5034
5243
|
if (options.loadTar) {
|
|
5035
5244
|
for (const imageId of dockerImageIds)
|
|
5036
|
-
if (imageId === id || id === '.') shellExec(`docker load -i ./${imageId}-dev_v3.
|
|
5245
|
+
if (imageId === id || id === '.') shellExec(`docker load -i ./${imageId}-dev_v3.3.73.tar`);
|
|
5037
5246
|
return;
|
|
5038
5247
|
}
|
|
5039
5248
|
switch (id) {
|
|
5040
5249
|
case 'engine-cyberia':
|
|
5250
|
+
stageCliPackage(`./src/runtime/engine-cyberia`);
|
|
5041
5251
|
shellExec(`
|
|
5042
5252
|
node bin/build dd-cyberia --conf
|
|
5043
5253
|
node bin/build dd-cyberia --update-private
|
|
5044
5254
|
node bin image --path src/runtime/engine-cyberia \
|
|
5045
5255
|
--docker-compose --pull-base --build \
|
|
5046
5256
|
--dockerfile-name Dockerfile.dev \
|
|
5047
|
-
--image-name engine-cyberia-dev:v3.
|
|
5257
|
+
--image-name engine-cyberia-dev:v3.3.73 \
|
|
5048
5258
|
--image-out-path .
|
|
5049
5259
|
`);
|
|
5050
5260
|
break;
|
|
5051
5261
|
|
|
5052
5262
|
case 'cyberia-server':
|
|
5263
|
+
stageCliPackage(`./cyberia-server`);
|
|
5053
5264
|
shellExec(`
|
|
5054
5265
|
cp -f src/runtime/cyberia-server/Dockerfile.dev cyberia-server/Dockerfile.dev
|
|
5055
5266
|
node bin image --path cyberia-server \
|
|
5056
5267
|
--docker-compose --pull-base --build \
|
|
5057
5268
|
--dockerfile-name Dockerfile.dev \
|
|
5058
|
-
--image-name cyberia-server-dev:v3.
|
|
5269
|
+
--image-name cyberia-server-dev:v3.3.73 \
|
|
5059
5270
|
--image-out-path .
|
|
5060
5271
|
`);
|
|
5061
5272
|
break;
|
|
5062
5273
|
case 'cyberia-client':
|
|
5274
|
+
stageCliPackage(`./cyberia-client`);
|
|
5063
5275
|
shellExec(`
|
|
5064
5276
|
cp -f src/runtime/cyberia-client/Dockerfile.dev cyberia-client/Dockerfile.dev
|
|
5065
5277
|
node bin image --path cyberia-client \
|
|
5066
5278
|
--docker-compose --pull-base --build \
|
|
5067
5279
|
--dockerfile-name Dockerfile.dev \
|
|
5068
|
-
--image-name cyberia-client-dev:v3.
|
|
5280
|
+
--image-name cyberia-client-dev:v3.3.73 \
|
|
5069
5281
|
--image-out-path .
|
|
5070
5282
|
`);
|
|
5071
5283
|
break;
|
|
5072
5284
|
}
|
|
5073
5285
|
});
|
|
5074
5286
|
|
|
5075
|
-
for (const [cmd, action] of Object.entries(
|
|
5287
|
+
for (const [cmd, action] of Object.entries(cyberiaCatalog.packageScripts))
|
|
5076
5288
|
runner.command(cmd).action(() => {
|
|
5077
5289
|
if (cmd === 'docker:up' || cmd === 'docker:up:build' || cmd === 'docker:restart') {
|
|
5078
5290
|
const { aliases, changed } = installCyberiaDockerHostAliases();
|
|
@@ -5626,6 +5838,23 @@ node bin image --path cyberia-client \
|
|
|
5626
5838
|
|
|
5627
5839
|
// Copy canonical doc sources into the generated project READMEs.
|
|
5628
5840
|
// Edit the canonical sources; never hand-edit these generated outputs.
|
|
5841
|
+
// The mirrored deploy tree is a generated artifact, rebuilt from scratch so a file
|
|
5842
|
+
// dropped or renamed upstream cannot linger in the published repo. It reproduces the
|
|
5843
|
+
// engine layout exactly — the <deploy-id> directory beside lib/ — because every deploy
|
|
5844
|
+
// script sources `$SCRIPT_DIR/../lib/logging.sh`, which only resolves when lib/ is the
|
|
5845
|
+
// script directory's sibling there too.
|
|
5846
|
+
for (const project of ['cyberia-client', 'cyberia-server']) {
|
|
5847
|
+
const scripts = `./deploy/${project}`;
|
|
5848
|
+
// A tree assembled before these scripts were packaged does not carry them; mirroring is
|
|
5849
|
+
// what publishes them, so say so and continue rather than failing the whole manifest build.
|
|
5850
|
+
if (!fs.existsSync(scripts)) {
|
|
5851
|
+
logger.warn(`[build-manifest] No deploy scripts to mirror for ${project}`, { path: scripts });
|
|
5852
|
+
continue;
|
|
5853
|
+
}
|
|
5854
|
+
fs.removeSync(`./${project}/deploy`);
|
|
5855
|
+
fs.copySync('./deploy/lib', `./${project}/deploy/lib`);
|
|
5856
|
+
fs.copySync(scripts, `./${project}/deploy/${project}`);
|
|
5857
|
+
}
|
|
5629
5858
|
fs.copyFileSync('./src/client/public/cyberia-docs/CYBERIA-CLIENT.md', './cyberia-client/README.md');
|
|
5630
5859
|
fs.copyFileSync('./src/client/public/cyberia-docs/CYBERIA-SERVER.md', './cyberia-server/README.md');
|
|
5631
5860
|
fs.copyFileSync(
|
|
@@ -5637,7 +5866,15 @@ node bin image --path cyberia-client \
|
|
|
5637
5866
|
'./cyberia-server/.github/workflows/cyberia-server.cd.yml',
|
|
5638
5867
|
);
|
|
5639
5868
|
shellExec('cp -a ./engine-private/conf/dd-cyberia/docker-compose/cyberia/. ./src/runtime/engine-cyberia/');
|
|
5640
|
-
|
|
5869
|
+
// The publish is scoped to the deployment this workflow builds — every other step here is —
|
|
5870
|
+
// so it reads dd-cyberia's own environment instead of the working-tree `./.env`, which names
|
|
5871
|
+
// whichever deployment `app load` ran for last.
|
|
5872
|
+
shellExec(
|
|
5873
|
+
`node bin/cyberia.js instance --publish-build --env-path ${deployEnvFilePath(
|
|
5874
|
+
'dd-cyberia',
|
|
5875
|
+
isDev ? 'development' : 'production',
|
|
5876
|
+
)}`,
|
|
5877
|
+
);
|
|
5641
5878
|
logger.info(`run-workflow build-manifest complete (${isDev ? 'dev' : 'prod'})`);
|
|
5642
5879
|
});
|
|
5643
5880
|
|
|
@@ -5767,7 +6004,7 @@ node bin image --path cyberia-client \
|
|
|
5767
6004
|
// line.
|
|
5768
6005
|
if (error && error.message === 'Trigger underpost passthrough') {
|
|
5769
6006
|
process.argv = process.argv.filter((c) => c !== 'underpost');
|
|
5770
|
-
logger.
|
|
6007
|
+
if (!process.argv.includes('--plain')) logger.info('Rerouting to underpost cli...');
|
|
5771
6008
|
try {
|
|
5772
6009
|
await underpostProgram.parseAsync();
|
|
5773
6010
|
} catch (err) {
|