@underpostnet/cyberia 3.2.80
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 +14 -0
- package/.env.example +144 -0
- package/.github/workflows/cyberia-client.cd.yml +40 -0
- package/.github/workflows/cyberia-server.cd.yml +40 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +71 -0
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +70 -0
- package/.github/workflows/docker-image.cyberia-server.ci.yml +71 -0
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +71 -0
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +53 -0
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +53 -0
- package/.github/workflows/engine-cyberia.cd.yml +157 -0
- package/.github/workflows/engine-cyberia.ci.yml +125 -0
- package/.github/workflows/ghpkg.ci.yml +160 -0
- package/.github/workflows/gitlab.ci.yml +20 -0
- package/.github/workflows/hardhat.ci.yml +82 -0
- package/.github/workflows/npmpkg.ci.yml +126 -0
- package/.github/workflows/publish.ci.yml +87 -0
- package/.github/workflows/publish.cyberia.ci.yml +79 -0
- package/.github/workflows/pwa-microservices-template-page.cd.yml +65 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +33 -0
- package/.github/workflows/release.cd.yml +46 -0
- package/.nycrc +9 -0
- package/.prettierignore +12 -0
- package/.prettierrc +9 -0
- package/.vscode/extensions.json +10 -0
- package/.vscode/settings.json +26 -0
- package/CHANGELOG.md +2516 -0
- package/CLI-HELP.md +1099 -0
- package/Dockerfile +161 -0
- package/Dockerfile.dev +161 -0
- package/Dockerfile.test +165 -0
- package/LICENSE +21 -0
- package/README.md +259 -0
- package/baremetal/commission-workflows.json +211 -0
- package/baremetal/packer-workflows.json +24 -0
- package/bin/build.js +261 -0
- package/bin/build.template.js +33 -0
- package/bin/cyberia.js +5627 -0
- package/bin/deploy.js +1547 -0
- package/bin/index.js +5627 -0
- package/bump.config.js +27 -0
- package/compose.env +144 -0
- package/conf.js +952 -0
- package/deployment.yaml +418 -0
- package/docker-compose.yml +434 -0
- package/examples/static-page/README.md +150 -0
- package/examples/static-page/ssr-components/CustomPage.js +554 -0
- package/examples/static-page/static-config-example.json +57 -0
- package/hardhat/.env.example +31 -0
- package/hardhat/contracts/ObjectLayerToken.sol +391 -0
- package/hardhat/deployments/.gitkeep +0 -0
- package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
- package/hardhat/hardhat.config.js +136 -0
- package/hardhat/ignition/modules/.gitkeep +0 -0
- package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
- package/hardhat/networks/besu-object-layer.network.json +138 -0
- package/hardhat/package-lock.json +2871 -0
- package/hardhat/package.json +43 -0
- package/hardhat/scripts/deployObjectLayerToken.js +98 -0
- package/hardhat/test/ObjectLayerToken.js +696 -0
- package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
- package/hardhat/types/ethers-contracts/common.ts +92 -0
- package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
- package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
- package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
- package/hardhat/types/ethers-contracts/index.ts +6 -0
- package/ipfs/configure-ipfs.sh +13 -0
- package/jsconfig.json +9 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +48 -0
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +48 -0
- package/manifests/deployment/adminer/deployment.yaml +32 -0
- package/manifests/deployment/adminer/kustomization.yaml +7 -0
- package/manifests/deployment/adminer/service.yaml +13 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +418 -0
- package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +189 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +164 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +163 -0
- package/manifests/deployment/dd-default-development/proxy.yaml +46 -0
- package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
- package/manifests/deployment/fastapi/backend-service.yml +19 -0
- package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
- package/manifests/deployment/fastapi/frontend-service.yml +15 -0
- package/manifests/deployment/fastapi/initial_data.sh +8 -0
- package/manifests/deployment/kafka/deployment.yaml +67 -0
- package/manifests/deployment/mongo-express/deployment.yaml +62 -0
- package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
- package/manifests/deployment/playwright/deployment.yaml +52 -0
- package/manifests/deployment/spark/spark-pi-py.yaml +20 -0
- package/manifests/deployment/tensorflow/tf-gpu-test.yaml +63 -0
- package/manifests/envoy-service-nodeport.yaml +22 -0
- package/manifests/grafana/deployment.yaml +64 -0
- package/manifests/grafana/kustomization.yaml +7 -0
- package/manifests/grafana/pvc.yaml +12 -0
- package/manifests/grafana/service.yaml +14 -0
- package/manifests/grafana/storage-class.yaml +9 -0
- package/manifests/ipfs/configmap.yaml +64 -0
- package/manifests/ipfs/headless-service.yaml +35 -0
- package/manifests/ipfs/kustomization.yaml +8 -0
- package/manifests/ipfs/statefulset.yaml +149 -0
- package/manifests/ipfs/storage-class.yaml +9 -0
- package/manifests/kind-config-dev.yaml +20 -0
- package/manifests/kind-config.yaml +12 -0
- package/manifests/kubeadm-calico-config.yaml +14 -0
- package/manifests/letsencrypt-prod.yaml +14 -0
- package/manifests/lxd/lxd-admin-profile.yaml +26 -0
- package/manifests/lxd/lxd-preseed.yaml +30 -0
- package/manifests/mariadb/kustomization.yaml +9 -0
- package/manifests/mariadb/pv.yaml +12 -0
- package/manifests/mariadb/pvc.yaml +10 -0
- package/manifests/mariadb/service.yaml +10 -0
- package/manifests/mariadb/statefulset.yaml +56 -0
- package/manifests/mariadb/storage-class.yaml +10 -0
- package/manifests/mongodb/headless-service.yaml +10 -0
- package/manifests/mongodb/kustomization.yaml +11 -0
- package/manifests/mongodb/pv-pvc.yaml +59 -0
- package/manifests/mongodb/statefulset.yaml +113 -0
- package/manifests/mongodb/storage-class.yaml +9 -0
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +9 -0
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +19 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +61 -0
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/mysql/kustomization.yaml +7 -0
- package/manifests/mysql/pv-pvc.yaml +27 -0
- package/manifests/mysql/statefulset.yaml +55 -0
- package/manifests/postgresql/configmap.yaml +9 -0
- package/manifests/postgresql/kustomization.yaml +10 -0
- package/manifests/postgresql/pv.yaml +15 -0
- package/manifests/postgresql/pvc.yaml +13 -0
- package/manifests/postgresql/service.yaml +10 -0
- package/manifests/postgresql/statefulset.yaml +37 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/manifests/pv-pvc-dd.yaml +34 -0
- package/manifests/valkey/kustomization.yaml +7 -0
- package/manifests/valkey/service.yaml +10 -0
- package/manifests/valkey/statefulset.yaml +37 -0
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/mongodb/entrypoint.sh +76 -0
- package/nginx.conf +128 -0
- package/nodemon.json +6 -0
- package/package.json +101 -0
- package/packer/images/Rocky9Amd64/Makefile +62 -0
- package/packer/images/Rocky9Amd64/QUICKSTART.md +113 -0
- package/packer/images/Rocky9Amd64/README.md +122 -0
- package/packer/images/Rocky9Amd64/http/rocky9.ks.pkrtpl.hcl +114 -0
- package/packer/images/Rocky9Amd64/rocky9.pkr.hcl +164 -0
- package/packer/images/Rocky9Arm64/Makefile +69 -0
- package/packer/images/Rocky9Arm64/README.md +122 -0
- package/packer/images/Rocky9Arm64/http/rocky9.ks.pkrtpl.hcl +114 -0
- package/packer/images/Rocky9Arm64/rocky9.pkr.hcl +171 -0
- package/packer/scripts/fuse-nbd +64 -0
- package/packer/scripts/fuse-tar-root +63 -0
- package/proxy.yaml +189 -0
- package/pv-pvc.yaml +164 -0
- package/scripts/device-scan.sh +65 -0
- package/scripts/disk-clean.sh +182 -0
- package/scripts/disk-devices.sh +13 -0
- package/scripts/gen-fqdns.sh +14 -0
- package/scripts/gpu-diag.sh +19 -0
- package/scripts/ip-info.sh +118 -0
- package/scripts/ipxe-setup.sh +200 -0
- package/scripts/k3s-node-setup.sh +124 -0
- package/scripts/kubeadm-node-setup.sh +317 -0
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/lxd-vm-setup.sh +208 -0
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/scripts/maas-setup.sh +135 -0
- package/scripts/maas-upload-boot-resource.sh +183 -0
- package/scripts/nat-iptables.sh +111 -0
- package/scripts/nvim.sh +91 -0
- package/scripts/packer-init-vars-file.sh +40 -0
- package/scripts/packer-setup.sh +289 -0
- package/scripts/ports-ls.sh +33 -0
- package/scripts/quick-tftp.sh +19 -0
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/scripts/rocky-kickstart.sh +986 -0
- package/scripts/rocky-pwa.sh +200 -0
- package/scripts/rocky-setup.sh +106 -0
- package/scripts/rpmfusion-ffmpeg-setup.sh +32 -0
- package/scripts/ssl.sh +170 -0
- package/scripts/test-monitor.sh +248 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +30 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +155 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +39 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +382 -0
- package/src/api/core/core.controller.js +8 -0
- package/src/api/core/core.model.js +11 -0
- package/src/api/core/core.router.js +23 -0
- package/src/api/core/core.service.js +30 -0
- package/src/api/crypto/crypto.controller.js +10 -0
- package/src/api/crypto/crypto.model.js +23 -0
- package/src/api/crypto/crypto.router.js +23 -0
- package/src/api/crypto/crypto.service.js +64 -0
- package/src/api/cyberia-action/cyberia-action.controller.js +8 -0
- package/src/api/cyberia-action/cyberia-action.model.js +79 -0
- package/src/api/cyberia-action/cyberia-action.router.js +21 -0
- package/src/api/cyberia-action/cyberia-action.service.js +58 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +27 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +100 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +70 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +8 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +20 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +57 -0
- package/src/api/cyberia-entity/cyberia-entity.controller.js +6 -0
- package/src/api/cyberia-entity/cyberia-entity.model.js +25 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +17 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +6 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +337 -0
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +57 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +583 -0
- package/src/api/cyberia-instance/cyberia-instance.controller.js +42 -0
- package/src/api/cyberia-instance/cyberia-instance.model.js +117 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +75 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +190 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
- package/src/api/cyberia-instance/cyberia-world-generator.js +618 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +6 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +200 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +17 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
- package/src/api/cyberia-map/cyberia-map.controller.js +6 -0
- package/src/api/cyberia-map/cyberia-map.model.js +33 -0
- package/src/api/cyberia-map/cyberia-map.router.js +19 -0
- package/src/api/cyberia-map/cyberia-map.service.js +76 -0
- package/src/api/cyberia-quest/cyberia-quest.controller.js +9 -0
- package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +26 -0
- package/src/api/cyberia-quest/cyberia-quest.service.js +97 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +6 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +21 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
- package/src/api/cyberia-saga/cyberia-saga.controller.js +6 -0
- package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
- package/src/api/cyberia-saga/cyberia-saga.router.js +17 -0
- package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +1076 -0
- package/src/api/cyberia-skill/cyberia-skill.controller.js +6 -0
- package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
- package/src/api/cyberia-skill/cyberia-skill.router.js +17 -0
- package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
- package/src/api/default/default.controller.js +6 -0
- package/src/api/default/default.model.js +20 -0
- package/src/api/default/default.router.js +21 -0
- package/src/api/default/default.service.js +42 -0
- package/src/api/document/document.controller.js +9 -0
- package/src/api/document/document.model.js +95 -0
- package/src/api/document/document.router.js +32 -0
- package/src/api/document/document.service.js +633 -0
- package/src/api/file/file.controller.js +15 -0
- package/src/api/file/file.model.js +127 -0
- package/src/api/file/file.ref.json +39 -0
- package/src/api/file/file.router.js +36 -0
- package/src/api/file/file.service.js +499 -0
- package/src/api/instance/instance.controller.js +8 -0
- package/src/api/instance/instance.model.js +34 -0
- package/src/api/instance/instance.router.js +27 -0
- package/src/api/instance/instance.service.js +75 -0
- package/src/api/ipfs/ipfs.controller.js +8 -0
- package/src/api/ipfs/ipfs.model.js +77 -0
- package/src/api/ipfs/ipfs.router.js +26 -0
- package/src/api/ipfs/ipfs.service.js +145 -0
- package/src/api/object-layer/object-layer.controller.js +18 -0
- package/src/api/object-layer/object-layer.model.js +200 -0
- package/src/api/object-layer/object-layer.router.js +729 -0
- package/src/api/object-layer/object-layer.service.js +894 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +6 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +93 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +17 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +46 -0
- package/src/api/test/test.controller.js +14 -0
- package/src/api/test/test.model.js +14 -0
- package/src/api/test/test.router.js +23 -0
- package/src/api/test/test.service.js +35 -0
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +100 -0
- package/src/api/user/postman_collection.json +216 -0
- package/src/api/user/user.build.js +16 -0
- package/src/api/user/user.controller.js +35 -0
- package/src/api/user/user.model.js +142 -0
- package/src/api/user/user.router.js +367 -0
- package/src/api/user/user.service.js +582 -0
- package/src/api.js +23 -0
- package/src/cli/baremetal.js +3947 -0
- package/src/cli/cloud-init.js +673 -0
- package/src/cli/cluster.js +1395 -0
- package/src/cli/db.js +1533 -0
- package/src/cli/deploy.js +1542 -0
- package/src/cli/docker-compose.js +802 -0
- package/src/cli/env.js +177 -0
- package/src/cli/fs.js +380 -0
- package/src/cli/image.js +389 -0
- package/src/cli/index.js +1059 -0
- package/src/cli/ipfs.js +182 -0
- package/src/cli/kickstart.js +271 -0
- package/src/cli/kubectl.js +214 -0
- package/src/cli/lxd.js +1232 -0
- package/src/cli/monitor.js +659 -0
- package/src/cli/release.js +595 -0
- package/src/cli/repository.js +1969 -0
- package/src/cli/run.js +3326 -0
- package/src/cli/secrets.js +151 -0
- package/src/cli/ssh.js +975 -0
- package/src/cli/static.js +653 -0
- package/src/cli/system.js +332 -0
- package/src/cli/test.js +176 -0
- package/src/client/Cryptokoyn.index.js +30 -0
- package/src/client/CyberiaPortal.index.js +31 -0
- package/src/client/Default.index.js +77 -0
- package/src/client/Itemledger.index.js +35 -0
- package/src/client/Underpost.index.js +31 -0
- package/src/client/components/core/404.js +20 -0
- package/src/client/components/core/500.js +20 -0
- package/src/client/components/core/Account.js +630 -0
- package/src/client/components/core/AgGrid.js +238 -0
- package/src/client/components/core/Alert.js +76 -0
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/Auth.js +353 -0
- package/src/client/components/core/Badge.js +26 -0
- package/src/client/components/core/Blockchain.js +41 -0
- package/src/client/components/core/Blog.js +9 -0
- package/src/client/components/core/BtnIcon.js +109 -0
- package/src/client/components/core/CalendarCore.js +437 -0
- package/src/client/components/core/Chat.js +62 -0
- package/src/client/components/core/ClientEvents.js +163 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/CommonJs.js +1014 -0
- package/src/client/components/core/Content.js +349 -0
- package/src/client/components/core/Css.js +1134 -0
- package/src/client/components/core/CssCore.js +881 -0
- package/src/client/components/core/D3Chart.js +44 -0
- package/src/client/components/core/Docs.js +478 -0
- package/src/client/components/core/DropDown.js +321 -0
- package/src/client/components/core/EventBus.js +96 -0
- package/src/client/components/core/EventsUI.js +130 -0
- package/src/client/components/core/FileExplorer.js +1406 -0
- package/src/client/components/core/FullScreen.js +201 -0
- package/src/client/components/core/Input.js +537 -0
- package/src/client/components/core/Keyboard.js +80 -0
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +152 -0
- package/src/client/components/core/LogIn.js +212 -0
- package/src/client/components/core/LogOut.js +72 -0
- package/src/client/components/core/Logger.js +22 -0
- package/src/client/components/core/Modal.js +2956 -0
- package/src/client/components/core/NotificationManager.js +80 -0
- package/src/client/components/core/Pagination.js +252 -0
- package/src/client/components/core/Panel.js +1308 -0
- package/src/client/components/core/PanelForm.js +915 -0
- package/src/client/components/core/Polyhedron.js +947 -0
- package/src/client/components/core/PublicProfile.js +895 -0
- package/src/client/components/core/Recover.js +211 -0
- package/src/client/components/core/Responsive.js +146 -0
- package/src/client/components/core/RichText.js +33 -0
- package/src/client/components/core/Router.js +523 -0
- package/src/client/components/core/Scroll.js +76 -0
- package/src/client/components/core/SearchBox.js +1007 -0
- package/src/client/components/core/SignUp.js +153 -0
- package/src/client/components/core/SocketIo.js +163 -0
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +161 -0
- package/src/client/components/core/ToggleSwitch.js +89 -0
- package/src/client/components/core/ToolTip.js +78 -0
- package/src/client/components/core/Translate.js +694 -0
- package/src/client/components/core/Validator.js +140 -0
- package/src/client/components/core/VanillaJs.js +485 -0
- package/src/client/components/core/Wallet.js +95 -0
- package/src/client/components/core/WebComponent.js +44 -0
- package/src/client/components/core/Webhook.js +58 -0
- package/src/client/components/core/Worker.js +313 -0
- package/src/client/components/core/windowGetDimensions.js +269 -0
- package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +352 -0
- package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
- package/src/client/components/cryptokoyn/CssCryptokoyn.js +212 -0
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +16 -0
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +12 -0
- package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +16 -0
- package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +11 -0
- package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +6 -0
- package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
- package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
- package/src/client/components/cyberia/InstanceEngineCyberia.js +1088 -0
- package/src/client/components/cyberia/InstanceSelectionView.js +900 -0
- package/src/client/components/cyberia/MapEngineCyberia.js +1976 -0
- package/src/client/components/cyberia/ObjectLayerEngine.js +1540 -0
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +2420 -0
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +1522 -0
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +528 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +772 -0
- package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +254 -0
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +21 -0
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +16 -0
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +518 -0
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +72 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +16 -0
- package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +13 -0
- package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +6 -0
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +48 -0
- package/src/client/components/default/AppShellDefault.js +765 -0
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/CommonDefault.js +29 -0
- package/src/client/components/default/CssDefault.js +27 -0
- package/src/client/components/default/LogInDefault.js +16 -0
- package/src/client/components/default/LogOutDefault.js +12 -0
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +16 -0
- package/src/client/components/default/SignUpDefault.js +11 -0
- package/src/client/components/default/SocketIoDefault.js +6 -0
- package/src/client/components/default/TranslateDefault.js +7 -0
- package/src/client/components/itemledger/AppShellItemledger.js +353 -0
- package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
- package/src/client/components/itemledger/CssItemledger.js +212 -0
- package/src/client/components/itemledger/LogInItemledger.js +17 -0
- package/src/client/components/itemledger/LogOutItemledger.js +12 -0
- package/src/client/components/itemledger/RouterItemledger.js +38 -0
- package/src/client/components/itemledger/SettingsItemledger.js +16 -0
- package/src/client/components/itemledger/SignUpItemledger.js +11 -0
- package/src/client/components/itemledger/SocketIoItemledger.js +6 -0
- package/src/client/components/itemledger/TranslateItemledger.js +7 -0
- package/src/client/components/underpost/AppShellUnderpost.js +691 -0
- package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
- package/src/client/components/underpost/CssUnderpost.js +281 -0
- package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +879 -0
- package/src/client/components/underpost/DocumentSearchProvider.js +448 -0
- package/src/client/components/underpost/LabGalleryUnderpost.js +79 -0
- package/src/client/components/underpost/LogInUnderpost.js +25 -0
- package/src/client/components/underpost/LogOutUnderpost.js +17 -0
- package/src/client/components/underpost/RouterUnderpost.js +45 -0
- package/src/client/components/underpost/SettingsUnderpost.js +16 -0
- package/src/client/components/underpost/SignUpUnderpost.js +11 -0
- package/src/client/components/underpost/SocketIoUnderpost.js +6 -0
- package/src/client/components/underpost/TranslateUnderpost.js +10 -0
- package/src/client/public/cryptokoyn/assets/banner/koyn-social.png +0 -0
- package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
- package/src/client/public/cryptokoyn/assets/logo/cryptokoyn.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-144x144.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-192x192.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-256x256.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-36x36.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-48x48.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-72x72.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-96x96.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-114x114-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-120x120-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-144x144-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-152x152-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-180x180-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-57x57-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-60x60-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-72x72-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-76x76-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/favicon-16x16.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/favicon-32x32.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-144x144.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-150x150.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-310x150.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-310x310.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-70x70.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/safari-pinned-tab.svg +42 -0
- package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
- package/src/client/public/cryptokoyn/favicon.ico +0 -0
- package/src/client/public/cryptokoyn/microdata.json +85 -0
- package/src/client/public/cryptokoyn/site.webmanifest +57 -0
- package/src/client/public/cryptokoyn/sitemap +148 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +307 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +309 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +204 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +341 -0
- package/src/client/public/cyberia-docs/CYBERIA-LORE.md +84 -0
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +294 -0
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +242 -0
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +309 -0
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +228 -0
- package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
- package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +740 -0
- 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-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152-precomposed.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-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76-precomposed.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/dark.jpg +0 -0
- package/src/client/public/default/assets/background/dark.svg +557 -0
- package/src/client/public/default/assets/background/white.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/default/assets/logo/base-icon.png +0 -0
- package/src/client/public/default/assets/logo/underpost.gif +0 -0
- package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
- package/src/client/public/default/browserconfig.xml +12 -0
- 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 +69 -0
- 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/safari-pinned-tab.svg +24 -0
- package/src/client/public/default/site.webmanifest +69 -0
- package/src/client/public/default/sitemap +148 -0
- package/src/client/public/default/yandex-browser-50x50.png +0 -0
- package/src/client/public/default/yandex-browser-manifest.json +9 -0
- package/src/client/public/doc/favicon.ico +0 -0
- package/src/client/public/doc/sitemap +148 -0
- package/src/client/public/itemledger/android-chrome-144x144.png +0 -0
- package/src/client/public/itemledger/android-chrome-192x192.png +0 -0
- package/src/client/public/itemledger/android-chrome-256x256.png +0 -0
- package/src/client/public/itemledger/android-chrome-36x36.png +0 -0
- package/src/client/public/itemledger/android-chrome-384x384.png +0 -0
- package/src/client/public/itemledger/android-chrome-48x48.png +0 -0
- package/src/client/public/itemledger/android-chrome-512x512.png +0 -0
- package/src/client/public/itemledger/android-chrome-72x72.png +0 -0
- package/src/client/public/itemledger/android-chrome-96x96.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/itemledger/assets/logo/base-icon.png +0 -0
- package/src/client/public/itemledger/browserconfig.xml +12 -0
- package/src/client/public/itemledger/favicon-16x16.png +0 -0
- package/src/client/public/itemledger/favicon-32x32.png +0 -0
- package/src/client/public/itemledger/favicon-48x48.png +0 -0
- package/src/client/public/itemledger/favicon.ico +0 -0
- package/src/client/public/itemledger/manifest.webmanifest +69 -0
- package/src/client/public/itemledger/microdata.json +71 -0
- package/src/client/public/itemledger/mstile-144x144.png +0 -0
- package/src/client/public/itemledger/mstile-150x150.png +0 -0
- package/src/client/public/itemledger/mstile-310x150.png +0 -0
- package/src/client/public/itemledger/mstile-310x310.png +0 -0
- package/src/client/public/itemledger/mstile-70x70.png +0 -0
- package/src/client/public/itemledger/sitemap +148 -0
- package/src/client/public/itemledger/yandex-browser-50x50.png +0 -0
- package/src/client/public/itemledger/yandex-browser-manifest.json +9 -0
- package/src/client/public/test/favicon.ico +0 -0
- package/src/client/public/test/sitemap +148 -0
- package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +137 -0
- package/src/client/services/core/core.service.js +309 -0
- package/src/client/services/crypto/crypto.service.js +68 -0
- package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
- package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
- package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +99 -0
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +137 -0
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +99 -0
- package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
- package/src/client/services/cyberia-map/cyberia-map.service.js +120 -0
- package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
- package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
- package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
- package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
- package/src/client/services/default/default.management.js +1015 -0
- package/src/client/services/default/default.service.js +99 -0
- package/src/client/services/document/document.service.js +134 -0
- package/src/client/services/file/file.service.js +94 -0
- package/src/client/services/instance/instance.management.js +78 -0
- package/src/client/services/instance/instance.service.js +107 -0
- package/src/client/services/ipfs/ipfs.service.js +118 -0
- package/src/client/services/object-layer/object-layer.management.js +414 -0
- package/src/client/services/object-layer/object-layer.service.js +208 -0
- package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +99 -0
- package/src/client/services/test/test.service.js +68 -0
- package/src/client/services/user/guest.service.js +86 -0
- package/src/client/services/user/user.management.js +51 -0
- package/src/client/services/user/user.service.js +106 -0
- package/src/client/ssr/RootDocument.js +237 -0
- package/src/client/ssr/body/404.js +77 -0
- package/src/client/ssr/body/500.js +76 -0
- package/src/client/ssr/body/CacheControl.js +117 -0
- package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +97 -0
- package/src/client/ssr/body/DefaultSplashScreen.js +97 -0
- package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +90 -0
- package/src/client/ssr/head/CryptokoynScripts.js +4 -0
- package/src/client/ssr/head/Css.js +241 -0
- package/src/client/ssr/head/CyberiaPortalScripts.js +6 -0
- package/src/client/ssr/head/DefaultScripts.js +6 -0
- package/src/client/ssr/head/ItemledgerScripts.js +4 -0
- package/src/client/ssr/head/Microdata.js +11 -0
- package/src/client/ssr/head/Production.js +1 -0
- package/src/client/ssr/head/Pwa.js +146 -0
- package/src/client/ssr/head/PwaItemledger.js +197 -0
- package/src/client/ssr/head/Seo.js +15 -0
- package/src/client/ssr/head/UnderpostScripts.js +6 -0
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +20 -0
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +16 -0
- package/src/client/ssr/views/Cyberia404.js +328 -0
- package/src/client/ssr/views/CyberiaServerMetrics.js +1070 -0
- package/src/client/ssr/views/Maintenance.js +64 -0
- package/src/client/ssr/views/NoNetworkConnection.js +68 -0
- package/src/client/ssr/views/Test.js +199 -0
- package/src/client/sw/core.sw.js +274 -0
- package/src/client-builder/client-build-docs.js +493 -0
- package/src/client-builder/client-build-live.js +100 -0
- package/src/client-builder/client-build.js +1092 -0
- package/src/client-builder/client-dev-server.js +88 -0
- package/src/client-builder/client-formatted.js +170 -0
- package/src/client-builder/client-icons.js +108 -0
- package/src/client-builder/ssr.js +124 -0
- package/src/client.build.js +17 -0
- package/src/client.dev.js +21 -0
- package/src/db/DataBaseProvider.js +213 -0
- package/src/db/mariadb/MariaDB.js +72 -0
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +199 -0
- package/src/grpc/cyberia/grpc-server.js +162 -0
- package/src/index.js +357 -0
- package/src/mailer/EmailRender.js +116 -0
- package/src/mailer/MailerProvider.js +213 -0
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +413 -0
- package/src/projects/cyberia/besu-genesis-generator.js +1630 -0
- package/src/projects/cyberia/catalog-cyberia.js +90 -0
- package/src/projects/cyberia/gemini-client.js +175 -0
- package/src/projects/cyberia/generate-saga.js +2137 -0
- package/src/projects/cyberia/hot-reload-trigger.js +163 -0
- package/src/projects/cyberia/instance-data.js +719 -0
- package/src/projects/cyberia/ipfs-client.js +599 -0
- package/src/projects/cyberia/map-preview-generator.js +304 -0
- package/src/projects/cyberia/object-layer.js +978 -0
- package/src/projects/cyberia/semantic-layer-generator-floor.js +319 -0
- package/src/projects/cyberia/semantic-layer-generator-resource.js +259 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +1164 -0
- package/src/projects/cyberia/semantic-layer-generator.js +753 -0
- package/src/projects/cyberia/shape-generator.js +1060 -0
- package/src/projects/underpost/catalog-underpost.js +60 -0
- package/src/proxy.js +19 -0
- package/src/runtime/cyberia-client/Dockerfile +49 -0
- package/src/runtime/cyberia-client/Dockerfile.dev +75 -0
- package/src/runtime/cyberia-server/Dockerfile +43 -0
- package/src/runtime/cyberia-server/Dockerfile.dev +56 -0
- package/src/runtime/engine-cyberia/Dockerfile +161 -0
- package/src/runtime/engine-cyberia/Dockerfile.dev +161 -0
- package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
- package/src/runtime/engine-cyberia/compose.env +144 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +434 -0
- package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
- package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
- package/src/runtime/engine-cyberia/nginx.conf +128 -0
- package/src/runtime/express/Dockerfile +45 -0
- package/src/runtime/express/Express.js +285 -0
- package/src/runtime/lampp/Dockerfile +62 -0
- package/src/runtime/lampp/Lampp.js +359 -0
- package/src/runtime/nginx/Nginx.js +250 -0
- package/src/runtime/wp/Dockerfile +62 -0
- package/src/runtime/wp/Wp.js +642 -0
- package/src/server/auth.js +713 -0
- package/src/server/backup.js +102 -0
- package/src/server/catalog.js +72 -0
- package/src/server/conf.js +2316 -0
- package/src/server/cron.js +476 -0
- package/src/server/crypto.js +210 -0
- package/src/server/data-query.js +461 -0
- package/src/server/dns.js +553 -0
- package/src/server/downloader.js +73 -0
- package/src/server/logger.js +229 -0
- package/src/server/middlewares.js +152 -0
- package/src/server/peer.js +75 -0
- package/src/server/process.js +299 -0
- package/src/server/proxy.js +139 -0
- package/src/server/runtime-status.js +252 -0
- package/src/server/runtime.js +183 -0
- package/src/server/start.js +272 -0
- package/src/server/tls.js +254 -0
- package/src/server/valkey.js +201 -0
- package/src/server.js +25 -0
- package/src/ws/IoInterface.js +129 -0
- package/src/ws/IoServer.js +68 -0
- package/src/ws/core/channels/core.ws.chat.js +68 -0
- package/src/ws/core/channels/core.ws.mailer.js +116 -0
- package/src/ws/core/channels/core.ws.stream.js +90 -0
- package/src/ws/core/core.ws.connection.js +41 -0
- package/src/ws/core/core.ws.emit.js +37 -0
- package/src/ws/core/core.ws.server.js +44 -0
- package/src/ws/default/channels/default.ws.main.js +57 -0
- package/src/ws/default/default.ws.connection.js +35 -0
- package/src/ws/default/default.ws.emit.js +14 -0
- package/src/ws/default/default.ws.server.js +39 -0
- package/test/api.test.js +53 -0
- package/test/crypto.test.js +117 -0
- package/test/cyberia-instance-conf-defaults.test.js +140 -0
- package/test/deploy-monitor.test.js +267 -0
- package/test/shape-generator.test.js +463 -0
- package/tsconfig.docs.json +15 -0
- package/typedoc.dd-cyberia.json +31 -0
- package/typedoc.json +31 -0
|
@@ -0,0 +1,2316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides utilities for building, loading, and managing server configurations,
|
|
3
|
+
* deployment contexts, and service configurations (API, Client, WS).
|
|
4
|
+
* @module src/server/conf.js
|
|
5
|
+
* @namespace ServerConfBuilder
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs-extra';
|
|
9
|
+
import dotenv from 'dotenv';
|
|
10
|
+
import {
|
|
11
|
+
capFirst,
|
|
12
|
+
getCapVariableName,
|
|
13
|
+
getDirname,
|
|
14
|
+
newInstance,
|
|
15
|
+
orderAbc,
|
|
16
|
+
orderArrayFromAttrInt,
|
|
17
|
+
range,
|
|
18
|
+
timer,
|
|
19
|
+
} from '../client/components/core/CommonJs.js';
|
|
20
|
+
import * as dir from 'path';
|
|
21
|
+
import colors from 'colors';
|
|
22
|
+
import { loggerFactory } from './logger.js';
|
|
23
|
+
import { shellExec } from './process.js';
|
|
24
|
+
import { DefaultConf } from '../../conf.js';
|
|
25
|
+
import splitFile from 'split-file';
|
|
26
|
+
import Underpost from '../index.js';
|
|
27
|
+
|
|
28
|
+
colors.enable();
|
|
29
|
+
|
|
30
|
+
const logger = loggerFactory(import.meta);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Prefix used in JSON configuration files to denote an environment variable reference.
|
|
34
|
+
* Any string value in a config object that starts with this prefix will be resolved
|
|
35
|
+
* to the corresponding `process.env` value at runtime.
|
|
36
|
+
*
|
|
37
|
+
* @constant {string}
|
|
38
|
+
* @memberof ServerConfBuilder
|
|
39
|
+
* @example
|
|
40
|
+
* // In conf.server.json:
|
|
41
|
+
* { "db": { "password": "env:MARIADB_PASSWORD" } }
|
|
42
|
+
*/
|
|
43
|
+
const ENV_REF_PREFIX = 'env:';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a standardized context key from host/path descriptors.
|
|
47
|
+
* The key is used across DB, WS, mailer, and cache registries.
|
|
48
|
+
*
|
|
49
|
+
* @method resolveHostKeyContext
|
|
50
|
+
* @param {{host?: string, path?: string}|string} [context={ host: '', path: '' }] - Context object or prebuilt key.
|
|
51
|
+
* @returns {string} Host key context string.
|
|
52
|
+
* @memberof ServerConfBuilder
|
|
53
|
+
*/
|
|
54
|
+
const resolveHostKeyContext = (context = { host: '', path: '' }) => {
|
|
55
|
+
if (typeof context === 'string') return context;
|
|
56
|
+
return `${context.host || ''}${context.path || ''}`;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Recursively walks a configuration object and replaces every string value that
|
|
61
|
+
* starts with {@link ENV_REF_PREFIX} (`"env:"`) with the corresponding
|
|
62
|
+
* `process.env[VAR_NAME]` value.
|
|
63
|
+
*
|
|
64
|
+
* Non-string values and strings that do not start with the prefix are left untouched.
|
|
65
|
+
*
|
|
66
|
+
* Supports three reference formats:
|
|
67
|
+
* - `"env:VAR_NAME"` — resolves to `process.env.VAR_NAME`, returns `''` if unset.
|
|
68
|
+
* - `"env:VAR_NAME:default_value"` — resolves to `process.env.VAR_NAME`, falls back to `default_value` if unset.
|
|
69
|
+
* - Type-coerced defaults:
|
|
70
|
+
* - `"env:VAR_NAME:int:465"` — resolved value is parsed as integer (`parseInt`), falls back to `465`.
|
|
71
|
+
* - `"env:VAR_NAME:bool:true"` — resolved value is coerced to boolean (`value !== 'false'`), falls back to `true`.
|
|
72
|
+
*
|
|
73
|
+
* @method resolveConfSecrets
|
|
74
|
+
* @param {any} obj - The configuration object (or value) to resolve.
|
|
75
|
+
* @returns {any} A **new** object with all `env:` references replaced by their runtime values.
|
|
76
|
+
* @memberof ServerConfBuilder
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Given process.env.MARIADB_PASSWORD = 'supersecret'
|
|
80
|
+
* resolveConfSecrets({ db: { password: 'env:MARIADB_PASSWORD' } });
|
|
81
|
+
* // => { db: { password: 'supersecret' } }
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // With default value fallback (env var not set)
|
|
85
|
+
* resolveConfSecrets({ db: { provider: 'env:DB_PROVIDER:mongoose' } });
|
|
86
|
+
* // => { db: { provider: 'mongoose' } }
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // With int type coercion
|
|
90
|
+
* resolveConfSecrets({ port: 'env:SMTP_PORT:int:465' });
|
|
91
|
+
* // => { port: 465 }
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // With bool type coercion
|
|
95
|
+
* resolveConfSecrets({ secure: 'env:SMTP_SECURE:bool:true' });
|
|
96
|
+
* // => { secure: true }
|
|
97
|
+
*/
|
|
98
|
+
const resolveConfSecrets = (obj) => {
|
|
99
|
+
if (obj === null || obj === undefined) return obj;
|
|
100
|
+
if (typeof obj === 'string') {
|
|
101
|
+
if (obj.startsWith(ENV_REF_PREFIX)) {
|
|
102
|
+
const ref = obj.slice(ENV_REF_PREFIX.length);
|
|
103
|
+
// Support env:VAR_NAME:default_value syntax (first colon separates key from default)
|
|
104
|
+
const colonIdx = ref.indexOf(':');
|
|
105
|
+
const envKey = colonIdx !== -1 ? ref.slice(0, colonIdx) : ref;
|
|
106
|
+
const defaultValue = colonIdx !== -1 ? ref.slice(colonIdx + 1) : undefined;
|
|
107
|
+
const envValue = process.env[envKey];
|
|
108
|
+
|
|
109
|
+
let resolved;
|
|
110
|
+
if (envValue !== undefined) {
|
|
111
|
+
resolved = envValue;
|
|
112
|
+
} else if (defaultValue !== undefined) {
|
|
113
|
+
resolved = defaultValue;
|
|
114
|
+
} else {
|
|
115
|
+
logger.warn(`resolveConfSecrets: environment variable "${envKey}" is not set (referenced as "${obj}")`);
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Type coercion via prefix in default value: int:N or bool:B
|
|
120
|
+
// Also apply coercion when an env value is present and a typed default is declared
|
|
121
|
+
if (defaultValue !== undefined) {
|
|
122
|
+
if (defaultValue.startsWith('int:')) {
|
|
123
|
+
return parseInt(resolved, 10) || parseInt(defaultValue.slice(4), 10) || 0;
|
|
124
|
+
}
|
|
125
|
+
if (defaultValue.startsWith('bool:')) {
|
|
126
|
+
const boolDefault = defaultValue.slice(5);
|
|
127
|
+
if (envValue !== undefined) return envValue !== 'false';
|
|
128
|
+
return boolDefault !== 'false';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return resolved;
|
|
133
|
+
}
|
|
134
|
+
return obj;
|
|
135
|
+
}
|
|
136
|
+
if (Array.isArray(obj)) return obj.map((item) => resolveConfSecrets(item));
|
|
137
|
+
if (typeof obj === 'object') {
|
|
138
|
+
const resolved = {};
|
|
139
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
140
|
+
resolved[key] = resolveConfSecrets(value);
|
|
141
|
+
}
|
|
142
|
+
return resolved;
|
|
143
|
+
}
|
|
144
|
+
return obj;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Returns the private configuration folder for a given deploy ID.
|
|
149
|
+
* Checks for a replica folder first, then falls back to the standard conf folder.
|
|
150
|
+
*
|
|
151
|
+
* @method getConfFolder
|
|
152
|
+
* @param {string} deployId - The deploy ID.
|
|
153
|
+
* @returns {string} The path to the private configuration folder.
|
|
154
|
+
* @memberof ServerConfBuilder
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* getConfFolder('dd-myapp');
|
|
158
|
+
* // => './engine-private/conf/dd-myapp' (or './engine-private/replica/dd-myapp' if it exists)
|
|
159
|
+
*/
|
|
160
|
+
const getConfFolder = (deployId) => {
|
|
161
|
+
return fs.existsSync(`./engine-private/replica/${deployId}`)
|
|
162
|
+
? `./engine-private/replica/${deployId}`
|
|
163
|
+
: `./engine-private/conf/${deployId}`;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Reads `engine-private/deploy/dd.cron` and returns the deploy-id string,
|
|
168
|
+
* or `null` if the file does not exist or is empty.
|
|
169
|
+
*
|
|
170
|
+
* @method cronDeployIdResolve
|
|
171
|
+
* @returns {string|null} The deploy-id from dd.cron, or null.
|
|
172
|
+
* @memberof ServerConfBuilder
|
|
173
|
+
*/
|
|
174
|
+
const cronDeployIdResolve = () => {
|
|
175
|
+
const cronDeployFile = './engine-private/deploy/dd.cron';
|
|
176
|
+
if (fs.existsSync(cronDeployFile)) {
|
|
177
|
+
const id = fs.readFileSync(cronDeployFile, 'utf8').trim();
|
|
178
|
+
return id || null;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Loads the deployment-specific `.env` file referenced by `engine-private/deploy/dd.cron`
|
|
185
|
+
* into `process.env`. Uses `NODE_ENV` to select the environment variant
|
|
186
|
+
* (defaults to `production`).
|
|
187
|
+
*
|
|
188
|
+
* Safe to call multiple times; subsequent calls are no-ops once the env is loaded.
|
|
189
|
+
*
|
|
190
|
+
* @method loadCronDeployEnv
|
|
191
|
+
* @memberof ServerConfBuilder
|
|
192
|
+
*/
|
|
193
|
+
function loadCronDeployEnv() {
|
|
194
|
+
const envName = process.env.NODE_ENV || 'production';
|
|
195
|
+
|
|
196
|
+
// 1) Load dd.cron env (takes full precedence)
|
|
197
|
+
const cronDeployId = cronDeployIdResolve();
|
|
198
|
+
if (cronDeployId) {
|
|
199
|
+
const cronEnvPath = `./engine-private/conf/${cronDeployId}/.env.${envName}`;
|
|
200
|
+
if (fs.existsSync(cronEnvPath)) {
|
|
201
|
+
const cronEnv = dotenv.parse(fs.readFileSync(cronEnvPath, 'utf8'));
|
|
202
|
+
process.env = { ...process.env, ...cronEnv };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 2) Load dd.router envs — only keys not already present
|
|
207
|
+
const routerDeployFile = './engine-private/deploy/dd.router';
|
|
208
|
+
if (fs.existsSync(routerDeployFile)) {
|
|
209
|
+
const routerIds = fs.readFileSync(routerDeployFile, 'utf8').trim().split(',');
|
|
210
|
+
for (const deployId of routerIds) {
|
|
211
|
+
const id = deployId.trim();
|
|
212
|
+
if (!id) continue;
|
|
213
|
+
const envPath = `./engine-private/conf/${id}/.env.${envName}`;
|
|
214
|
+
if (!fs.existsSync(envPath)) continue;
|
|
215
|
+
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
216
|
+
for (const key of Object.keys(env)) {
|
|
217
|
+
if (!(key in process.env)) process.env[key] = env[key];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolves the full path to a specific configuration JSON file for a deploy ID.
|
|
225
|
+
* For `server` configs in development mode with a subConf, it will prefer the
|
|
226
|
+
* dev-specific variant if it exists.
|
|
227
|
+
*
|
|
228
|
+
* @method getConfFilePath
|
|
229
|
+
* @param {string} deployId - The deploy ID.
|
|
230
|
+
* @param {string} confType - The configuration type (e.g. 'server', 'client', 'cron', 'ssr').
|
|
231
|
+
* @param {string} [subConf=''] - Optional sub-configuration identifier (used for dev server variants).
|
|
232
|
+
* @returns {string} The resolved path to the configuration JSON file.
|
|
233
|
+
* @memberof ServerConfBuilder
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* getConfFilePath('dd-myapp', 'server');
|
|
237
|
+
* // => './engine-private/conf/dd-myapp/conf.server.json'
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* // In development with subConf 'local':
|
|
241
|
+
* getConfFilePath('dd-myapp', 'server', 'local');
|
|
242
|
+
* // => './engine-private/conf/dd-myapp/conf.server.dev.local.json' (if it exists)
|
|
243
|
+
*/
|
|
244
|
+
const getConfFilePath = (deployId, confType, subConf = '') => {
|
|
245
|
+
const folder = getConfFolder(deployId);
|
|
246
|
+
// When no explicit subConf is given, fall back to the env var set by loadConf()
|
|
247
|
+
const effectiveSubConf = subConf || process.env.DEPLOY_SUB_CONF || '';
|
|
248
|
+
if (confType === 'server' && effectiveSubConf) {
|
|
249
|
+
const devConfPath = `${folder}/conf.${confType}.dev.${effectiveSubConf}.json`;
|
|
250
|
+
if (fs.existsSync(devConfPath)) return devConfPath;
|
|
251
|
+
}
|
|
252
|
+
return `${folder}/conf.${confType}.json`;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Reads and parses a configuration JSON file for a given deploy ID and config type.
|
|
257
|
+
* Optionally resolves `env:` secret references and/or applies replica expansion.
|
|
258
|
+
*
|
|
259
|
+
* @method readConfJson
|
|
260
|
+
* @param {string} deployId - The deploy ID.
|
|
261
|
+
* @param {string} confType - The configuration type (e.g. 'server', 'client', 'cron', 'ssr').
|
|
262
|
+
* @param {object} [options={}] - Options.
|
|
263
|
+
* @param {string} [options.subConf=''] - Sub-configuration identifier for dev variants.
|
|
264
|
+
* @param {boolean} [options.resolve=false] - Whether to resolve `env:` references.
|
|
265
|
+
* @param {boolean} [options.loadReplicas=false] - Whether to expand replica entries (server configs).
|
|
266
|
+
* @returns {object} The parsed (and optionally resolved) configuration object.
|
|
267
|
+
* @memberof ServerConfBuilder
|
|
268
|
+
*/
|
|
269
|
+
const readConfJson = (deployId, confType, options = {}) => {
|
|
270
|
+
const filePath = getConfFilePath(deployId, confType, options.subConf || '');
|
|
271
|
+
if (!fs.existsSync(filePath)) {
|
|
272
|
+
throw new Error(`readConfJson: configuration file not found: ${filePath}`);
|
|
273
|
+
}
|
|
274
|
+
let parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
275
|
+
if (options.loadReplicas && confType === 'server') parsed = loadReplicas(deployId, parsed);
|
|
276
|
+
if (options.resolve) parsed = resolveConfSecrets(parsed);
|
|
277
|
+
return parsed;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Default deploy ID used when no deploy ID is specified.
|
|
282
|
+
* @constant {string}
|
|
283
|
+
* @memberof ServerConfBuilder
|
|
284
|
+
*/
|
|
285
|
+
const DEFAULT_DEPLOY_ID = 'dd-default';
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @class Config
|
|
289
|
+
* @description Manages the configuration of the server.
|
|
290
|
+
* This class provides a set of static methods to automate various
|
|
291
|
+
* infrastructure operations, including NFS management, control server setup,
|
|
292
|
+
* and system provisioning for different architectures.
|
|
293
|
+
* @memberof ServerConfBuilder
|
|
294
|
+
*/
|
|
295
|
+
const Config = {
|
|
296
|
+
/**
|
|
297
|
+
* @method default
|
|
298
|
+
* @description The default configuration of the server.
|
|
299
|
+
* @memberof ServerConfBuilder
|
|
300
|
+
*/
|
|
301
|
+
default: DefaultConf,
|
|
302
|
+
/**
|
|
303
|
+
* @method build
|
|
304
|
+
* @description Builds the configuration of the server.
|
|
305
|
+
* @param {string} [deployContext='dd-default'] - The deploy context.
|
|
306
|
+
* @param {string} [deployList=''] - The deploy list.
|
|
307
|
+
* @param {string} [subConf=''] - The sub configuration.
|
|
308
|
+
* @memberof ServerConfBuilder
|
|
309
|
+
*/
|
|
310
|
+
build: async function (deployContext = DEFAULT_DEPLOY_ID, deployList, subConf) {
|
|
311
|
+
if (process.argv[2] && typeof process.argv[2] === 'string' && process.argv[2].startsWith('dd-'))
|
|
312
|
+
deployContext = process.argv[2];
|
|
313
|
+
else if (deployContext !== 'proxy' && process.env.DEPLOY_ID && process.env.DEPLOY_ID.startsWith('dd-'))
|
|
314
|
+
deployContext = process.env.DEPLOY_ID;
|
|
315
|
+
if (!subConf && process.argv[3] && typeof process.argv[3] === 'string') subConf = process.argv[3];
|
|
316
|
+
|
|
317
|
+
Underpost.env.set('await-deploy', new Date().toISOString());
|
|
318
|
+
if (deployContext.startsWith('dd-')) loadConf(deployContext, subConf);
|
|
319
|
+
if (deployContext === 'proxy') await Config.buildProxy(deployList, subConf);
|
|
320
|
+
},
|
|
321
|
+
/**
|
|
322
|
+
* @method deployIdFactory
|
|
323
|
+
* @description Creates a new deploy ID.
|
|
324
|
+
* @param {string} [deployId='dd-default']
|
|
325
|
+
* @param {object} [options={ subConf: '', cluster: false }] - The options.
|
|
326
|
+
* @memberof ServerConfBuilder
|
|
327
|
+
*/
|
|
328
|
+
deployIdFactory: function (deployId = DEFAULT_DEPLOY_ID, options = { subConf: '', cluster: false }) {
|
|
329
|
+
if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
|
|
330
|
+
|
|
331
|
+
logger.info('Build deployId', deployId);
|
|
332
|
+
|
|
333
|
+
const folder = `./engine-private/conf/${deployId}`;
|
|
334
|
+
const repoName = `engine-${deployId.split('dd-')[1]}`;
|
|
335
|
+
|
|
336
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
337
|
+
|
|
338
|
+
const sharedEnvTemplate = fs.existsSync('./.env.example')
|
|
339
|
+
? fs.readFileSync('./.env.example', 'utf8')
|
|
340
|
+
: fs.existsSync('./.env.production')
|
|
341
|
+
? fs.readFileSync('./.env.production', 'utf8')
|
|
342
|
+
: '';
|
|
343
|
+
|
|
344
|
+
const envTemplates = {
|
|
345
|
+
production: fs.existsSync('./.env.production') ? fs.readFileSync('./.env.production', 'utf8') : sharedEnvTemplate,
|
|
346
|
+
development: fs.existsSync('./.env.development')
|
|
347
|
+
? fs.readFileSync('./.env.development', 'utf8')
|
|
348
|
+
: sharedEnvTemplate
|
|
349
|
+
? sharedEnvTemplate.replace('NODE_ENV=production', 'NODE_ENV=development').replace('PORT=3000', 'PORT=4000')
|
|
350
|
+
: '',
|
|
351
|
+
test: fs.existsSync('./.env.test')
|
|
352
|
+
? fs.readFileSync('./.env.test', 'utf8')
|
|
353
|
+
: sharedEnvTemplate
|
|
354
|
+
? sharedEnvTemplate.replace('NODE_ENV=production', 'NODE_ENV=test').replace('PORT=3000', 'PORT=5000')
|
|
355
|
+
: '',
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
for (const [envName, envTemplate] of Object.entries(envTemplates)) {
|
|
359
|
+
if (!envTemplate) continue;
|
|
360
|
+
fs.writeFileSync(`${folder}/.env.${envName}`, envTemplate.replaceAll('dd-default', deployId), 'utf8');
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
fs.writeFileSync(
|
|
364
|
+
`${folder}/package.json`,
|
|
365
|
+
fs.readFileSync('./package.json', 'utf8').replaceAll('dd-default', deployId),
|
|
366
|
+
'utf8',
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
// Write default conf JSON files if they don't exist
|
|
370
|
+
for (const confType of Object.keys(this.default)) {
|
|
371
|
+
const confPath = `${folder}/conf.${confType}.json`;
|
|
372
|
+
if (!fs.existsSync(confPath)) fs.writeFileSync(confPath, JSON.stringify(this.default[confType], null, 4), 'utf8');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (options.subConf) {
|
|
376
|
+
logger.info('Creating sub conf', {
|
|
377
|
+
deployId: deployId,
|
|
378
|
+
subConf: options.subConf,
|
|
379
|
+
});
|
|
380
|
+
fs.copySync(
|
|
381
|
+
`./engine-private/conf/${deployId}/conf.server.json`,
|
|
382
|
+
`./engine-private/conf/${deployId}/conf.server.dev.${options.subConf}.json`,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (options.cluster === true) {
|
|
387
|
+
fs.writeFileSync(
|
|
388
|
+
`./.github/workflows/${repoName}.cd.yml`,
|
|
389
|
+
fs.readFileSync(`./.github/workflows/engine-test.cd.yml`, 'utf8').replaceAll('test', deployId.split('dd-')[1]),
|
|
390
|
+
'utf8',
|
|
391
|
+
);
|
|
392
|
+
fs.writeFileSync(
|
|
393
|
+
`./.github/workflows/${repoName}.ci.yml`,
|
|
394
|
+
fs.readFileSync(`./.github/workflows/engine-test.ci.yml`, 'utf8').replaceAll('test', deployId.split('dd-')[1]),
|
|
395
|
+
'utf8',
|
|
396
|
+
);
|
|
397
|
+
shellExec(`node bin new --default-conf --deploy-id ${deployId}`);
|
|
398
|
+
|
|
399
|
+
if (!fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
400
|
+
fs.writeFileSync(`./engine-private/deploy/dd.router`, deployId, 'utf8');
|
|
401
|
+
else
|
|
402
|
+
fs.writeFileSync(
|
|
403
|
+
`./engine-private/deploy/dd.router`,
|
|
404
|
+
fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim() + `,${deployId}`,
|
|
405
|
+
'utf8',
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return { deployIdFolder: folder, deployId };
|
|
410
|
+
},
|
|
411
|
+
/**
|
|
412
|
+
* @method buildProxyByDeployId
|
|
413
|
+
* @description Builds the proxy by deploy ID.
|
|
414
|
+
* @param {string} [deployId='dd-default'] - The deploy ID.
|
|
415
|
+
* @param {string} [subConf=''] - The sub configuration.
|
|
416
|
+
* @memberof ServerConfBuilder
|
|
417
|
+
*/
|
|
418
|
+
buildProxyByDeployId: function (deployId = 'dd-default', subConf = '') {
|
|
419
|
+
let confPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
|
|
420
|
+
? `./engine-private/replica/${deployId}/conf.server.json`
|
|
421
|
+
: `./engine-private/conf/${deployId}/conf.server.json`;
|
|
422
|
+
|
|
423
|
+
if (
|
|
424
|
+
process.env.NODE_ENV === 'development' &&
|
|
425
|
+
subConf &&
|
|
426
|
+
fs.existsSync(`./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`)
|
|
427
|
+
)
|
|
428
|
+
confPath = `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
|
|
429
|
+
|
|
430
|
+
const serverConf = loadConfServerJson(confPath);
|
|
431
|
+
|
|
432
|
+
for (const host of Object.keys(loadReplicas(deployId, serverConf)))
|
|
433
|
+
this.default.server[host] = {
|
|
434
|
+
...this.default.server[host],
|
|
435
|
+
...serverConf[host],
|
|
436
|
+
};
|
|
437
|
+
},
|
|
438
|
+
/**
|
|
439
|
+
* @method buildProxy
|
|
440
|
+
* @description Builds the proxy.
|
|
441
|
+
* @param {string} [deployList='dd-default'] - The deploy list.
|
|
442
|
+
* @param {string} [subConf=''] - The sub configuration.
|
|
443
|
+
* @memberof ServerConfBuilder
|
|
444
|
+
*/
|
|
445
|
+
buildProxy: async function (deployList = 'dd-default', subConf = '') {
|
|
446
|
+
if (!deployList) deployList = process.argv[3];
|
|
447
|
+
if (!subConf) subConf = process.argv[4];
|
|
448
|
+
this.default.server = {};
|
|
449
|
+
for (const deployId of deployList.split(',')) {
|
|
450
|
+
this.buildProxyByDeployId(deployId, subConf);
|
|
451
|
+
if (fs.existsSync(`./engine-private/replica`)) {
|
|
452
|
+
const singleReplicas = await fs.readdir(`./engine-private/replica`);
|
|
453
|
+
for (let replica of singleReplicas) {
|
|
454
|
+
if (replica.startsWith(deployId)) this.buildProxyByDeployId(replica, subConf);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* @method loadConf
|
|
463
|
+
* @description Loads the configuration of the server.
|
|
464
|
+
* @param {string} [deployId='dd-default'] - The deploy ID.
|
|
465
|
+
* @param {string} [subConf=''] - The sub configuration.
|
|
466
|
+
* @memberof ServerConfBuilder
|
|
467
|
+
*/
|
|
468
|
+
const loadConf = (deployId = DEFAULT_DEPLOY_ID, subConf) => {
|
|
469
|
+
if (deployId === 'current') {
|
|
470
|
+
console.log(process.env.DEPLOY_ID);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (deployId === 'clean') {
|
|
474
|
+
const path = '.';
|
|
475
|
+
fs.removeSync(`${path}/.env`);
|
|
476
|
+
fs.removeSync(`${path}/.env.production`);
|
|
477
|
+
fs.removeSync(`${path}/.env.development`);
|
|
478
|
+
fs.removeSync(`${path}/.env.test`);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const folder = getConfFolder(deployId);
|
|
482
|
+
|
|
483
|
+
if (!fs.existsSync(folder)) Config.deployIdFactory(deployId);
|
|
484
|
+
|
|
485
|
+
if (subConf) process.env.DEPLOY_SUB_CONF = subConf;
|
|
486
|
+
|
|
487
|
+
for (const typeConf of Object.keys(Config.default)) {
|
|
488
|
+
let srcConf = fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8');
|
|
489
|
+
if (process.env.NODE_ENV === 'development' && typeConf === 'server' && subConf) {
|
|
490
|
+
const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
|
|
491
|
+
if (fs.existsSync(devConfPath)) srcConf = fs.readFileSync(devConfPath, 'utf8');
|
|
492
|
+
}
|
|
493
|
+
let parsed = JSON.parse(srcConf);
|
|
494
|
+
if (typeConf === 'server') parsed = loadReplicas(deployId, parsed);
|
|
495
|
+
Config.default[typeConf] = parsed;
|
|
496
|
+
}
|
|
497
|
+
fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
|
|
498
|
+
fs.writeFileSync(`./.env.development`, fs.readFileSync(`${folder}/.env.development`, 'utf8'), 'utf8');
|
|
499
|
+
fs.writeFileSync(`./.env.test`, fs.readFileSync(`${folder}/.env.test`, 'utf8'), 'utf8');
|
|
500
|
+
const NODE_ENV = process.env.NODE_ENV || 'development';
|
|
501
|
+
if (NODE_ENV) {
|
|
502
|
+
const subPathEnv = fs.existsSync(`${folder}/.env.${NODE_ENV}.${subConf}`)
|
|
503
|
+
? `${folder}/.env.${NODE_ENV}.${subConf}`
|
|
504
|
+
: `${folder}/.env.${NODE_ENV}`;
|
|
505
|
+
fs.writeFileSync(`./.env`, fs.readFileSync(subPathEnv, 'utf8'), 'utf8');
|
|
506
|
+
const env = dotenv.parse(fs.readFileSync(subPathEnv, 'utf8'));
|
|
507
|
+
process.env = {
|
|
508
|
+
...process.env,
|
|
509
|
+
...env,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
const originPackageJson = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
|
|
513
|
+
const packageJson = JSON.parse(fs.readFileSync(`${folder}/package.json`, 'utf8'));
|
|
514
|
+
originPackageJson.scripts.start = packageJson.scripts.start;
|
|
515
|
+
packageJson.scripts = originPackageJson.scripts;
|
|
516
|
+
fs.writeFileSync(`./package.json`, JSON.stringify(packageJson, null, 4), 'utf8');
|
|
517
|
+
return { folder, deployId };
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* @method loadReplicas
|
|
522
|
+
* @description Loads the replicas of the server.
|
|
523
|
+
* @param {object} confServer - The server configuration.
|
|
524
|
+
* @memberof ServerConfBuilder
|
|
525
|
+
*/
|
|
526
|
+
const loadReplicas = (deployId, confServer) => {
|
|
527
|
+
const confServerOrigin = newInstance(confServer);
|
|
528
|
+
for (const host of Object.keys(confServer)) {
|
|
529
|
+
for (const path of Object.keys(confServer[host])) {
|
|
530
|
+
const { replicas, singleReplica } = confServer[host][path];
|
|
531
|
+
if (replicas) {
|
|
532
|
+
if (!singleReplica)
|
|
533
|
+
for (const replicaPath of replicas) {
|
|
534
|
+
{
|
|
535
|
+
confServer[host][replicaPath] = newInstance(confServer[host][path]);
|
|
536
|
+
delete confServer[host][replicaPath].replicas;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
const orderReplica = orderAbc(confServerOrigin[host][path].replicas);
|
|
541
|
+
confServerOrigin[host][path].replicas = orderReplica;
|
|
542
|
+
confServer[host][path].replicas = orderReplica;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const serverPath = `./engine-private/conf/${deployId}/conf.server${process.env.NODE_ENV === 'production' ? '' : '.dev'}.json`;
|
|
548
|
+
if (fs.existsSync(serverPath)) fs.writeFileSync(serverPath, JSON.stringify(confServerOrigin, null, 4), 'utf8');
|
|
549
|
+
|
|
550
|
+
return confServer;
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* @method cloneConf
|
|
555
|
+
* @description Clones the configuration of the server.
|
|
556
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
557
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
558
|
+
* @param {object} [fromDefaultOptions={ deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
|
|
559
|
+
* @memberof ServerConfBuilder
|
|
560
|
+
*/
|
|
561
|
+
const cloneConf = async (
|
|
562
|
+
{ toOptions, fromOptions },
|
|
563
|
+
fromDefaultOptions = { deployId: 'dd-default', clientId: 'default' },
|
|
564
|
+
) => {
|
|
565
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
566
|
+
if (!fromOptions.clientId) fromOptions.clientId = fromDefaultOptions.clientId;
|
|
567
|
+
|
|
568
|
+
const confFromFolder = `./engine-private/conf/${fromOptions.deployId}`;
|
|
569
|
+
const confToFolder = `./engine-private/conf/${toOptions.deployId}`;
|
|
570
|
+
|
|
571
|
+
const toClientVariableName = getCapVariableName(toOptions.clientId);
|
|
572
|
+
const fromClientVariableName = getCapVariableName(fromOptions.clientId);
|
|
573
|
+
|
|
574
|
+
const formattedSrc = (dataConf) =>
|
|
575
|
+
JSON.stringify(dataConf, null, 4)
|
|
576
|
+
.replaceAll(fromClientVariableName, toClientVariableName)
|
|
577
|
+
.replaceAll(fromOptions.clientId, toOptions.clientId);
|
|
578
|
+
|
|
579
|
+
const isMergeConf = fs.existsSync(confToFolder);
|
|
580
|
+
if (!isMergeConf) fs.mkdirSync(confToFolder, { recursive: true });
|
|
581
|
+
|
|
582
|
+
fs.writeFileSync(
|
|
583
|
+
`${confToFolder}/.env.production`,
|
|
584
|
+
fs.readFileSync(`${confFromFolder}/.env.production`, 'utf8'),
|
|
585
|
+
'utf8',
|
|
586
|
+
);
|
|
587
|
+
fs.writeFileSync(
|
|
588
|
+
`${confToFolder}/.env.development`,
|
|
589
|
+
fs.readFileSync(`${confFromFolder}/.env.development`, 'utf8'),
|
|
590
|
+
'utf8',
|
|
591
|
+
);
|
|
592
|
+
fs.writeFileSync(`${confToFolder}/.env.test`, fs.readFileSync(`${confFromFolder}/.env.test`, 'utf8'), 'utf8');
|
|
593
|
+
|
|
594
|
+
for (const confTypeId of ['server', 'client', 'cron', 'ssr']) {
|
|
595
|
+
const confFromData = JSON.parse(fs.readFileSync(`${confFromFolder}/conf.${confTypeId}.json`, 'utf8'));
|
|
596
|
+
fs.writeFileSync(`${confToFolder}/conf.${confTypeId}.json`, formattedSrc(confFromData), 'utf8');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const packageData = JSON.parse(fs.readFileSync(`${confFromFolder}/package.json`, 'utf8'));
|
|
600
|
+
packageData.scripts.start = packageData.scripts.start.replaceAll(fromOptions.deployId, toOptions.deployId);
|
|
601
|
+
fs.writeFileSync(`${confToFolder}/package.json`, JSON.stringify(packageData, null, 4), 'utf8');
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* @method addClientConf
|
|
606
|
+
* @description Adds the client configuration to the server.
|
|
607
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
608
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
609
|
+
* @param {object} [fromDefaultOptions={ deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
|
|
610
|
+
* @memberof ServerConfBuilder
|
|
611
|
+
*/
|
|
612
|
+
const addClientConf = async (
|
|
613
|
+
{ toOptions, fromOptions },
|
|
614
|
+
fromDefaultOptions = { deployId: 'dd-default', clientId: 'default' },
|
|
615
|
+
) => {
|
|
616
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
617
|
+
if (!fromOptions.clientId) fromOptions.clientId = fromDefaultOptions.clientId;
|
|
618
|
+
|
|
619
|
+
const confFromFolder = `./engine-private/conf/${fromOptions.deployId}`;
|
|
620
|
+
const confToFolder = `./engine-private/conf/${toOptions.deployId}`;
|
|
621
|
+
|
|
622
|
+
const toClientConf = JSON.parse(fs.readFileSync(`${confToFolder}/conf.client.json`, 'utf8'));
|
|
623
|
+
const fromClientConf = JSON.parse(fs.readFileSync(`${confFromFolder}/conf.client.json`, 'utf8'));
|
|
624
|
+
|
|
625
|
+
const toClientVariableName = getCapVariableName(toOptions.clientId);
|
|
626
|
+
const fromClientVariableName = getCapVariableName(fromOptions.clientId);
|
|
627
|
+
|
|
628
|
+
const { host, path } = toOptions;
|
|
629
|
+
|
|
630
|
+
toClientConf[fromOptions.clientId] = fromClientConf[fromOptions.clientId];
|
|
631
|
+
|
|
632
|
+
fs.writeFileSync(`${confToFolder}/conf.client.json`, JSON.stringify(toClientConf, null, 4), 'utf8');
|
|
633
|
+
|
|
634
|
+
const toServerConf = JSON.parse(fs.readFileSync(`${confToFolder}/conf.server.json`, 'utf8'));
|
|
635
|
+
const fromServerConf = JSON.parse(fs.readFileSync(`${confToFolder}/conf.server.json`, 'utf8'));
|
|
636
|
+
|
|
637
|
+
toServerConf[host][path].client = fromOptions.clientId;
|
|
638
|
+
toServerConf[host][path].runtime = 'nodejs';
|
|
639
|
+
toServerConf[host][path].apis = fromClientConf[fromOptions.clientId].services;
|
|
640
|
+
|
|
641
|
+
fs.writeFileSync(`${confToFolder}/conf.server.json`, JSON.stringify(toServerConf, null, 4), 'utf8');
|
|
642
|
+
|
|
643
|
+
const fromSsrConf = JSON.parse(fs.readFileSync(`${confFromFolder}/conf.ssr.json`, 'utf8'));
|
|
644
|
+
const toSsrConf = JSON.parse(fs.readFileSync(`${confToFolder}/conf.ssr.json`, 'utf8'));
|
|
645
|
+
|
|
646
|
+
toSsrConf[fromClientVariableName] = fromSsrConf[fromClientVariableName];
|
|
647
|
+
|
|
648
|
+
fs.writeFileSync(`${confToFolder}/conf.ssr.json`, JSON.stringify(toSsrConf, null, 4), 'utf8');
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* @method buildClientSrc
|
|
653
|
+
* @description Builds the client source code.
|
|
654
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
655
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
656
|
+
* @param {object} [fromDefaultOptions={ deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
|
|
657
|
+
* @memberof ServerConfBuilder
|
|
658
|
+
*/
|
|
659
|
+
const buildClientSrc = async (
|
|
660
|
+
{ toOptions, fromOptions },
|
|
661
|
+
fromDefaultOptions = { deployId: 'dd-default', clientId: 'default' },
|
|
662
|
+
) => {
|
|
663
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
664
|
+
if (!fromOptions.clientId) fromOptions.clientId = fromDefaultOptions.clientId;
|
|
665
|
+
|
|
666
|
+
const confFromFolder = `./src/client/components/${fromOptions.clientId}`;
|
|
667
|
+
const confToFolder = `./src/client/components/${toOptions.clientId}`;
|
|
668
|
+
|
|
669
|
+
const toClientVariableName = getCapVariableName(toOptions.clientId);
|
|
670
|
+
const fromClientVariableName = getCapVariableName(fromOptions.clientId);
|
|
671
|
+
|
|
672
|
+
const formattedSrc = (src) =>
|
|
673
|
+
src.replaceAll(fromClientVariableName, toClientVariableName).replaceAll(fromOptions.clientId, toOptions.clientId);
|
|
674
|
+
|
|
675
|
+
const isMergeConf = fs.existsSync(confToFolder);
|
|
676
|
+
if (!isMergeConf) fs.mkdirSync(confToFolder, { recursive: true });
|
|
677
|
+
|
|
678
|
+
const files = await fs.readdir(confFromFolder, { recursive: true });
|
|
679
|
+
for (const relativePath of files) {
|
|
680
|
+
const fromFilePath = dir.resolve(`${confFromFolder}/${relativePath}`);
|
|
681
|
+
const toFilePath = dir.resolve(`${confToFolder}/${relativePath}`);
|
|
682
|
+
|
|
683
|
+
fs.writeFileSync(formattedSrc(toFilePath), formattedSrc(fs.readFileSync(fromFilePath, 'utf8')), 'utf8');
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
fs.writeFileSync(
|
|
687
|
+
`./src/client/ssr/head/${toClientVariableName}Scripts.js`,
|
|
688
|
+
formattedSrc(fs.readFileSync(`./src/client/ssr/head/${fromClientVariableName}Scripts.js`, 'utf8')),
|
|
689
|
+
'utf8',
|
|
690
|
+
);
|
|
691
|
+
|
|
692
|
+
fs.writeFileSync(
|
|
693
|
+
`./src/client/${toClientVariableName}.index.js`,
|
|
694
|
+
formattedSrc(fs.readFileSync(`./src/client/${fromClientVariableName}.index.js`, 'utf8')),
|
|
695
|
+
'utf8',
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
fs.copySync(`./src/client/public/${fromOptions.clientId}`, `./src/client/public/${toOptions.clientId}`);
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* @method buildApiSrc
|
|
703
|
+
* @description Builds the API source code.
|
|
704
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
705
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
706
|
+
* @param {object} [fromDefaultOptions={ apiId: 'default', deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
|
|
707
|
+
* @memberof ServerConfBuilder
|
|
708
|
+
*/
|
|
709
|
+
const buildApiSrc = async (
|
|
710
|
+
{ toOptions, fromOptions },
|
|
711
|
+
fromDefaultOptions = { apiId: 'default', deployId: 'dd-default', clientId: 'default' },
|
|
712
|
+
) => {
|
|
713
|
+
if (!fromOptions.apiId) fromOptions.apiId = fromDefaultOptions.apiId;
|
|
714
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
715
|
+
if (!fromOptions.clientId) fromOptions.clientId = fromDefaultOptions.clientId;
|
|
716
|
+
|
|
717
|
+
const toClientVariableName = getCapVariableName(toOptions.apiId);
|
|
718
|
+
const fromClientVariableName = getCapVariableName(fromOptions.apiId);
|
|
719
|
+
|
|
720
|
+
const formattedSrc = (src) =>
|
|
721
|
+
src.replaceAll(fromClientVariableName, toClientVariableName).replaceAll(fromOptions.apiId, toOptions.apiId);
|
|
722
|
+
|
|
723
|
+
const apiToFolder = `./src/api/${toOptions.apiId}`;
|
|
724
|
+
const apiFromFolder = `./src/api/${fromOptions.apiId}`;
|
|
725
|
+
|
|
726
|
+
const isMergeConf = fs.existsSync(apiToFolder);
|
|
727
|
+
if (!isMergeConf) fs.mkdirSync(apiToFolder, { recursive: true });
|
|
728
|
+
|
|
729
|
+
for (const srcApiType of ['model', 'controller', 'service', 'router']) {
|
|
730
|
+
fs.writeFileSync(
|
|
731
|
+
`${apiToFolder}/${toOptions.apiId}.${srcApiType}.js`,
|
|
732
|
+
formattedSrc(fs.readFileSync(`${apiFromFolder}/${fromOptions.apiId}.${srcApiType}.js`, 'utf8')),
|
|
733
|
+
'utf8',
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
fs.mkdirSync(`./src/client/services/${toOptions.apiId}`, { recursive: true });
|
|
738
|
+
if (fs.existsSync(`./src/client/services/${fromOptions.apiId}/${fromOptions.apiId}.service.js`))
|
|
739
|
+
fs.writeFileSync(
|
|
740
|
+
`./src/client/services/${toOptions.apiId}/${toOptions.apiId}.service.js`,
|
|
741
|
+
formattedSrc(
|
|
742
|
+
fs.readFileSync(`./src/client/services/${fromOptions.apiId}/${fromOptions.apiId}.service.js`, 'utf8'),
|
|
743
|
+
),
|
|
744
|
+
'utf8',
|
|
745
|
+
);
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @method addApiConf
|
|
750
|
+
* @description Adds the API configuration to the server.
|
|
751
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
752
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
753
|
+
* @param {object} [fromDefaultOptions={ apiId: 'default', deployId: 'dd-default', clientId: 'default' }] - The default options for the source configuration.
|
|
754
|
+
* @memberof ServerConfBuilder
|
|
755
|
+
*/
|
|
756
|
+
const addApiConf = async (
|
|
757
|
+
{ toOptions, fromOptions },
|
|
758
|
+
fromDefaultOptions = { apiId: 'default', deployId: 'dd-default', clientId: 'default' },
|
|
759
|
+
) => {
|
|
760
|
+
if (!fromOptions.apiId) fromOptions.apiId = fromDefaultOptions.apiId;
|
|
761
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
762
|
+
if (!fromOptions.clientId) fromOptions.clientId = fromDefaultOptions.clientId;
|
|
763
|
+
|
|
764
|
+
const toClientVariableName = getCapVariableName(toOptions.apiId);
|
|
765
|
+
const fromClientVariableName = getCapVariableName(fromOptions.apiId);
|
|
766
|
+
|
|
767
|
+
const confFromFolder = `./engine-private/conf/${fromOptions.deployId}`;
|
|
768
|
+
const confToFolder = `./engine-private/conf/${toOptions.deployId}`;
|
|
769
|
+
|
|
770
|
+
const confServer = JSON.parse(fs.readFileSync(`${confToFolder}/conf.server.json`, 'utf8'));
|
|
771
|
+
for (const host of Object.keys(confServer))
|
|
772
|
+
for (const path of Object.keys(confServer[host]))
|
|
773
|
+
if (confServer[host][path].apis) confServer[host][path].apis.push(toOptions.apiId);
|
|
774
|
+
fs.writeFileSync(`${confToFolder}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
775
|
+
|
|
776
|
+
const confClient = JSON.parse(fs.readFileSync(`${confToFolder}/conf.client.json`, 'utf8'));
|
|
777
|
+
confClient[toOptions.clientId].services.push(toOptions.apiId);
|
|
778
|
+
fs.writeFileSync(`${confToFolder}/conf.client.json`, JSON.stringify(confClient, null, 4), 'utf8');
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* @method addWsConf
|
|
783
|
+
* @description Adds the WebSocket configuration to the server.
|
|
784
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
785
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
786
|
+
* @param {object} [fromDefaultOptions={ wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' }] - The default options for the source configuration.
|
|
787
|
+
* @memberof ServerConfBuilder
|
|
788
|
+
*/
|
|
789
|
+
const addWsConf = async (
|
|
790
|
+
{ toOptions, fromOptions },
|
|
791
|
+
fromDefaultOptions = { wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' },
|
|
792
|
+
) => {
|
|
793
|
+
if (!fromOptions.wsId) fromOptions.wsId = fromDefaultOptions.wsId;
|
|
794
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
795
|
+
if (!fromOptions.host) fromOptions.host = fromDefaultOptions.host;
|
|
796
|
+
if (!fromOptions.paths) fromOptions.paths = fromDefaultOptions.paths;
|
|
797
|
+
|
|
798
|
+
const toClientVariableName = getCapVariableName(toOptions.apiId);
|
|
799
|
+
const fromClientVariableName = getCapVariableName(fromOptions.apiId);
|
|
800
|
+
|
|
801
|
+
const confFromFolder = `./engine-private/conf/${fromOptions.deployId}`;
|
|
802
|
+
const confToFolder = `./engine-private/conf/${toOptions.deployId}`;
|
|
803
|
+
|
|
804
|
+
const paths = toOptions.paths.split(',');
|
|
805
|
+
|
|
806
|
+
const confServer = JSON.parse(fs.readFileSync(`${confToFolder}/conf.server.json`, 'utf8'));
|
|
807
|
+
for (const host of Object.keys(confServer))
|
|
808
|
+
for (const path of Object.keys(confServer[host]))
|
|
809
|
+
if (host === toOptions.host && paths.includes(path) && confServer[host][path])
|
|
810
|
+
confServer[host][path].ws = toOptions.wsId;
|
|
811
|
+
fs.writeFileSync(`${confToFolder}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* @method buildWsSrc
|
|
816
|
+
* @description Builds the WebSocket source code.
|
|
817
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
818
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
819
|
+
* @param {object} [fromDefaultOptions={ wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' }] - The default options for the source configuration.
|
|
820
|
+
* @memberof ServerConfBuilder
|
|
821
|
+
*/
|
|
822
|
+
const buildWsSrc = async (
|
|
823
|
+
{ toOptions, fromOptions },
|
|
824
|
+
fromDefaultOptions = { wsId: 'default', deployId: 'dd-default', host: 'default.net', paths: '/' },
|
|
825
|
+
) => {
|
|
826
|
+
if (!fromOptions.wsId) fromOptions.wsId = fromDefaultOptions.wsId;
|
|
827
|
+
if (!fromOptions.deployId) fromOptions.deployId = fromDefaultOptions.deployId;
|
|
828
|
+
if (!fromOptions.host) fromOptions.host = fromDefaultOptions.host;
|
|
829
|
+
if (!fromOptions.paths) fromOptions.paths = fromDefaultOptions.paths;
|
|
830
|
+
|
|
831
|
+
const toClientVariableName = getCapVariableName(toOptions.wsId);
|
|
832
|
+
const fromClientVariableName = getCapVariableName(fromOptions.wsId);
|
|
833
|
+
|
|
834
|
+
const confFromFolder = `./src/ws/${fromOptions.wsId}`;
|
|
835
|
+
const confToFolder = `./src/ws/${toOptions.wsId}`;
|
|
836
|
+
|
|
837
|
+
const paths = toOptions.paths.split(',');
|
|
838
|
+
|
|
839
|
+
const formattedSrc = (src) =>
|
|
840
|
+
src.replaceAll(fromClientVariableName, toClientVariableName).replaceAll(fromOptions.wsId, toOptions.wsId);
|
|
841
|
+
|
|
842
|
+
const files = await fs.readdir(confFromFolder, { recursive: true });
|
|
843
|
+
for (const relativePath of files) {
|
|
844
|
+
const fromFilePath = dir.resolve(`${confFromFolder}/${relativePath}`);
|
|
845
|
+
const toFilePath = dir.resolve(`${confToFolder}/${relativePath}`);
|
|
846
|
+
|
|
847
|
+
if (fs.lstatSync(fromFilePath).isDirectory() && !fs.existsSync(formattedSrc(toFilePath)))
|
|
848
|
+
fs.mkdirSync(formattedSrc(toFilePath), { recursive: true });
|
|
849
|
+
|
|
850
|
+
if (fs.lstatSync(fromFilePath).isFile() && !fs.existsSync(formattedSrc(toFilePath))) {
|
|
851
|
+
fs.writeFileSync(formattedSrc(toFilePath), formattedSrc(fs.readFileSync(fromFilePath, 'utf8')), 'utf8');
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* @method cloneSrcComponents
|
|
858
|
+
* @description Clones the source components.
|
|
859
|
+
* @param {object} toOptions - The options for the target configuration.
|
|
860
|
+
* @param {object} fromOptions - The options for the source configuration.
|
|
861
|
+
* @memberof ServerConfBuilder
|
|
862
|
+
*/
|
|
863
|
+
const cloneSrcComponents = async ({ toOptions, fromOptions }) => {
|
|
864
|
+
const toClientVariableName = getCapVariableName(toOptions.componentsFolder);
|
|
865
|
+
const fromClientVariableName = getCapVariableName(fromOptions.componentsFolder);
|
|
866
|
+
|
|
867
|
+
const formattedSrc = (src) =>
|
|
868
|
+
src
|
|
869
|
+
.replaceAll(fromClientVariableName, toClientVariableName)
|
|
870
|
+
.replaceAll(fromOptions.componentsFolder, toOptions.componentsFolder);
|
|
871
|
+
|
|
872
|
+
const confFromFolder = `./src/client/components/${fromOptions.componentsFolder}`;
|
|
873
|
+
const confToFolder = `./src/client/components/${toOptions.componentsFolder}`;
|
|
874
|
+
|
|
875
|
+
fs.mkdirSync(confToFolder, { recursive: true });
|
|
876
|
+
|
|
877
|
+
const files = await fs.readdir(confFromFolder);
|
|
878
|
+
for (const relativePath of files) {
|
|
879
|
+
const fromFilePath = dir.resolve(`${confFromFolder}/${relativePath}`);
|
|
880
|
+
const toFilePath = dir.resolve(`${confToFolder}/${relativePath}`);
|
|
881
|
+
|
|
882
|
+
fs.writeFileSync(formattedSrc(toFilePath), formattedSrc(fs.readFileSync(fromFilePath, 'utf8')), 'utf8');
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* @method buildProxyRouter
|
|
888
|
+
* @description Builds the proxy router.
|
|
889
|
+
* @memberof ServerConfBuilder
|
|
890
|
+
*/
|
|
891
|
+
const buildProxyRouter = () => {
|
|
892
|
+
const confServer = newInstance(Config.default.server);
|
|
893
|
+
let currentPort = parseInt(process.env.PORT) + 1;
|
|
894
|
+
const proxyRouter = {};
|
|
895
|
+
for (const host of Object.keys(confServer)) {
|
|
896
|
+
for (const path of Object.keys(confServer[host])) {
|
|
897
|
+
if (confServer[host][path].singleReplica) continue;
|
|
898
|
+
|
|
899
|
+
if (isDevProxyContext()) confServer[host][path].proxy = [isTlsDevProxy() ? 443 : 80];
|
|
900
|
+
|
|
901
|
+
confServer[host][path].port = newInstance(currentPort);
|
|
902
|
+
for (const port of confServer[host][path].proxy) {
|
|
903
|
+
if (!(port in proxyRouter)) proxyRouter[port] = {};
|
|
904
|
+
proxyRouter[port][`${host}${path}`] = {
|
|
905
|
+
// target: `http://${host}:${confServer[host][path].port}${path}`,
|
|
906
|
+
target: `http://localhost:${confServer[host][path].port}`,
|
|
907
|
+
// target: `http://127.0.0.1:${confServer[host][path].port}`,
|
|
908
|
+
proxy: confServer[host][path].proxy,
|
|
909
|
+
redirect: confServer[host][path].redirect,
|
|
910
|
+
host,
|
|
911
|
+
path,
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
currentPort++;
|
|
915
|
+
if (confServer[host][path].peer) {
|
|
916
|
+
const peerPath = path === '/' ? `/peer` : `${path}/peer`;
|
|
917
|
+
confServer[host][peerPath] = newInstance(confServer[host][path]);
|
|
918
|
+
confServer[host][peerPath].port = newInstance(currentPort);
|
|
919
|
+
for (const port of confServer[host][path].proxy) {
|
|
920
|
+
if (!(port in proxyRouter)) proxyRouter[port] = {};
|
|
921
|
+
proxyRouter[port][`${host}${peerPath}`] = {
|
|
922
|
+
// target: `http://${host}:${confServer[host][peerPath].port}${peerPath}`,
|
|
923
|
+
target: `http://localhost:${confServer[host][peerPath].port}`,
|
|
924
|
+
// target: `http://127.0.0.1:${confServer[host][peerPath].port}`,
|
|
925
|
+
proxy: confServer[host][peerPath].proxy,
|
|
926
|
+
host,
|
|
927
|
+
path: peerPath,
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
currentPort++;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return proxyRouter;
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* @method pathPortAssignmentFactory
|
|
940
|
+
* @description Creates the path port assignment.
|
|
941
|
+
* @param {string} deployId - The deploy ID.
|
|
942
|
+
* @param {object} router - The router.
|
|
943
|
+
* @param {object} confServer - The server configuration.
|
|
944
|
+
* @memberof ServerConfBuilder
|
|
945
|
+
*/
|
|
946
|
+
const pathPortAssignmentFactory = async (deployId, router, confServer) => {
|
|
947
|
+
const pathPortAssignmentData = {};
|
|
948
|
+
for (const host of Object.keys(confServer)) {
|
|
949
|
+
const pathPortAssignment = [];
|
|
950
|
+
for (const path of Object.keys(confServer[host])) {
|
|
951
|
+
const { peer } = confServer[host][path];
|
|
952
|
+
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
953
|
+
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
954
|
+
// logger.info('', { host, port, path });
|
|
955
|
+
pathPortAssignment.push({
|
|
956
|
+
port,
|
|
957
|
+
path,
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
if (peer) {
|
|
961
|
+
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
962
|
+
pathPortAssignment.push({
|
|
963
|
+
port: port + 1,
|
|
964
|
+
path: `${path === '/' ? '' : path}/peer`,
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
pathPortAssignmentData[host] = pathPortAssignment;
|
|
969
|
+
}
|
|
970
|
+
if (fs.existsSync(`./engine-private/replica`)) {
|
|
971
|
+
const singleReplicas = await fs.readdir(`./engine-private/replica`);
|
|
972
|
+
for (let replica of singleReplicas) {
|
|
973
|
+
if (replica.startsWith(deployId)) {
|
|
974
|
+
const replicaServerConf = loadConfServerJson(`./engine-private/replica/${replica}/conf.server.json`);
|
|
975
|
+
for (const host of Object.keys(replicaServerConf)) {
|
|
976
|
+
const pathPortAssignment = [];
|
|
977
|
+
for (const path of Object.keys(replicaServerConf[host])) {
|
|
978
|
+
const { peer } = replicaServerConf[host][path];
|
|
979
|
+
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
980
|
+
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
981
|
+
// logger.info('', { host, port, path });
|
|
982
|
+
pathPortAssignment.push({
|
|
983
|
+
port,
|
|
984
|
+
path,
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
if (peer) {
|
|
988
|
+
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
989
|
+
pathPortAssignment.push({
|
|
990
|
+
port: port + 1,
|
|
991
|
+
path: `${path === '/' ? '' : path}/peer`,
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
pathPortAssignmentData[host] = pathPortAssignmentData[host].concat(pathPortAssignment);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return pathPortAssignmentData;
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* @method deployRangePortFactory
|
|
1005
|
+
* @description Creates the deploy range port factory.
|
|
1006
|
+
* @param {object} router - The router.
|
|
1007
|
+
* @returns {object} - The deploy range port factory.
|
|
1008
|
+
* @memberof ServerConfBuilder
|
|
1009
|
+
*/
|
|
1010
|
+
const deployRangePortFactory = (router) => {
|
|
1011
|
+
const ports = Object.values(router).map((p) => parseInt(p.split(':')[2]));
|
|
1012
|
+
const fromPort = Math.min(...ports);
|
|
1013
|
+
const toPort = Math.max(...ports);
|
|
1014
|
+
return { ports, fromPort, toPort };
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* @method buildKindPorts
|
|
1019
|
+
* @description Builds the kind ports.
|
|
1020
|
+
* @param {number} from - The from port.
|
|
1021
|
+
* @param {number} to - The to port.
|
|
1022
|
+
* @returns {string} - The kind ports.
|
|
1023
|
+
* @memberof ServerConfBuilder
|
|
1024
|
+
*/
|
|
1025
|
+
const buildKindPorts = (from, to) =>
|
|
1026
|
+
range(parseInt(from), parseInt(to))
|
|
1027
|
+
.map(
|
|
1028
|
+
(port) => ` - name: 'tcp-${port}'
|
|
1029
|
+
protocol: TCP
|
|
1030
|
+
port: ${port}
|
|
1031
|
+
targetPort: ${port}
|
|
1032
|
+
- name: 'udp-${port}'
|
|
1033
|
+
protocol: UDP
|
|
1034
|
+
port: ${port}
|
|
1035
|
+
targetPort: ${port}
|
|
1036
|
+
`,
|
|
1037
|
+
)
|
|
1038
|
+
.join('\n');
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* @method buildPortProxyRouter
|
|
1042
|
+
* @description Builds the port proxy router.
|
|
1043
|
+
* @param {object} options - The options.
|
|
1044
|
+
* @param {number} [options.port=4000] - The port.
|
|
1045
|
+
* @param {object} options.proxyRouter - The proxy router.
|
|
1046
|
+
* @param {object} [options.hosts] - The hosts.
|
|
1047
|
+
* @param {boolean} [options.orderByPathLength=false] - Whether to order by path length.
|
|
1048
|
+
* @param {boolean} [options.devProxyContext=false] - Whether to use dev proxy context.
|
|
1049
|
+
* @returns {object} - The port proxy router.
|
|
1050
|
+
* @memberof ServerConfBuilder
|
|
1051
|
+
*/
|
|
1052
|
+
const buildPortProxyRouter = (
|
|
1053
|
+
options = { port: 4000, proxyRouter, hosts, orderByPathLength: false, devProxyContext: false },
|
|
1054
|
+
) => {
|
|
1055
|
+
let { port, proxyRouter, hosts, orderByPathLength } = options;
|
|
1056
|
+
hosts = hosts || proxyRouter[port] || {};
|
|
1057
|
+
|
|
1058
|
+
const router = {};
|
|
1059
|
+
// build router
|
|
1060
|
+
Object.keys(hosts).map((hostKey) => {
|
|
1061
|
+
let { host, path, target, proxy, peer } = hosts[hostKey];
|
|
1062
|
+
|
|
1063
|
+
if (!proxy.includes(port)) {
|
|
1064
|
+
logger.warn('Proxy port not set on conf', { port, host, path, proxy, target });
|
|
1065
|
+
if (process.env.NODE_ENV === 'production') {
|
|
1066
|
+
logger.warn('Omitting host', { host, path, target });
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
// ${process.env.NODE_ENV === 'development' && !isDevProxyContext() ? `:${port}` : ''}
|
|
1071
|
+
const absoluteHost = [80, 443].includes(port)
|
|
1072
|
+
? `${host}${path === '/' ? '' : path}`
|
|
1073
|
+
: `${host}:${port}${path === '/' ? '' : path}`;
|
|
1074
|
+
|
|
1075
|
+
if (absoluteHost in router)
|
|
1076
|
+
logger.warn('Overwrite: Absolute host already exists on router', { absoluteHost, target });
|
|
1077
|
+
|
|
1078
|
+
if (options.devProxyContext === true) {
|
|
1079
|
+
const appDevPort = parseInt(target.split(':')[2]) - process.env.DEV_PROXY_PORT_OFFSET;
|
|
1080
|
+
router[absoluteHost] = `http://localhost:${appDevPort}`;
|
|
1081
|
+
} else router[absoluteHost] = target;
|
|
1082
|
+
}); // order router
|
|
1083
|
+
|
|
1084
|
+
if (Object.keys(router).length === 0) return router;
|
|
1085
|
+
|
|
1086
|
+
const devApiConfPath = `./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`;
|
|
1087
|
+
if (options.devProxyContext === true && process.env.NODE_ENV === 'development' && fs.existsSync(devApiConfPath)) {
|
|
1088
|
+
const confDevApiServer = JSON.parse(fs.readFileSync(devApiConfPath, 'utf8'));
|
|
1089
|
+
let devApiHosts = [];
|
|
1090
|
+
let origins = [];
|
|
1091
|
+
for (const _host of Object.keys(confDevApiServer))
|
|
1092
|
+
for (const _path of Object.keys(confDevApiServer[_host])) {
|
|
1093
|
+
if (confDevApiServer[_host][_path].origins && confDevApiServer[_host][_path].origins.length) {
|
|
1094
|
+
origins.push(...confDevApiServer[_host][_path].origins);
|
|
1095
|
+
if (_path !== 'peer' && devApiHosts.length === 0)
|
|
1096
|
+
devApiHosts.push(
|
|
1097
|
+
`${_host}${[80, 443].includes(port) && isDevProxyContext() ? '' : `:${port}`}${_path == '/' ? '' : _path}`,
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
origins = Array.from(new Set(origins));
|
|
1102
|
+
console.log({
|
|
1103
|
+
origins,
|
|
1104
|
+
devApiHosts,
|
|
1105
|
+
});
|
|
1106
|
+
for (const devApiHost of devApiHosts) {
|
|
1107
|
+
if (devApiHost in router) {
|
|
1108
|
+
const target = router[devApiHost];
|
|
1109
|
+
delete router[devApiHost];
|
|
1110
|
+
router[`${devApiHost}/${process.env.BASE_API}`] = target;
|
|
1111
|
+
router[`${devApiHost}/socket.io`] = target;
|
|
1112
|
+
for (const origin of origins) router[devApiHost] = origin;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
if (orderByPathLength === true) {
|
|
1118
|
+
const reOrderRouter = {};
|
|
1119
|
+
for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
|
|
1120
|
+
reOrderRouter[absoluteHostKey] = router[absoluteHostKey];
|
|
1121
|
+
return reOrderRouter;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
return router;
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* @method buildReplicaId
|
|
1129
|
+
* @description Builds the replica ID.
|
|
1130
|
+
* @param {object} options - The options.
|
|
1131
|
+
* @param {string} options.deployId - The deploy ID.
|
|
1132
|
+
* @param {string} options.replica - The replica.
|
|
1133
|
+
* @returns {string} - The replica ID.
|
|
1134
|
+
* @memberof ServerConfBuilder
|
|
1135
|
+
*/
|
|
1136
|
+
const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* @method getDataDeploy
|
|
1140
|
+
* @description Gets the data deploy.
|
|
1141
|
+
* @param {object} options - The options.
|
|
1142
|
+
* @param {boolean} [options.buildSingleReplica=false] - The build single replica.
|
|
1143
|
+
* @param {string} [options.deployId] - The deploy ID.
|
|
1144
|
+
* @param {boolean} [options.disableSyncEnvPort=false] - The disable sync env port.
|
|
1145
|
+
* @returns {object} - The data deploy.
|
|
1146
|
+
* @memberof ServerConfBuilder
|
|
1147
|
+
*/
|
|
1148
|
+
const getDataDeploy = async (
|
|
1149
|
+
options = {
|
|
1150
|
+
buildSingleReplica: false,
|
|
1151
|
+
disableSyncEnvPort: false,
|
|
1152
|
+
},
|
|
1153
|
+
) => {
|
|
1154
|
+
let dataDeploy = fs
|
|
1155
|
+
.readFileSync(`./engine-private/deploy/dd.router`, 'utf8')
|
|
1156
|
+
.split(',')
|
|
1157
|
+
.map((deployId) => deployId.trim())
|
|
1158
|
+
.filter((deployId) => deployId);
|
|
1159
|
+
|
|
1160
|
+
dataDeploy = dataDeploy.map((deployId) => {
|
|
1161
|
+
return {
|
|
1162
|
+
deployId,
|
|
1163
|
+
};
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
if (options && options.buildSingleReplica && fs.existsSync(`./engine-private/replica`))
|
|
1167
|
+
fs.removeSync(`./engine-private/replica`);
|
|
1168
|
+
|
|
1169
|
+
let buildDataDeploy = [];
|
|
1170
|
+
for (const deployObj of dataDeploy) {
|
|
1171
|
+
const isReplicaDeploy = fs.existsSync(`./engine-private/replica/${deployObj.deployId}`);
|
|
1172
|
+
const serverConf = loadReplicas(
|
|
1173
|
+
deployObj.deployId,
|
|
1174
|
+
loadConfServerJson(`./engine-private/conf/${deployObj.deployId}/conf.server.json`),
|
|
1175
|
+
);
|
|
1176
|
+
let replicaDataDeploy = [];
|
|
1177
|
+
for (const host of Object.keys(serverConf))
|
|
1178
|
+
for (const path of Object.keys(serverConf[host])) {
|
|
1179
|
+
if (!isReplicaDeploy && serverConf[host][path].replicas && serverConf[host][path].singleReplica) {
|
|
1180
|
+
if (options && options.buildSingleReplica)
|
|
1181
|
+
await Underpost.repo.client(deployObj.deployId, '', host, path, {
|
|
1182
|
+
singleReplica: true,
|
|
1183
|
+
});
|
|
1184
|
+
replicaDataDeploy = replicaDataDeploy.concat(
|
|
1185
|
+
serverConf[host][path].replicas.map((r) => {
|
|
1186
|
+
return {
|
|
1187
|
+
deployId: buildReplicaId({ deployId: deployObj.deployId, replica: r }),
|
|
1188
|
+
replicaHost: host,
|
|
1189
|
+
};
|
|
1190
|
+
}),
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
buildDataDeploy.push(deployObj);
|
|
1195
|
+
if (replicaDataDeploy.length > 0) buildDataDeploy = buildDataDeploy.concat(replicaDataDeploy);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
if (!options.disableSyncEnvPort && options.buildSingleReplica)
|
|
1199
|
+
await Underpost.repo.client(undefined, '', '', '', { syncEnvPort: true });
|
|
1200
|
+
|
|
1201
|
+
logger.info('Deployments configured', buildDataDeploy);
|
|
1202
|
+
|
|
1203
|
+
return buildDataDeploy;
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* @method validateTemplatePath
|
|
1208
|
+
* @description Validates the template path.
|
|
1209
|
+
* @param {string} absolutePath - The absolute path.
|
|
1210
|
+
* @returns {boolean} - The validation result.
|
|
1211
|
+
* @memberof ServerConfBuilder
|
|
1212
|
+
*/
|
|
1213
|
+
const validateTemplatePath = (absolutePath = '') => {
|
|
1214
|
+
const host = 'default.net';
|
|
1215
|
+
const path = '/';
|
|
1216
|
+
const client = 'default';
|
|
1217
|
+
const ssr = 'Default';
|
|
1218
|
+
const confServer = DefaultConf.server[host][path];
|
|
1219
|
+
const confClient = DefaultConf.client[client];
|
|
1220
|
+
const confSsr = DefaultConf.ssr[ssr];
|
|
1221
|
+
const clients = DefaultConf.client.default.services;
|
|
1222
|
+
|
|
1223
|
+
if (
|
|
1224
|
+
absolutePath.match('src/api') &&
|
|
1225
|
+
!absolutePath.match('src/api/types.js') &&
|
|
1226
|
+
!confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))
|
|
1227
|
+
) {
|
|
1228
|
+
return false;
|
|
1229
|
+
}
|
|
1230
|
+
if (absolutePath.match('conf.dd-') && absolutePath.match('.js')) return false;
|
|
1231
|
+
if (absolutePath.match('typedoc.dd-') && absolutePath.match('.json')) return false;
|
|
1232
|
+
if (
|
|
1233
|
+
absolutePath.match('src/client/services/') &&
|
|
1234
|
+
!clients.find((p) => absolutePath.match(`src/client/services/${p}/`))
|
|
1235
|
+
) {
|
|
1236
|
+
return false;
|
|
1237
|
+
}
|
|
1238
|
+
if (absolutePath.match('src/client/public/') && !clients.find((p) => absolutePath.match(`src/client/public/${p}/`))) {
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
if (
|
|
1242
|
+
absolutePath.match('src/client/components/') &&
|
|
1243
|
+
!clients.find((p) => absolutePath.match(`src/client/components/${p}/`))
|
|
1244
|
+
) {
|
|
1245
|
+
return false;
|
|
1246
|
+
}
|
|
1247
|
+
if (absolutePath.match('src/client/sw/') && !absolutePath.match('src/client/sw/core.sw.js')) {
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
if (
|
|
1251
|
+
absolutePath.match('src/client/ssr/body') &&
|
|
1252
|
+
!confSsr.body.find((p) => absolutePath.match(`src/client/ssr/body/${p}.js`))
|
|
1253
|
+
) {
|
|
1254
|
+
return false;
|
|
1255
|
+
}
|
|
1256
|
+
if (
|
|
1257
|
+
absolutePath.match('src/client/ssr/head') &&
|
|
1258
|
+
!confSsr.head.find((p) => absolutePath.match(`src/client/ssr/head/${p}.js`))
|
|
1259
|
+
) {
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
1262
|
+
if (
|
|
1263
|
+
absolutePath.match('src/client/ssr/mailer') &&
|
|
1264
|
+
!Object.keys(confSsr.mailer).find((p) => absolutePath.match(`src/client/ssr/mailer/${confSsr.mailer[p]}.js`))
|
|
1265
|
+
) {
|
|
1266
|
+
return false;
|
|
1267
|
+
}
|
|
1268
|
+
if (
|
|
1269
|
+
absolutePath.match('src/client/ssr/views') &&
|
|
1270
|
+
!(confSsr.views || []).find((p) => absolutePath.match(`src/client/ssr/views/${p.client}.js`))
|
|
1271
|
+
) {
|
|
1272
|
+
return false;
|
|
1273
|
+
}
|
|
1274
|
+
if (absolutePath.match('hardhat/')) return false;
|
|
1275
|
+
if (
|
|
1276
|
+
absolutePath.match('/client') &&
|
|
1277
|
+
absolutePath.match('.index.js') &&
|
|
1278
|
+
!absolutePath.match('/offline') &&
|
|
1279
|
+
!clients.find((p) => absolutePath.match(`src/client/${capFirst(p)}.index.js`))
|
|
1280
|
+
) {
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1283
|
+
if (absolutePath.match('src/ws/') && !clients.find((p) => absolutePath.match(`src/ws/${p}/`))) {
|
|
1284
|
+
return false;
|
|
1285
|
+
}
|
|
1286
|
+
return true;
|
|
1287
|
+
};
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* @method awaitDeployMonitor
|
|
1291
|
+
* @description Waits for the deploy monitor.
|
|
1292
|
+
* @param {boolean} [isFinal=false] - If true, logs when the final (non-replica) deployment completes.
|
|
1293
|
+
* @param {number} [deltaMs=1000] - The delta ms.
|
|
1294
|
+
* @param {boolean} [callback=false] - The callback.
|
|
1295
|
+
* @returns {Promise<boolean>} - `false` if `container-status=error` was detected, `true` on clean completion.
|
|
1296
|
+
* @memberof ServerConfBuilder
|
|
1297
|
+
*/
|
|
1298
|
+
const awaitDeployMonitor = async (isFinal = false, deltaMs = 1000, callback = false) => {
|
|
1299
|
+
if (!callback) Underpost.env.set('await-deploy', new Date().toISOString());
|
|
1300
|
+
if (isFinal) logger.info('Final deployment running (no replica)');
|
|
1301
|
+
await timer(deltaMs);
|
|
1302
|
+
if (Underpost.env.get('container-status') === 'error') return false;
|
|
1303
|
+
if (Underpost.env.get('await-deploy')) return await awaitDeployMonitor(false, deltaMs, true);
|
|
1304
|
+
return true;
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* @method mergeFile
|
|
1309
|
+
* @description Merges the file.
|
|
1310
|
+
* @param {Array} parts - The parts.
|
|
1311
|
+
* @param {string} outputFilePath - The output file path.
|
|
1312
|
+
* @returns {Promise<void>} - The merge file.
|
|
1313
|
+
* @memberof ServerConfBuilder
|
|
1314
|
+
*/
|
|
1315
|
+
const mergeFile = async (parts = [], outputFilePath) => {
|
|
1316
|
+
await new Promise((resolve) => {
|
|
1317
|
+
splitFile
|
|
1318
|
+
.mergeFiles(parts, outputFilePath)
|
|
1319
|
+
.then(() => {
|
|
1320
|
+
resolve();
|
|
1321
|
+
})
|
|
1322
|
+
.catch((err) => {
|
|
1323
|
+
console.log('Error: ', err);
|
|
1324
|
+
resolve();
|
|
1325
|
+
});
|
|
1326
|
+
});
|
|
1327
|
+
};
|
|
1328
|
+
|
|
1329
|
+
/**
|
|
1330
|
+
* @method getPathsSSR
|
|
1331
|
+
* @description Gets the paths SSR.
|
|
1332
|
+
* @param {object} conf - The conf.
|
|
1333
|
+
* @returns {Array} - The paths SSR.
|
|
1334
|
+
* @memberof ServerConfBuilder
|
|
1335
|
+
*/
|
|
1336
|
+
const getPathsSSR = (conf) => {
|
|
1337
|
+
const paths = ['src/client/ssr/RootDocument.js'];
|
|
1338
|
+
for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
|
|
1339
|
+
for (const o of conf.body) paths.push(`src/client/ssr/body/${o}.js`);
|
|
1340
|
+
for (const o of Object.keys(conf.mailer)) paths.push(`src/client/ssr/mailer/${conf.mailer[o]}.js`);
|
|
1341
|
+
for (const o of conf.views || []) paths.push(`src/client/ssr/views/${o.client}.js`);
|
|
1342
|
+
return paths;
|
|
1343
|
+
};
|
|
1344
|
+
|
|
1345
|
+
/**
|
|
1346
|
+
* @method splitFileFactory
|
|
1347
|
+
* @description Splits the file factory.
|
|
1348
|
+
* @param {string} name - The name.
|
|
1349
|
+
* @param {string} _path - The path.
|
|
1350
|
+
* @returns {Promise<boolean>} - The split file factory.
|
|
1351
|
+
* @memberof ServerConfBuilder
|
|
1352
|
+
*/
|
|
1353
|
+
const splitFileFactory = async (name, _path) => {
|
|
1354
|
+
const stats = fs.statSync(_path);
|
|
1355
|
+
const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
|
|
1356
|
+
const fileSizeInBytes = stats.size;
|
|
1357
|
+
if (fileSizeInBytes > maxSizeInBytes) {
|
|
1358
|
+
logger.info('splitFileFactory input', { name, from: _path });
|
|
1359
|
+
return await new Promise((resolve) => {
|
|
1360
|
+
splitFile
|
|
1361
|
+
.splitFileBySize(_path, maxSizeInBytes) // 50 mb
|
|
1362
|
+
.then((names) => {
|
|
1363
|
+
logger.info('splitFileFactory output', { parts: names });
|
|
1364
|
+
fs.writeFileSync(
|
|
1365
|
+
`${_path.split('/').slice(0, -1).join('/')}/${name}-parths.json`,
|
|
1366
|
+
JSON.stringify(names, null, 4),
|
|
1367
|
+
'utf8',
|
|
1368
|
+
);
|
|
1369
|
+
fs.removeSync(_path);
|
|
1370
|
+
return resolve(true);
|
|
1371
|
+
})
|
|
1372
|
+
.catch((err) => {
|
|
1373
|
+
console.log('Error: ', err);
|
|
1374
|
+
return resolve(false);
|
|
1375
|
+
});
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
return false;
|
|
1379
|
+
};
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* @method getNpmRootPath
|
|
1383
|
+
* @description Gets the npm root path.
|
|
1384
|
+
* @returns {string} - The npm root path.
|
|
1385
|
+
* @memberof ServerConfBuilder
|
|
1386
|
+
*/
|
|
1387
|
+
const getNpmRootPath = () =>
|
|
1388
|
+
shellExec(`npm root -g`, {
|
|
1389
|
+
stdout: true,
|
|
1390
|
+
disableLog: true,
|
|
1391
|
+
silent: true,
|
|
1392
|
+
}).trim();
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* @method getUnderpostRootPath
|
|
1396
|
+
* @description Gets the underpost root path.
|
|
1397
|
+
* @returns {string} - The underpost root path.
|
|
1398
|
+
* @memberof ServerConfBuilder
|
|
1399
|
+
*/
|
|
1400
|
+
const getUnderpostRootPath = () => `${getNpmRootPath()}/underpost`;
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* @method writeEnv
|
|
1404
|
+
* @description Writes the environment variables.
|
|
1405
|
+
* @param {string} envPath - The environment path.
|
|
1406
|
+
* @param {object} envObj - The environment object.
|
|
1407
|
+
* @memberof ServerConfBuilder
|
|
1408
|
+
*/
|
|
1409
|
+
const writeEnv = (envPath, envObj) =>
|
|
1410
|
+
fs.writeFileSync(
|
|
1411
|
+
envPath,
|
|
1412
|
+
Object.keys(envObj)
|
|
1413
|
+
.map((key) => `${key}=${envObj[key]}`)
|
|
1414
|
+
.join(`\n`),
|
|
1415
|
+
'utf8',
|
|
1416
|
+
);
|
|
1417
|
+
|
|
1418
|
+
/**
|
|
1419
|
+
* @method buildCliDoc
|
|
1420
|
+
* @description Scrapes `node bin help` (and `node bin help <command>` for every
|
|
1421
|
+
* registered command) and renders a structured Markdown reference: a command
|
|
1422
|
+
* index with anchor links, plus a per-command section with its description,
|
|
1423
|
+
* usage, and Arguments/Options rendered as tables. Writes
|
|
1424
|
+
* `CLI-HELP.md` + the served reference doc, and refreshes the README CLI index.
|
|
1425
|
+
* @param {object} program - The commander program.
|
|
1426
|
+
* @param {string} oldVersion - The old version string to replace.
|
|
1427
|
+
* @param {string} newVersion - The new version string.
|
|
1428
|
+
* @memberof ServerConfBuilder
|
|
1429
|
+
*/
|
|
1430
|
+
const buildCliDoc = (program, oldVersion, newVersion) => {
|
|
1431
|
+
const help = (args = '') => shellExec(`node bin help${args ? ` ${args}` : ''}`, { silent: true, stdout: true });
|
|
1432
|
+
// Escape table-breaking pipes and collapse wrapped whitespace for a Markdown cell.
|
|
1433
|
+
const cell = (s) => String(s).replace(/\s+/g, ' ').replaceAll('|', '\\|').trim();
|
|
1434
|
+
const anchor = (name) => `underpost-${name}`.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
1435
|
+
|
|
1436
|
+
// Parse a commander help block into { usage, description, sections: { Options, Arguments, Commands } }.
|
|
1437
|
+
const parseHelp = (text) => {
|
|
1438
|
+
const lines = text.split('\n');
|
|
1439
|
+
const usageMatch = lines[0].match(/^Usage:\s*(.*)$/);
|
|
1440
|
+
const usage = usageMatch ? usageMatch[1].trim() : '';
|
|
1441
|
+
const sections = {};
|
|
1442
|
+
const descLines = [];
|
|
1443
|
+
let current = null;
|
|
1444
|
+
let buf = [];
|
|
1445
|
+
const flush = () => {
|
|
1446
|
+
if (current) sections[current] = buf.join('\n');
|
|
1447
|
+
buf = [];
|
|
1448
|
+
};
|
|
1449
|
+
for (let i = 1; i < lines.length; i++) {
|
|
1450
|
+
const line = lines[i];
|
|
1451
|
+
const head = line.match(/^([A-Za-z][\w ]*):\s*$/); // top-level "Options:", "Arguments:", "Commands:"
|
|
1452
|
+
if (head) {
|
|
1453
|
+
flush();
|
|
1454
|
+
current = head[1].trim();
|
|
1455
|
+
} else if (current !== null) {
|
|
1456
|
+
buf.push(line);
|
|
1457
|
+
} else {
|
|
1458
|
+
descLines.push(line);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
flush();
|
|
1462
|
+
return { usage, description: descLines.join('\n').trim(), sections };
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
// Parse a columnar " <term> <description>" section (descriptions may wrap onto
|
|
1466
|
+
// indented continuation lines) into [{ term, desc }].
|
|
1467
|
+
const parseEntries = (text = '') => {
|
|
1468
|
+
const entries = [];
|
|
1469
|
+
for (const line of text.split('\n')) {
|
|
1470
|
+
if (!line.trim()) continue;
|
|
1471
|
+
const leading = line.length - line.trimStart().length;
|
|
1472
|
+
if (leading <= 2) {
|
|
1473
|
+
const rest = line.trim();
|
|
1474
|
+
const gap = rest.search(/\s{2,}/);
|
|
1475
|
+
entries.push(gap === -1 ? { term: rest, desc: '' } : { term: rest.slice(0, gap), desc: rest.slice(gap) });
|
|
1476
|
+
} else if (entries.length) {
|
|
1477
|
+
entries[entries.length - 1].desc += ` ${line.trim()}`;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return entries;
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
const table = (head, entries) =>
|
|
1484
|
+
!entries.length
|
|
1485
|
+
? ''
|
|
1486
|
+
: `| ${head[0]} | ${head[1]} |\n| --- | --- |\n` +
|
|
1487
|
+
entries.map(({ term, desc }) => `| \`${cell(term)}\` | ${cell(desc)} |`).join('\n') +
|
|
1488
|
+
'\n';
|
|
1489
|
+
|
|
1490
|
+
const detailSection = (sections, name, head) => {
|
|
1491
|
+
const t = table(head, parseEntries(sections[name]));
|
|
1492
|
+
return t ? `\n#### ${name}\n\n${t}` : '';
|
|
1493
|
+
};
|
|
1494
|
+
|
|
1495
|
+
// ── Top-level index ──
|
|
1496
|
+
const root = parseHelp(help());
|
|
1497
|
+
const commandEntries = parseEntries(root.sections['Commands']).filter((e) => e.term.split(' ')[0] !== 'help');
|
|
1498
|
+
|
|
1499
|
+
const index =
|
|
1500
|
+
`## Underpost CLI\n\n` +
|
|
1501
|
+
(root.description ? `> ${root.description.replace(/\s+/g, ' ')}\n\n` : '') +
|
|
1502
|
+
`**Usage:** \`${root.usage}\`\n\n` +
|
|
1503
|
+
`### Global options\n\n${table(['Option', 'Description'], parseEntries(root.sections['Options']))}\n` +
|
|
1504
|
+
`### Commands\n\n| Command | Description |\n| --- | --- |\n` +
|
|
1505
|
+
commandEntries
|
|
1506
|
+
.map((e) => {
|
|
1507
|
+
const name = e.term.split(' ')[0];
|
|
1508
|
+
return `| [\`${name}\`](#${anchor(name)}) | ${cell(e.desc)} |`;
|
|
1509
|
+
})
|
|
1510
|
+
.join('\n') +
|
|
1511
|
+
'\n';
|
|
1512
|
+
|
|
1513
|
+
// ── Per-command detail ──
|
|
1514
|
+
let details = `\n## Command reference\n`;
|
|
1515
|
+
for (const cmd of program.commands) {
|
|
1516
|
+
const name = cmd._name;
|
|
1517
|
+
if (name === 'help') continue;
|
|
1518
|
+
const cmdHelp = parseHelp(help(name));
|
|
1519
|
+
details +=
|
|
1520
|
+
`\n### underpost ${name}\n\n` +
|
|
1521
|
+
(cmdHelp.description ? `${cmdHelp.description.replace(/\s+/g, ' ')}\n\n` : '') +
|
|
1522
|
+
`**Usage:** \`${cmdHelp.usage}\`\n` +
|
|
1523
|
+
detailSection(cmdHelp.sections, 'Arguments', ['Argument', 'Description']) +
|
|
1524
|
+
detailSection(cmdHelp.sections, 'Options', ['Option', 'Description']) +
|
|
1525
|
+
`\n---\n`;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
const md = `${index}${details}`.replaceAll(oldVersion, newVersion);
|
|
1529
|
+
fs.writeFileSync(`./src/client/public/nexodev/docs/references/Command Line Interface.md`, md, 'utf8');
|
|
1530
|
+
fs.writeFileSync(`./CLI-HELP.md`, md, 'utf8');
|
|
1531
|
+
|
|
1532
|
+
// Update README.md: bump version and refresh the CLI index between the comment tags.
|
|
1533
|
+
let readme = fs.readFileSync(`./README.md`, 'utf8').replaceAll(oldVersion, newVersion);
|
|
1534
|
+
const cliStartTag = '<!-- cli-index-start -->';
|
|
1535
|
+
const cliEndTag = '<!-- cli-index-end -->';
|
|
1536
|
+
const startIdx = readme.indexOf(cliStartTag);
|
|
1537
|
+
const endIdx = readme.indexOf(cliEndTag);
|
|
1538
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
1539
|
+
const readmeIndex = index.replace(/\(#(underpost-[a-z0-9-]+)\)/g, '(CLI-HELP.md#$1)');
|
|
1540
|
+
readme =
|
|
1541
|
+
readme.substring(0, startIdx) +
|
|
1542
|
+
cliStartTag +
|
|
1543
|
+
'\n' +
|
|
1544
|
+
readmeIndex.replaceAll(oldVersion, newVersion) +
|
|
1545
|
+
'\n' +
|
|
1546
|
+
cliEndTag +
|
|
1547
|
+
readme.substring(endIdx + cliEndTag.length);
|
|
1548
|
+
}
|
|
1549
|
+
fs.writeFileSync('./README.md', readme, 'utf8');
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* @method getInstanceContext
|
|
1554
|
+
* @description Gets the instance context.
|
|
1555
|
+
* @param {object} options - The options.
|
|
1556
|
+
* @param {string} options.deployId - The deploy ID.
|
|
1557
|
+
* @param {boolean} options.singleReplica - The single replica.
|
|
1558
|
+
* @param {Array} options.replicas - The replicas.
|
|
1559
|
+
* @param {string} options.redirect - The redirect.
|
|
1560
|
+
* @param {boolean} [options.peer=false] - Whether peer is enabled on the parent singleReplica path (used for port offset estimation when replica conf is not yet built).
|
|
1561
|
+
* @returns {object} - The instance context.
|
|
1562
|
+
* @memberof ServerConfBuilder
|
|
1563
|
+
*/
|
|
1564
|
+
const getInstanceContext = async (options = { deployId, singleReplica, replicas, redirect: '', peer: false }) => {
|
|
1565
|
+
const { deployId, singleReplica, replicas, redirect, peer } = options;
|
|
1566
|
+
let singleReplicaOffsetPortSum = 0;
|
|
1567
|
+
|
|
1568
|
+
if (singleReplica && replicas && replicas.length > 0) {
|
|
1569
|
+
for (const replica of replicas) {
|
|
1570
|
+
const replicaDeployId = buildReplicaId({ deployId, replica });
|
|
1571
|
+
const replicaConfPath = `./engine-private/replica/${replicaDeployId}/conf.server.json`;
|
|
1572
|
+
if (!fs.existsSync(replicaConfPath)) {
|
|
1573
|
+
// Replica folder not built yet (e.g. dev mode without prior build);
|
|
1574
|
+
// estimate port offset: 1 per replica path + 1 extra if peer is enabled on the parent singleReplica config
|
|
1575
|
+
singleReplicaOffsetPortSum++;
|
|
1576
|
+
if (peer) singleReplicaOffsetPortSum++;
|
|
1577
|
+
continue;
|
|
1578
|
+
}
|
|
1579
|
+
const confReplicaServer = loadConfServerJson(replicaConfPath);
|
|
1580
|
+
for (const host of Object.keys(confReplicaServer)) {
|
|
1581
|
+
for (const path of Object.keys(confReplicaServer[host])) {
|
|
1582
|
+
singleReplicaOffsetPortSum++;
|
|
1583
|
+
if (confReplicaServer[host][path].peer) singleReplicaOffsetPortSum++;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
const redirectTarget = redirect
|
|
1590
|
+
? redirect[redirect.length - 1] === '/'
|
|
1591
|
+
? redirect.slice(0, -1)
|
|
1592
|
+
: redirect
|
|
1593
|
+
: undefined;
|
|
1594
|
+
|
|
1595
|
+
return { redirectTarget, singleReplicaOffsetPortSum };
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
/**
|
|
1599
|
+
* @method buildApiConf
|
|
1600
|
+
* @description Builds the API configuration.
|
|
1601
|
+
* @param {object} options - The options.
|
|
1602
|
+
* @param {string} options.deployId - The deploy ID.
|
|
1603
|
+
* @param {string} options.subConf - The sub configuration.
|
|
1604
|
+
* @param {string} options.host - The host.
|
|
1605
|
+
* @param {string} options.path - The path.
|
|
1606
|
+
* @param {string} options.origin - The origin.
|
|
1607
|
+
* @returns {object} - The API configuration.
|
|
1608
|
+
* @memberof ServerConfBuilder
|
|
1609
|
+
*/
|
|
1610
|
+
const buildApiConf = async (options = { deployId: '', subConf: '', host: '', path: '', origin: '' }) => {
|
|
1611
|
+
let { deployId, subConf, host, path, origin } = options;
|
|
1612
|
+
if (!deployId) deployId = process.argv[2].trim();
|
|
1613
|
+
if (!subConf) subConf = process.argv[3].trim();
|
|
1614
|
+
if (process.argv[4]) host = process.argv[4].trim();
|
|
1615
|
+
if (process.argv[5]) path = process.argv[5].trim();
|
|
1616
|
+
if (process.argv[6])
|
|
1617
|
+
origin = `${process.env.NODE_ENV === 'production' ? 'https' : 'http'}://${process.argv[6].trim()}`;
|
|
1618
|
+
|
|
1619
|
+
if (!origin) return;
|
|
1620
|
+
const confServer = JSON.parse(
|
|
1621
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`, 'utf8'),
|
|
1622
|
+
);
|
|
1623
|
+
const envObj = dotenv.parse(
|
|
1624
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}`, 'utf8'),
|
|
1625
|
+
);
|
|
1626
|
+
if (host && path) {
|
|
1627
|
+
confServer[host][path].origins = [origin];
|
|
1628
|
+
logger.info('Build api conf', { host, path, origin });
|
|
1629
|
+
} else return;
|
|
1630
|
+
writeEnv(`./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-api`, envObj);
|
|
1631
|
+
fs.writeFileSync(
|
|
1632
|
+
`./engine-private/conf/${deployId}/conf.server.dev.${subConf}-dev-api.json`,
|
|
1633
|
+
JSON.stringify(confServer, null, 4),
|
|
1634
|
+
'utf8',
|
|
1635
|
+
);
|
|
1636
|
+
};
|
|
1637
|
+
|
|
1638
|
+
/**
|
|
1639
|
+
* @method buildClientStaticConf
|
|
1640
|
+
* @description Builds the client static configuration.
|
|
1641
|
+
* @param {object} options - The options.
|
|
1642
|
+
* @param {string} options.deployId - The deploy ID.
|
|
1643
|
+
* @param {string} options.subConf - The sub configuration.
|
|
1644
|
+
* @param {string} options.apiBaseHost - The API base host.
|
|
1645
|
+
* @param {string} options.host - The host.
|
|
1646
|
+
* @param {string} options.path - The path.
|
|
1647
|
+
* @param {boolean} options.devProxy - The dev proxy flag.
|
|
1648
|
+
* @returns {void}
|
|
1649
|
+
* @memberof ServerConfBuilder
|
|
1650
|
+
*/
|
|
1651
|
+
const buildClientStaticConf = async (
|
|
1652
|
+
options = { deployId: '', subConf: '', apiBaseHost: '', host: '', path: '', devProxy: false },
|
|
1653
|
+
) => {
|
|
1654
|
+
let { deployId, subConf, host, path, devProxy } = options;
|
|
1655
|
+
if (!deployId) deployId = process.argv[2].trim();
|
|
1656
|
+
if (!subConf) subConf = process.argv[3].trim();
|
|
1657
|
+
if (!host) host = process.argv[4].trim();
|
|
1658
|
+
if (!path) path = process.argv[5].trim();
|
|
1659
|
+
const confServer = JSON.parse(
|
|
1660
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.dev.${subConf}-dev-api.json`, 'utf8'),
|
|
1661
|
+
);
|
|
1662
|
+
const envObj = dotenv.parse(
|
|
1663
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-api`, 'utf8'),
|
|
1664
|
+
);
|
|
1665
|
+
envObj.PORT = parseInt(envObj.PORT);
|
|
1666
|
+
const apiBaseHost = devProxy
|
|
1667
|
+
? devProxyHostFactory({ host, tls: isTlsDevProxy() })
|
|
1668
|
+
: options?.apiBaseHost
|
|
1669
|
+
? options.apiBaseHost
|
|
1670
|
+
: `localhost:${envObj.PORT + 1}`;
|
|
1671
|
+
confServer[host][path].apiBaseHost = apiBaseHost;
|
|
1672
|
+
confServer[host][path].apiBaseProxyPath = path;
|
|
1673
|
+
logger.warn('Build client static conf', { host, path, apiBaseHost });
|
|
1674
|
+
envObj.PORT = parseInt(confServer[host][path].origins[0].split(':')[2]) - 1;
|
|
1675
|
+
writeEnv(`./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-client`, envObj);
|
|
1676
|
+
fs.writeFileSync(
|
|
1677
|
+
`./engine-private/conf/${deployId}/conf.server.dev.${subConf}-dev-client.json`,
|
|
1678
|
+
JSON.stringify(confServer, null, 4),
|
|
1679
|
+
'utf8',
|
|
1680
|
+
);
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* @method isDeployRunnerContext
|
|
1685
|
+
* @description Checks if the deploy runner context is valid.
|
|
1686
|
+
* @param {string} path - The path.
|
|
1687
|
+
* @param {object} options - The options.
|
|
1688
|
+
* @returns {boolean} - The deploy runner context.
|
|
1689
|
+
* @memberof ServerConfBuilder
|
|
1690
|
+
*/
|
|
1691
|
+
const isDeployRunnerContext = (path, options) => !options.build && path && path !== 'template-deploy';
|
|
1692
|
+
|
|
1693
|
+
/**
|
|
1694
|
+
* @method isDevProxyContext
|
|
1695
|
+
* @description Checks if the dev proxy context is valid.
|
|
1696
|
+
* @returns {boolean} - The dev proxy context.
|
|
1697
|
+
* @memberof ServerConfBuilder
|
|
1698
|
+
*/
|
|
1699
|
+
const isDevProxyContext = () => (process.argv.find((arg) => arg === 'proxy') ? true : false);
|
|
1700
|
+
|
|
1701
|
+
/**
|
|
1702
|
+
* @method devProxyHostFactory
|
|
1703
|
+
* @description Creates the dev proxy host.
|
|
1704
|
+
* @param {object} options - The options.
|
|
1705
|
+
* @param {string} [options.host='default.net'] - The host.
|
|
1706
|
+
* @param {boolean} [options.includeHttp=false] - Whether to include HTTP.
|
|
1707
|
+
* @param {number} [options.port=443] - The port.
|
|
1708
|
+
* @param {boolean} [options.tls=false] - Whether to use TLS.
|
|
1709
|
+
* @returns {string} - The dev proxy host.
|
|
1710
|
+
* @memberof ServerConfBuilder
|
|
1711
|
+
*/
|
|
1712
|
+
const devProxyHostFactory = (options = { host: 'default.net', includeHttp: false, port: 80, tls: false }) => {
|
|
1713
|
+
const resolvedPort =
|
|
1714
|
+
(options.port ? options.port : options.tls ? 443 : 80) + parseInt(process.env.DEV_PROXY_PORT_OFFSET);
|
|
1715
|
+
const isDefaultPort = (options.tls && resolvedPort === 443) || (!options.tls && resolvedPort === 80);
|
|
1716
|
+
const protocol = options.includeHttp ? (options.tls ? 'https://' : 'http://') : '';
|
|
1717
|
+
const hostname = options.host ? options.host : 'localhost';
|
|
1718
|
+
return `${protocol}${hostname}${isDefaultPort ? '' : `:${resolvedPort}`}`;
|
|
1719
|
+
};
|
|
1720
|
+
|
|
1721
|
+
/**
|
|
1722
|
+
* @method isTlsDevProxy
|
|
1723
|
+
* @description Checks if TLS is used in the dev proxy.
|
|
1724
|
+
* @returns {boolean} - The TLS dev proxy status.
|
|
1725
|
+
* @memberof ServerConfBuilder
|
|
1726
|
+
*/
|
|
1727
|
+
const isTlsDevProxy = () => process.env.NODE_ENV !== 'production' && !!process.argv.find((arg) => arg === 'tls');
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* @method getTlsHosts
|
|
1731
|
+
* @description Gets the TLS hosts.
|
|
1732
|
+
* @param {object} confServer - The server configuration.
|
|
1733
|
+
* @returns {Array} - The TLS hosts.
|
|
1734
|
+
* @memberof ServerConfBuilder
|
|
1735
|
+
*/
|
|
1736
|
+
const getTlsHosts = (confServer) =>
|
|
1737
|
+
Array.from(new Set(Object.keys(confServer).map((h) => new URL('https://' + h).hostname)));
|
|
1738
|
+
|
|
1739
|
+
/**
|
|
1740
|
+
* Reads a `conf.server.json` file from disk, parses it, and resolves all `env:` secret
|
|
1741
|
+
* references using {@link resolveConfSecrets}.
|
|
1742
|
+
*
|
|
1743
|
+
* Reads and parses a `conf.server.json` file from disk. The `env:` secret
|
|
1744
|
+
* references are **preserved** by default so that build/deploy tooling never
|
|
1745
|
+
* accidentally strips them. Callers that need the actual secret values
|
|
1746
|
+
* (e.g. database or mailer modules) should explicitly wrap the result with
|
|
1747
|
+
* {@link resolveConfSecrets}.
|
|
1748
|
+
*
|
|
1749
|
+
* @method loadConfServerJson
|
|
1750
|
+
* @param {string} jsonPath - Absolute or relative path to the `conf.server.json` file.
|
|
1751
|
+
* @param {object} [options] - Optional settings.
|
|
1752
|
+
* @param {boolean} [options.resolve=false] - When `true`, resolves `env:` references
|
|
1753
|
+
* via {@link resolveConfSecrets} before returning.
|
|
1754
|
+
* @returns {object} The parsed server configuration object (secrets unresolved unless
|
|
1755
|
+
* `options.resolve` is `true`).
|
|
1756
|
+
* @throws {Error} If the file does not exist or cannot be parsed.
|
|
1757
|
+
* @memberof ServerConfBuilder
|
|
1758
|
+
*
|
|
1759
|
+
* @example
|
|
1760
|
+
* // Structure-only read (env: strings preserved)
|
|
1761
|
+
* const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
|
|
1762
|
+
*
|
|
1763
|
+
* @example
|
|
1764
|
+
* // Resolved read (env: strings replaced with process.env values)
|
|
1765
|
+
* const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`, { resolve: true });
|
|
1766
|
+
*/
|
|
1767
|
+
const loadConfServerJson = (jsonPath, options) => {
|
|
1768
|
+
if (!fs.existsSync(jsonPath)) {
|
|
1769
|
+
throw new Error(`loadConfServerJson: configuration file not found: ${jsonPath}`);
|
|
1770
|
+
}
|
|
1771
|
+
const raw = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
1772
|
+
return options && options.resolve === true ? resolveConfSecrets(raw) : raw;
|
|
1773
|
+
};
|
|
1774
|
+
|
|
1775
|
+
/**
|
|
1776
|
+
* @method deepReplaceToken
|
|
1777
|
+
* @description Recursively replaces every occurrence of `from` with `to` in all
|
|
1778
|
+
* string leaves of a JSON-shaped value, returning a new structure.
|
|
1779
|
+
* @param {*} value - Any JSON-serialisable value.
|
|
1780
|
+
* @param {string} from - Token to replace.
|
|
1781
|
+
* @param {string} to - Replacement token.
|
|
1782
|
+
* @returns {*} A structurally identical value with the token replaced.
|
|
1783
|
+
* @memberof ServerConfBuilder
|
|
1784
|
+
*/
|
|
1785
|
+
const deepReplaceToken = (value, from, to) => {
|
|
1786
|
+
if (typeof value === 'string') return value.split(from).join(to);
|
|
1787
|
+
if (Array.isArray(value)) return value.map((entry) => deepReplaceToken(entry, from, to));
|
|
1788
|
+
if (value && typeof value === 'object')
|
|
1789
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, deepReplaceToken(v, from, to)]));
|
|
1790
|
+
return value;
|
|
1791
|
+
};
|
|
1792
|
+
|
|
1793
|
+
/**
|
|
1794
|
+
* @method readConfInstances
|
|
1795
|
+
* @description Reads `conf.instances.json` and returns the bare array of instance
|
|
1796
|
+
* entries. The canonical shape is a plain array; the historical `{ instances }`
|
|
1797
|
+
* object wrapper is still unwrapped for backward compatibility. Multi-instance is
|
|
1798
|
+
* declared per entry under `entry.multiInstance` (not deploy-wide).
|
|
1799
|
+
* @param {string} deployId - Deployment identifier (e.g. `dd-cyberia`).
|
|
1800
|
+
* @returns {Array<object>} Instance entries.
|
|
1801
|
+
* @memberof ServerConfBuilder
|
|
1802
|
+
*/
|
|
1803
|
+
const readConfInstances = (deployId) => {
|
|
1804
|
+
const raw = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.instances.json`, 'utf8'));
|
|
1805
|
+
return Array.isArray(raw) ? raw : raw.instances || [];
|
|
1806
|
+
};
|
|
1807
|
+
|
|
1808
|
+
/**
|
|
1809
|
+
* @method loadInstanceTopology
|
|
1810
|
+
* @description Returns `{ default, variants }` describing the deploy's instance
|
|
1811
|
+
* variants, or `null` when the deploy is single-instance. The topology is
|
|
1812
|
+
* declared per instance entry (`entry.multiInstance.default` / `.variants`); all
|
|
1813
|
+
* multi-instance entries share the same variant set, so this returns it from the
|
|
1814
|
+
* first entry that declares one.
|
|
1815
|
+
* @param {string} deployId - Deployment identifier (e.g. `dd-cyberia`).
|
|
1816
|
+
* @returns {?{default: string, variants: Array<object>}} The topology, or `null`.
|
|
1817
|
+
* @memberof ServerConfBuilder
|
|
1818
|
+
*/
|
|
1819
|
+
const loadInstanceTopology = (deployId) => {
|
|
1820
|
+
for (const entry of readConfInstances(deployId)) {
|
|
1821
|
+
const mi = entry.multiInstance;
|
|
1822
|
+
if (mi && Array.isArray(mi.variants) && mi.variants.length > 0)
|
|
1823
|
+
return { default: mi.default || mi.variants[0].code, variants: mi.variants };
|
|
1824
|
+
}
|
|
1825
|
+
return null;
|
|
1826
|
+
};
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* @method resolveInstanceEnvValue
|
|
1830
|
+
* @description Resolves one declared env value. A plain string is used verbatim;
|
|
1831
|
+
* an object is treated as env-scoped (`{ development, production }`), matching the
|
|
1832
|
+
* convention already used by `lifecycle` / `readinessProbe` / `livenessProbe`.
|
|
1833
|
+
* Placeholders are substituted from the variant tokens.
|
|
1834
|
+
* @param {string|object} value - Declared value.
|
|
1835
|
+
* @param {string} env - `development` | `production`.
|
|
1836
|
+
* @param {Object<string,string>} tokens - Placeholder name → replacement.
|
|
1837
|
+
* @returns {?string} Resolved value, or `null` when the env has no entry.
|
|
1838
|
+
* @memberof ServerConfBuilder
|
|
1839
|
+
*/
|
|
1840
|
+
const resolveInstanceEnvValue = (value, env, tokens) => {
|
|
1841
|
+
const scoped = value && typeof value === 'object' && !Array.isArray(value) ? value[env] : value;
|
|
1842
|
+
if (scoped === undefined || scoped === null) return null;
|
|
1843
|
+
return `${scoped}`.replace(/\{\{(\w+)\}\}/g, (match, token) => (token in tokens ? tokens[token] : match));
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* @method loadConfInstances
|
|
1848
|
+
* @description Loads `conf.instances.json` and expands every entry carrying a
|
|
1849
|
+
* `multiInstance` block into one concrete instance per declared variant.
|
|
1850
|
+
*
|
|
1851
|
+
* A template entry is never deployed as-is once variants exist: each variant
|
|
1852
|
+
* produces its own entry whose id, env file path, volume mount and
|
|
1853
|
+
* container-status strings are derived by replacing the template id token
|
|
1854
|
+
* throughout. The variant whose `slug` is empty keeps the template id verbatim,
|
|
1855
|
+
* so pre-existing deployments, PVCs and env directories survive the move to
|
|
1856
|
+
* multi-instance untouched.
|
|
1857
|
+
*
|
|
1858
|
+
* Nothing here is application-specific: the variant set (`default` + `variants`),
|
|
1859
|
+
* which env keys an instance needs (`env`), and prefix-stripping (`stripPathPrefix`)
|
|
1860
|
+
* are all declared per entry under `entry.multiInstance`. Env values may use the
|
|
1861
|
+
* `{{code}}`, `{{slug}}`, `{{path}}`, `{{id}}` and `{{default}}` placeholders and
|
|
1862
|
+
* may be env-scoped objects.
|
|
1863
|
+
*
|
|
1864
|
+
* Every expanded entry carries three extra fields consumed by the deploy runners:
|
|
1865
|
+
* `instanceCode` (the variant this instance serves), `templateId` (so targeting
|
|
1866
|
+
* the template id acts on the whole family) and `instanceEnv` (the resolved env
|
|
1867
|
+
* keys to write, keyed by environment: `{ development, production }`, so a build
|
|
1868
|
+
* in either mode can emit a complete env directory).
|
|
1869
|
+
*
|
|
1870
|
+
* @param {string} deployId - Deployment identifier (e.g. `dd-cyberia`).
|
|
1871
|
+
* @returns {Array<object>} Expanded instance entries.
|
|
1872
|
+
* @memberof ServerConfBuilder
|
|
1873
|
+
*/
|
|
1874
|
+
const INSTANCE_ENVS = ['development', 'production'];
|
|
1875
|
+
|
|
1876
|
+
const loadConfInstances = (deployId) => {
|
|
1877
|
+
const expanded = [];
|
|
1878
|
+
for (const entry of readConfInstances(deployId)) {
|
|
1879
|
+
const spec = entry.multiInstance;
|
|
1880
|
+
const variants = spec?.variants;
|
|
1881
|
+
if (!Array.isArray(variants) || 0 === variants.length) {
|
|
1882
|
+
expanded.push(entry);
|
|
1883
|
+
continue;
|
|
1884
|
+
}
|
|
1885
|
+
for (const variant of variants) {
|
|
1886
|
+
const id = variant.slug ? `${entry.id}-${variant.slug}` : entry.id;
|
|
1887
|
+
const instance = variant.slug ? deepReplaceToken(entry, entry.id, id) : JSON.parse(JSON.stringify(entry));
|
|
1888
|
+
delete instance.multiInstance;
|
|
1889
|
+
instance.id = id;
|
|
1890
|
+
instance.path = variant.path;
|
|
1891
|
+
instance.instanceCode = variant.code;
|
|
1892
|
+
instance.templateId = entry.id;
|
|
1893
|
+
|
|
1894
|
+
const tokens = {
|
|
1895
|
+
code: variant.code,
|
|
1896
|
+
slug: variant.slug || '',
|
|
1897
|
+
path: variant.path,
|
|
1898
|
+
id,
|
|
1899
|
+
default: spec.default || '',
|
|
1900
|
+
};
|
|
1901
|
+
// Resolve the declared env keys for both environments so a build in either
|
|
1902
|
+
// mode writes a complete env directory (development.env + production.env).
|
|
1903
|
+
instance.instanceEnv = Object.fromEntries(INSTANCE_ENVS.map((e) => [e, {}]));
|
|
1904
|
+
for (const [key, value] of Object.entries(spec.env || {}))
|
|
1905
|
+
for (const e of INSTANCE_ENVS) {
|
|
1906
|
+
const resolved = resolveInstanceEnvValue(value, e, tokens);
|
|
1907
|
+
if (resolved !== null) instance.instanceEnv[e][key] = resolved;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// A backend that serves its routes at the root knows nothing about the
|
|
1911
|
+
// variant prefix — it is selected by env instead. Strip the prefix at the
|
|
1912
|
+
// proxy so the runtime stays instance-agnostic.
|
|
1913
|
+
if (spec.stripPathPrefix && variant.path !== '/')
|
|
1914
|
+
instance.pathRewritePolicy = [{ prefix: variant.path, replacement: '/' }];
|
|
1915
|
+
expanded.push(instance);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
return expanded;
|
|
1919
|
+
};
|
|
1920
|
+
|
|
1921
|
+
/**
|
|
1922
|
+
* @method selectConfInstances
|
|
1923
|
+
* @description Filters expanded instances for a deploy target. Targeting a
|
|
1924
|
+
* template id (`mmo-server`) selects the whole instance family; targeting a
|
|
1925
|
+
* concrete id (`mmo-server-forest`) selects just that one.
|
|
1926
|
+
* @param {Array<object>} instances - Expanded entries from {@link loadConfInstances}.
|
|
1927
|
+
* @param {string} id - Target instance id or template id.
|
|
1928
|
+
* @returns {Array<object>} Matching entries.
|
|
1929
|
+
* @memberof ServerConfBuilder
|
|
1930
|
+
*/
|
|
1931
|
+
const selectConfInstances = (instances, id) =>
|
|
1932
|
+
instances.filter((instance) => instance.id === id || instance.templateId === id);
|
|
1933
|
+
|
|
1934
|
+
/**
|
|
1935
|
+
* Creates and writes the /etc/hosts file for a deployment.
|
|
1936
|
+
* @method etcHostFactory
|
|
1937
|
+
* @param {Array<string>} hosts - List of hosts to be added to the hosts file.
|
|
1938
|
+
* @param {object} options - Options for the hosts file creation.
|
|
1939
|
+
* @param {boolean} options.append - Whether to append to the existing hosts file.
|
|
1940
|
+
* @returns {object} - Object containing the rendered hosts file.
|
|
1941
|
+
* @memberof ServerConfBuilder
|
|
1942
|
+
*/
|
|
1943
|
+
const etcHostFactory = (hosts = [], options = { append: false }) => {
|
|
1944
|
+
hosts = hosts.map((host) => {
|
|
1945
|
+
try {
|
|
1946
|
+
if (!host.startsWith('http')) host = `http://${host}`;
|
|
1947
|
+
const hostname = new URL(host).hostname;
|
|
1948
|
+
logger.info('Hostname extract valid', { host, hostname });
|
|
1949
|
+
return hostname;
|
|
1950
|
+
} catch (e) {
|
|
1951
|
+
logger.warn('No hostname extract valid', host);
|
|
1952
|
+
return host;
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
const renderHosts = `127.0.0.1 ${hosts.join(
|
|
1956
|
+
' ',
|
|
1957
|
+
)} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
1958
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
1959
|
+
|
|
1960
|
+
if (options && options.append && fs.existsSync(`/etc/hosts`)) {
|
|
1961
|
+
fs.writeFileSync(
|
|
1962
|
+
`/etc/hosts`,
|
|
1963
|
+
fs.readFileSync(`/etc/hosts`, 'utf8') +
|
|
1964
|
+
`
|
|
1965
|
+
${renderHosts}`,
|
|
1966
|
+
'utf8',
|
|
1967
|
+
);
|
|
1968
|
+
} else fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
1969
|
+
return { renderHosts };
|
|
1970
|
+
};
|
|
1971
|
+
|
|
1972
|
+
/**
|
|
1973
|
+
* Resolves the concrete deploy ids a build or conf-sync run should iterate over.
|
|
1974
|
+
*
|
|
1975
|
+
* The meta deploy id `dd` fans out to the comma separated ids declared in
|
|
1976
|
+
* `engine-private/deploy/dd.router`; any other value is parsed as a comma separated list.
|
|
1977
|
+
* Entries are trimmed and empties dropped.
|
|
1978
|
+
*
|
|
1979
|
+
* @method resolveDeployList
|
|
1980
|
+
* @param {string} deployId - A deploy id, a comma separated list, or the `dd` meta id.
|
|
1981
|
+
* @returns {string[]} Ordered list of concrete deploy ids.
|
|
1982
|
+
* @memberof ServerConfBuilder
|
|
1983
|
+
*/
|
|
1984
|
+
const resolveDeployList = (deployId) =>
|
|
1985
|
+
(deployId === 'dd' ? fs.readFileSync('./engine-private/deploy/dd.router', 'utf8') : deployId)
|
|
1986
|
+
.split(',')
|
|
1987
|
+
.map((id) => id.trim())
|
|
1988
|
+
.filter(Boolean);
|
|
1989
|
+
|
|
1990
|
+
/**
|
|
1991
|
+
* Syncs a single deploy id's private configuration into its dedicated
|
|
1992
|
+
* `engine-<suffix>-private` repository and pushes the result.
|
|
1993
|
+
*
|
|
1994
|
+
* Idempotent and safe to rerun: the private repo is cloned when missing or reset to a clean
|
|
1995
|
+
* checkout when present, then the deploy id's `conf` folder, matching `replica` and
|
|
1996
|
+
* `itc-scripts` entries, and any caller-supplied `extraPaths` payloads are mirrored. The
|
|
1997
|
+
* commit/push step is a no-op when nothing changed (`silentOnError`).
|
|
1998
|
+
*
|
|
1999
|
+
* @method syncPrivateConf
|
|
2000
|
+
* @param {string} deployId - A concrete deploy id (e.g. `dd-cyberia`), not the `dd` meta id.
|
|
2001
|
+
* @param {string[]} [extraPaths=[]] - Extra `./engine-private` payload paths to mirror (from the
|
|
2002
|
+
* deploy's product catalog), kept out of this module so it stays product-agnostic.
|
|
2003
|
+
* @returns {void}
|
|
2004
|
+
* @memberof ServerConfBuilder
|
|
2005
|
+
*/
|
|
2006
|
+
const syncPrivateConf = (deployId, extraPaths = []) => {
|
|
2007
|
+
const suffix = deployId.split('dd-')[1];
|
|
2008
|
+
const privateRepoName = `engine-${suffix}-private`;
|
|
2009
|
+
const privateGitUri = `${process.env.GITHUB_USERNAME}/${privateRepoName}`;
|
|
2010
|
+
const privateRepoPath = `../${privateRepoName}`;
|
|
2011
|
+
|
|
2012
|
+
if (!fs.existsSync(privateRepoPath)) {
|
|
2013
|
+
shellExec(`cd .. && underpost clone ${privateGitUri}`, { silent: true });
|
|
2014
|
+
} else {
|
|
2015
|
+
shellExec(`git config --global --add safe.directory '${dir.resolve(privateRepoPath)}'`);
|
|
2016
|
+
shellExec(`cd ${privateRepoPath} && git checkout . && git clean -f -d && underpost pull . ${privateGitUri}`, {
|
|
2017
|
+
silent: true,
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
const confDest = `${privateRepoPath}/conf/${deployId}`;
|
|
2022
|
+
fs.removeSync(confDest);
|
|
2023
|
+
fs.mkdirSync(confDest, { recursive: true });
|
|
2024
|
+
fs.copySync(`./engine-private/conf/${deployId}`, confDest);
|
|
2025
|
+
|
|
2026
|
+
fs.removeSync(`${privateRepoPath}/replica`);
|
|
2027
|
+
for (const payloadDir of ['replica', 'itc-scripts']) {
|
|
2028
|
+
const srcDir = `./engine-private/${payloadDir}`;
|
|
2029
|
+
if (!fs.existsSync(srcDir)) continue;
|
|
2030
|
+
for (const entry of fs.readdirSync(srcDir))
|
|
2031
|
+
if (entry.match(deployId)) fs.copySync(`${srcDir}/${entry}`, `${privateRepoPath}/${payloadDir}/${entry}`);
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
for (const extraPath of extraPaths) fs.copySync(`./engine-private/${extraPath}`, `${privateRepoPath}/${extraPath}`);
|
|
2035
|
+
|
|
2036
|
+
shellExec(
|
|
2037
|
+
`cd ${privateRepoPath}` +
|
|
2038
|
+
` && git add .` +
|
|
2039
|
+
` && underpost cmt . ci engine-core-conf 'Update ${deployId} conf'` +
|
|
2040
|
+
` && underpost push . ${privateGitUri}`,
|
|
2041
|
+
{ silent: true, silentOnError: true },
|
|
2042
|
+
);
|
|
2043
|
+
};
|
|
2044
|
+
|
|
2045
|
+
/**
|
|
2046
|
+
* Moves a deploy's public template sources into the engine working tree ahead of
|
|
2047
|
+
* the build copy step. Idempotent and safe to rerun: each move is guarded by
|
|
2048
|
+
* `existsSync`, so already-moved or absent sources are skipped rather than throwing.
|
|
2049
|
+
* The `[src, dest]` pairs come from the deploy's product catalog (passed in), so
|
|
2050
|
+
* this module stays product-agnostic.
|
|
2051
|
+
*
|
|
2052
|
+
* @method syncDeployIdSources
|
|
2053
|
+
* @param {Array<[string, string]>} [sourceMoves=[]] - Public `[src, dest]` move pairs.
|
|
2054
|
+
* @returns {boolean} `true` when any sources were declared, else `false`.
|
|
2055
|
+
* @memberof ServerConfBuilder
|
|
2056
|
+
*/
|
|
2057
|
+
const syncDeployIdSources = (sourceMoves = []) => {
|
|
2058
|
+
if (!sourceMoves.length) return false;
|
|
2059
|
+
for (const dir of ['src/api', 'src/client/components', 'src/client/public', 'src/client/services'])
|
|
2060
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
2061
|
+
for (const [src, dest] of sourceMoves) if (fs.existsSync(src)) fs.moveSync(src, dest, { overwrite: true });
|
|
2062
|
+
return true;
|
|
2063
|
+
};
|
|
2064
|
+
|
|
2065
|
+
/**
|
|
2066
|
+
* Rebuilds the standalone `pwa-microservices-template` from scratch out of the current
|
|
2067
|
+
* engine source tree.
|
|
2068
|
+
*
|
|
2069
|
+
* Clones the template repo next to the engine when missing, otherwise resets it to a clean
|
|
2070
|
+
* pristine checkout, then syncs every engine-tracked file the template is allowed to carry
|
|
2071
|
+
* ({@link validateTemplatePath}), strips engine-only + product modules, restores the template's
|
|
2072
|
+
* own CI workflows + guest services, and rewrites `package.json` / `package-lock.json` / `README`
|
|
2073
|
+
* so the result is a standalone, installable project. Throws on failure; callers own exit codes.
|
|
2074
|
+
*
|
|
2075
|
+
* Product catalogs are read dynamically ({@link module:src/server/catalog} `loadProductCatalogs`),
|
|
2076
|
+
* so this stays decoupled from — and survives removal of — any product module.
|
|
2077
|
+
*
|
|
2078
|
+
* @method buildTemplate
|
|
2079
|
+
* @param {object} [options]
|
|
2080
|
+
* @param {string} [options.srcPath='./'] - Engine source root to sync from.
|
|
2081
|
+
* @param {string} [options.toPath='../pwa-microservices-template'] - Template output path.
|
|
2082
|
+
* @returns {Promise<void>}
|
|
2083
|
+
* @memberof ServerConfBuilder
|
|
2084
|
+
*/
|
|
2085
|
+
const buildTemplate = async ({ srcPath = './', toPath = '../pwa-microservices-template' } = {}) => {
|
|
2086
|
+
const walk = (await import('ignore-walk')).default;
|
|
2087
|
+
const { TEMPLATE_RESTORE_PATHS, TEMPLATE_KEYWORDS, TEMPLATE_DESCRIPTION } =
|
|
2088
|
+
await import('../projects/underpost/catalog-underpost.js');
|
|
2089
|
+
const { loadProductCatalogs } = await import('./catalog.js');
|
|
2090
|
+
const githubUsername = process.env.GITHUB_USERNAME;
|
|
2091
|
+
|
|
2092
|
+
logger.info('Build template', { srcPath, toPath });
|
|
2093
|
+
|
|
2094
|
+
const sourceFiles = (
|
|
2095
|
+
await new Promise((resolve) =>
|
|
2096
|
+
walk({ path: srcPath, ignoreFiles: [`.gitignore`], includeEmpty: false, follow: false }, (...args) =>
|
|
2097
|
+
resolve(args[1]),
|
|
2098
|
+
),
|
|
2099
|
+
)
|
|
2100
|
+
).filter((p) => !p.startsWith('.git'));
|
|
2101
|
+
|
|
2102
|
+
fs.removeSync(`${githubUsername}/pwa-microservices-template`);
|
|
2103
|
+
shellExec(`cd .. && node engine/bin clone ${githubUsername}/pwa-microservices-template`);
|
|
2104
|
+
|
|
2105
|
+
shellExec(`cd ${toPath} && git config core.filemode false`);
|
|
2106
|
+
|
|
2107
|
+
for (const copyPath of sourceFiles) {
|
|
2108
|
+
if (copyPath === 'NaN') continue;
|
|
2109
|
+
const absolutePath = `${srcPath}/${copyPath}`;
|
|
2110
|
+
if (!validateTemplatePath(absolutePath)) continue;
|
|
2111
|
+
|
|
2112
|
+
const folder = getDirname(`${toPath}/${copyPath}`);
|
|
2113
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
2114
|
+
|
|
2115
|
+
logger.info('build', `${toPath}/${copyPath}`);
|
|
2116
|
+
fs.copyFileSync(absolutePath, `${toPath}/${copyPath}`);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
fs.copySync(`./.vscode`, `${toPath}/.vscode`);
|
|
2120
|
+
fs.copySync(`./src/client/public/default`, `${toPath}/src/client/public/default`);
|
|
2121
|
+
|
|
2122
|
+
// Preserve the template's own README + package.json identity before merging engine metadata.
|
|
2123
|
+
for (const checkoutPath of ['README.md', 'package.json']) shellExec(`cd ${toPath} && git checkout ${checkoutPath}`);
|
|
2124
|
+
|
|
2125
|
+
// Strip each product catalog's `stripPaths` (aggregated dynamically) plus the engine-only
|
|
2126
|
+
// workflows, deploy manifests, and product catalog modules.
|
|
2127
|
+
const productStripPaths = (await loadProductCatalogs()).flatMap((c) => c.stripPaths);
|
|
2128
|
+
for (const deletePath of productStripPaths) {
|
|
2129
|
+
const target = `${toPath}/${deletePath}`;
|
|
2130
|
+
if (fs.existsSync(target)) fs.removeSync(target);
|
|
2131
|
+
}
|
|
2132
|
+
shellExec(`rm -rf ${toPath}/.github`);
|
|
2133
|
+
shellExec(`rm -rf ${toPath}/manifests/deployment/dd-*`);
|
|
2134
|
+
|
|
2135
|
+
fs.mkdirSync(`${toPath}/.github/workflows`, { recursive: true });
|
|
2136
|
+
for (const restorePath of TEMPLATE_RESTORE_PATHS) {
|
|
2137
|
+
const dest = `${toPath}/${restorePath}`;
|
|
2138
|
+
if (fs.statSync(restorePath).isDirectory()) fs.copySync(restorePath, dest, { overwrite: true });
|
|
2139
|
+
else fs.copyFileSync(restorePath, dest);
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
// ── package.json: take engine deps/scripts/version, keep template identity. ──
|
|
2143
|
+
const originPackageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
2144
|
+
const templatePackageJson = JSON.parse(fs.readFileSync(`${toPath}/package.json`, 'utf8'));
|
|
2145
|
+
const templateName = templatePackageJson.name;
|
|
2146
|
+
|
|
2147
|
+
templatePackageJson.dependencies = originPackageJson.dependencies;
|
|
2148
|
+
templatePackageJson.devDependencies = originPackageJson.devDependencies;
|
|
2149
|
+
templatePackageJson.version = originPackageJson.version;
|
|
2150
|
+
templatePackageJson.scripts = originPackageJson.scripts;
|
|
2151
|
+
templatePackageJson.overrides = originPackageJson.overrides;
|
|
2152
|
+
templatePackageJson.name = templateName;
|
|
2153
|
+
templatePackageJson.description = TEMPLATE_DESCRIPTION;
|
|
2154
|
+
templatePackageJson.keywords = TEMPLATE_KEYWORDS;
|
|
2155
|
+
delete templatePackageJson.scripts['build:template'];
|
|
2156
|
+
fs.writeFileSync(`${toPath}/package.json`, JSON.stringify(templatePackageJson, null, 4), 'utf8');
|
|
2157
|
+
|
|
2158
|
+
// ── package-lock.json: mirror engine packages, keep template name/version on the root entry. ──
|
|
2159
|
+
const originPackageLockJson = JSON.parse(fs.readFileSync('./package-lock.json', 'utf8'));
|
|
2160
|
+
const templatePackageLockJson = JSON.parse(fs.readFileSync(`${toPath}/package-lock.json`, 'utf8'));
|
|
2161
|
+
const originBasePackageLock = newInstance(templatePackageLockJson.packages['']);
|
|
2162
|
+
templatePackageLockJson.name = templateName;
|
|
2163
|
+
templatePackageLockJson.version = originPackageLockJson.version;
|
|
2164
|
+
templatePackageLockJson.packages = originPackageLockJson.packages;
|
|
2165
|
+
templatePackageLockJson.packages[''].name = templateName;
|
|
2166
|
+
templatePackageLockJson.packages[''].version = originPackageLockJson.version;
|
|
2167
|
+
templatePackageLockJson.packages[''].hasInstallScript = originBasePackageLock.hasInstallScript;
|
|
2168
|
+
templatePackageLockJson.packages[''].license = originBasePackageLock.license;
|
|
2169
|
+
fs.writeFileSync(`${toPath}/package-lock.json`, JSON.stringify(templatePackageLockJson, null, 4), 'utf8');
|
|
2170
|
+
|
|
2171
|
+
fs.writeFileSync(
|
|
2172
|
+
`${toPath}/README.md`,
|
|
2173
|
+
fs
|
|
2174
|
+
.readFileSync('./README.md', 'utf8')
|
|
2175
|
+
.replace('<!-- template-title -->', '#### Base template for pwa/api-rest projects.'),
|
|
2176
|
+
'utf8',
|
|
2177
|
+
);
|
|
2178
|
+
};
|
|
2179
|
+
|
|
2180
|
+
const updatePrivateTemplateRepo = async () => {
|
|
2181
|
+
const templatePath = '/home/dd/pwa-microservices-template';
|
|
2182
|
+
shellExec(`sudo rm -rf ${templatePath}
|
|
2183
|
+
cd /home/dd/engine && npm run build:template
|
|
2184
|
+
cd /home/dd
|
|
2185
|
+
underpost clone --bare underpostnet/pwa-microservices-template-private
|
|
2186
|
+
sudo rm -rf ${templatePath}/.git
|
|
2187
|
+
mv ./pwa-microservices-template-private.git ${templatePath}/.git
|
|
2188
|
+
cd ${templatePath}
|
|
2189
|
+
npm install --omit=dev --ignore-scripts
|
|
2190
|
+
git init
|
|
2191
|
+
git config user.name 'underpostnet'
|
|
2192
|
+
git config user.email 'development@underpost.net'
|
|
2193
|
+
git add .`);
|
|
2194
|
+
const hasChanges = shellExec(`node bin cmt ${templatePath} --has-changes`, {
|
|
2195
|
+
stdout: true,
|
|
2196
|
+
silent: true,
|
|
2197
|
+
disableLog: true,
|
|
2198
|
+
}).trim();
|
|
2199
|
+
if (hasChanges === '1') {
|
|
2200
|
+
shellExec(
|
|
2201
|
+
`cd ${templatePath} && git commit -m 'Update template' && underpost push . underpostnet/pwa-microservices-template-private`,
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
};
|
|
2205
|
+
|
|
2206
|
+
/**
|
|
2207
|
+
* @method updatePrivateEngineTestRepo
|
|
2208
|
+
* @description Publishes a deploy id's freshly assembled template to its private
|
|
2209
|
+
* **test** source repo `engine-test-<idPart>` (separate from the production
|
|
2210
|
+
* `engine-<idPart>`). A pod started with `underpost start --build --private-test-repo`
|
|
2211
|
+
* clones this repo, so work-in-progress engine source can be tested end to end
|
|
2212
|
+
* without touching the production source. Mirrors {@link updatePrivateTemplateRepo}
|
|
2213
|
+
* but per-deploy-id and against the test repo.
|
|
2214
|
+
*
|
|
2215
|
+
* Assumes the deploy id template has already been assembled at the template path
|
|
2216
|
+
* (run `node bin/build <deployId>` first, or use `node bin/build <deployId> --update-private`).
|
|
2217
|
+
* @param {string} deployId - Concrete deploy id (e.g. `dd-core`).
|
|
2218
|
+
* @returns {Promise<void>}
|
|
2219
|
+
* @memberof ServerConfBuilder
|
|
2220
|
+
*/
|
|
2221
|
+
const updatePrivateEngineTestRepo = async (deployId) => {
|
|
2222
|
+
const username = process.env.GITHUB_USERNAME || 'underpostnet';
|
|
2223
|
+
const repoName = `engine-test-${deployId.split('-')[1]}`;
|
|
2224
|
+
const templatePath = '/home/dd/pwa-microservices-template';
|
|
2225
|
+
if (!fs.existsSync(templatePath))
|
|
2226
|
+
throw new Error(`updatePrivateEngineTestRepo: assemble the template first (node bin/build ${deployId})`);
|
|
2227
|
+
|
|
2228
|
+
// Detach the assembled working tree from any engine-build git history.
|
|
2229
|
+
shellExec(`sudo rm -rf ${templatePath}/.git`);
|
|
2230
|
+
|
|
2231
|
+
// Adopt the test repo's existing history when present (so the push is a delta);
|
|
2232
|
+
// otherwise publish a fresh history on first push.
|
|
2233
|
+
shellExec(`cd /home/dd && sudo rm -rf ./${repoName}.git && underpost clone --bare ${username}/${repoName}`, {
|
|
2234
|
+
silent: true,
|
|
2235
|
+
disableLog: true,
|
|
2236
|
+
silentOnError: true,
|
|
2237
|
+
});
|
|
2238
|
+
if (fs.existsSync(`/home/dd/${repoName}.git`)) shellExec(`mv /home/dd/${repoName}.git ${templatePath}/.git`);
|
|
2239
|
+
|
|
2240
|
+
// `git init` converts the moved bare repo into a normal work-tree repo (bare
|
|
2241
|
+
// clones have no work tree, so `git add` would fail), and bootstraps a fresh
|
|
2242
|
+
// repo on first publish. Idempotent — mirrors updatePrivateTemplateRepo.
|
|
2243
|
+
shellExec(`cd ${templatePath}
|
|
2244
|
+
git init
|
|
2245
|
+
git config user.name '${username}'
|
|
2246
|
+
git config user.email 'development@underpost.net'
|
|
2247
|
+
git add .`);
|
|
2248
|
+
|
|
2249
|
+
const hasChanges = shellExec(`node bin cmt ${templatePath} --has-changes`, {
|
|
2250
|
+
stdout: true,
|
|
2251
|
+
silent: true,
|
|
2252
|
+
disableLog: true,
|
|
2253
|
+
}).trim();
|
|
2254
|
+
if (hasChanges === '1')
|
|
2255
|
+
shellExec(`cd ${templatePath} && git commit -m 'Update ${repoName}' && underpost push . ${username}/${repoName}`);
|
|
2256
|
+
else logger.info('No changes to publish', { repoName });
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
export {
|
|
2260
|
+
Config,
|
|
2261
|
+
loadConf,
|
|
2262
|
+
loadConfInstances,
|
|
2263
|
+
loadInstanceTopology,
|
|
2264
|
+
readConfInstances,
|
|
2265
|
+
selectConfInstances,
|
|
2266
|
+
loadReplicas,
|
|
2267
|
+
cloneConf,
|
|
2268
|
+
getCapVariableName,
|
|
2269
|
+
addClientConf,
|
|
2270
|
+
buildClientSrc,
|
|
2271
|
+
buildApiSrc,
|
|
2272
|
+
addApiConf,
|
|
2273
|
+
addWsConf,
|
|
2274
|
+
buildWsSrc,
|
|
2275
|
+
cloneSrcComponents,
|
|
2276
|
+
buildProxyRouter,
|
|
2277
|
+
getDataDeploy,
|
|
2278
|
+
validateTemplatePath,
|
|
2279
|
+
buildReplicaId,
|
|
2280
|
+
mergeFile,
|
|
2281
|
+
getPathsSSR,
|
|
2282
|
+
buildKindPorts,
|
|
2283
|
+
buildPortProxyRouter,
|
|
2284
|
+
splitFileFactory,
|
|
2285
|
+
getNpmRootPath,
|
|
2286
|
+
getUnderpostRootPath,
|
|
2287
|
+
writeEnv,
|
|
2288
|
+
pathPortAssignmentFactory,
|
|
2289
|
+
deployRangePortFactory,
|
|
2290
|
+
awaitDeployMonitor,
|
|
2291
|
+
buildCliDoc,
|
|
2292
|
+
getInstanceContext,
|
|
2293
|
+
buildApiConf,
|
|
2294
|
+
buildClientStaticConf,
|
|
2295
|
+
isDeployRunnerContext,
|
|
2296
|
+
isDevProxyContext,
|
|
2297
|
+
devProxyHostFactory,
|
|
2298
|
+
isTlsDevProxy,
|
|
2299
|
+
getTlsHosts,
|
|
2300
|
+
resolveHostKeyContext,
|
|
2301
|
+
resolveConfSecrets,
|
|
2302
|
+
loadConfServerJson,
|
|
2303
|
+
getConfFolder,
|
|
2304
|
+
getConfFilePath,
|
|
2305
|
+
readConfJson,
|
|
2306
|
+
DEFAULT_DEPLOY_ID,
|
|
2307
|
+
loadCronDeployEnv,
|
|
2308
|
+
cronDeployIdResolve,
|
|
2309
|
+
etcHostFactory,
|
|
2310
|
+
resolveDeployList,
|
|
2311
|
+
syncPrivateConf,
|
|
2312
|
+
syncDeployIdSources,
|
|
2313
|
+
buildTemplate,
|
|
2314
|
+
updatePrivateTemplateRepo,
|
|
2315
|
+
updatePrivateEngineTestRepo,
|
|
2316
|
+
};
|