Compare commits

...

90 Commits

Author SHA1 Message Date
bc7a2ca5f1 5.0.4
Some checks failed
Docker (tags) / security (push) Successful in 48s
Docker (tags) / test (push) Successful in 1m56s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 14s
2025-04-25 18:20:18 +00:00
77d911e47a fix(platformservice/mta): Update getEmailStatus response schema: make details property optional 2025-04-25 18:20:18 +00:00
b9c9c2d0a9 5.0.3
Some checks failed
Docker (tags) / security (push) Successful in 49s
Docker (tags) / test (push) Successful in 1m55s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 14s
2025-04-25 17:02:48 +00:00
d5b91789d1 fix(mta): update email status response type in MTA platform service 2025-04-25 17:02:48 +00:00
eb8350f453 5.0.2
Some checks failed
Docker (tags) / security (push) Successful in 38s
Docker (tags) / test (push) Successful in 1m56s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 13s
2025-04-25 16:34:01 +00:00
b987ce27b8 fix(platformservice/mta): Refactor email status response in MTA service 2025-04-25 16:34:00 +00:00
630e363e53 5.0.1
Some checks failed
Docker (tags) / security (push) Successful in 48s
Docker (tags) / test (push) Successful in 1m54s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 14s
2025-04-25 16:27:48 +00:00
a602021952 fix(mta): Update email stats response interface in mta platform service to include totalEmailsSent, totalEmailsDelivered, totalEmailsBounced, averageDeliveryTimeMs, and lastUpdated timestamp. 2025-04-25 16:27:48 +00:00
80585437a0 5.0.0
Some checks failed
Docker (tags) / security (push) Successful in 47s
Docker (tags) / test (push) Successful in 1m54s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 41s
2025-04-25 15:57:35 +00:00
4674a20a2c BREAKING CHANGE(ts_interfaces/platformservice/mta): Rename mta interfaces and upgrade dependency versions 2025-04-25 15:57:35 +00:00
820cdfcd48 4.13.0
Some checks failed
Docker (tags) / security (push) Successful in 52s
Docker (tags) / test (push) Successful in 3m5s
Docker (tags) / metadata (push) Successful in 8s
Docker (tags) / release (push) Failing after 22s
2025-01-20 02:18:58 +01:00
6e5dd9b05a feat(service): Add support for service creation, update, and deletion. 2025-01-20 02:18:58 +01:00
f3d5c21fab 4.12.2
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 3m5s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 24s
2025-01-20 02:11:12 +01:00
04b278ee28 fix(service): Fix secret bundle and service management bugs 2025-01-20 02:11:12 +01:00
7084d76c43 4.12.1
Some checks failed
Docker (tags) / security (push) Successful in 51s
Docker (tags) / test (push) Successful in 2m53s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 20s
2025-01-02 04:07:43 +01:00
41d7550e89 fix(deps): Updated @git.zone/tspublish to version ^1.9.1 2025-01-02 04:07:43 +01:00
4bf361d3a6 4.12.0
Some checks failed
Docker (tags) / security (push) Successful in 1m1s
Docker (tags) / test (push) Successful in 2m57s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 31s
2025-01-02 03:58:09 +01:00
d70617a90c feat(cli): Add CLI support and external registries view 2025-01-02 03:58:09 +01:00
62ad1655d5 4.11.0
Some checks failed
Docker (tags) / security (push) Successful in 1m7s
Docker (tags) / test (push) Successful in 3m0s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-30 00:01:27 +01:00
caf3a095f2 feat(external-registry): Introduce external registry management 2024-12-30 00:01:26 +01:00
89e44b2e5f 4.10.0
Some checks failed
Docker (tags) / security (push) Successful in 1m3s
Docker (tags) / test (push) Successful in 2m59s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-29 13:40:51 +01:00
a617f51b19 feat(apiclient): Added support for managing external registries in the API client. 2024-12-29 13:40:51 +01:00
355e04fd1d 4.9.0
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 3m2s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 30s
2024-12-29 13:19:46 +01:00
89bd767bea feat(apiclient): Add external registry management capabilities to Cloudly API client. 2024-12-29 13:19:46 +01:00
e567ebbf21 4.8.1
Some checks failed
Docker (tags) / security (push) Successful in 53s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-28 21:48:57 +01:00
33311348e2 fix(interfaces): Fix image location schema in IImage interface 2024-12-28 21:48:57 +01:00
d6e914edab 4.8.0
Some checks failed
Docker (tags) / security (push) Successful in 1m5s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-28 21:39:44 +01:00
da7b866f23 feat(manager.registry): Add external registry management 2024-12-28 21:39:44 +01:00
7654d780b1 4.7.1
Some checks failed
Docker (tags) / security (push) Successful in 1m10s
Docker (tags) / test (push) Successful in 3m1s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-28 19:50:30 +01:00
dbd9b661c6 fix(secretmanagement): Refactor secret bundle actions and improve authorization handling 2024-12-28 19:50:29 +01:00
e19d0b4deb 4.7.0
Some checks failed
Docker (tags) / security (push) Successful in 53s
Docker (tags) / test (push) Successful in 3m3s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-22 20:09:23 +01:00
f0ebb719f7 feat(apiclient): Add method to flatten secret bundles into key-value objects. 2024-12-22 20:09:23 +01:00
c8e0666bc6 4.6.0
Some checks failed
Docker (tags) / security (push) Successful in 54s
Docker (tags) / test (push) Successful in 3m0s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-22 20:03:11 +01:00
0d0b106f90 feat(cloudlyapiclient): Extend CloudlyApiClient with cluster, secretbundle, and secretgroup methods 2024-12-22 20:03:11 +01:00
c9073df7cd 4.5.5
Some checks failed
Docker (tags) / security (push) Successful in 1m4s
Docker (tags) / test (push) Successful in 3m0s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-22 19:55:56 +01:00
f65200703d fix(apiclient): Fixed image creation method in cloudlyApiClient 2024-12-22 19:55:56 +01:00
57970b3d10 4.5.4
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-21 22:14:45 +01:00
b4d9f40c41 fix(ts_web): Fix action type and data fields in appstate for CRUD operations 2024-12-21 22:14:45 +01:00
a219725ff6 4.5.3
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23m54s
2024-12-21 20:21:54 +01:00
4b993fc6b3 fix(secret-management): Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups. 2024-12-21 20:21:54 +01:00
d453da709f 4.5.2
Some checks failed
Docker (tags) / security (push) Successful in 1m4s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23m21s
2024-12-20 02:13:50 +01:00
50fac41c95 fix(apiclient): Implemented IService interface in Service class and improved secret bundle documentation. 2024-12-20 02:13:50 +01:00
affce1fcd1 4.5.1
Some checks failed
Docker (tags) / security (push) Successful in 1m4s
Docker (tags) / test (push) Successful in 3m4s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 16s
2024-12-17 19:51:11 +01:00
df67ebd27a fix(core): Updated dependencies in package.json to latest versions. 2024-12-17 19:51:10 +01:00
ef5bfd435a 4.5.0
Some checks failed
Docker (tags) / security (push) Successful in 1m8s
Docker (tags) / test (push) Successful in 3m5s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23m36s
2024-12-14 20:32:17 +01:00
db07db930c feat(services): Add service management functionalities 2024-12-14 20:32:17 +01:00
f6309f600c 4.4.0
All checks were successful
Docker (tags) / security (push) Successful in 48s
Docker (tags) / test (push) Successful in 2m42s
Docker (tags) / metadata (push) Successful in 6s
Docker (tags) / release (push) Successful in 4m55s
2024-11-18 19:52:15 +01:00
7477704905 feat(api-client): Add static method getImageById for Image class in api-client 2024-11-18 19:52:15 +01:00
db89d86242 4.3.21
All checks were successful
Docker (tags) / security (push) Successful in 58s
Docker (tags) / test (push) Successful in 2m43s
Docker (tags) / metadata (push) Successful in 6s
Docker (tags) / release (push) Successful in 5m0s
2024-11-18 19:43:52 +01:00
b74ce05845 fix(interfaces): Remove deprecated deployment directive and update related interfaces 2024-11-18 19:43:52 +01:00
79db68a4a2 4.3.20
All checks were successful
Docker (tags) / security (push) Successful in 58s
Docker (tags) / test (push) Successful in 2m42s
Docker (tags) / metadata (push) Successful in 6s
Docker (tags) / release (push) Successful in 6m19s
2024-11-18 17:48:26 +01:00
5a3ddcf39b fix(apiclient): Ensure mandatory parameter in CloudlyApiClient constructor 2024-11-18 17:48:26 +01:00
fe6bfc0a83 4.3.19
All checks were successful
Docker (tags) / security (push) Successful in 1m1s
Docker (tags) / test (push) Successful in 2m52s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Successful in 5m3s
2024-11-18 13:41:29 +01:00
36a481ecd1 fix(docker): Fix improper Docker push command preventing push to the correct registry. 2024-11-18 13:41:29 +01:00
f7b2e203ed 4.3.18
All checks were successful
Docker (tags) / security (push) Successful in 1m2s
Docker (tags) / test (push) Successful in 2m49s
Docker (tags) / metadata (push) Successful in 6s
Docker (tags) / release (push) Successful in 4m25s
2024-11-17 07:05:41 +01:00
27c98c4e32 fix(docker_tags): Updated Docker configuration to include NPM tokens. 2024-11-17 07:05:41 +01:00
79257908d0 4.3.17
Some checks failed
Docker (tags) / security (push) Successful in 1m2s
Docker (tags) / test (push) Successful in 2m46s
Docker (tags) / metadata (push) Successful in 9s
Docker (tags) / release (push) Failing after 28s
2024-11-17 06:31:22 +01:00
b5ca898eac fix(Dockerfile): Corrected docker base image tag in Dockerfile for alpine compatibility. 2024-11-17 06:31:22 +01:00
53ade28931 4.3.16
Some checks failed
Docker (tags) / security (push) Successful in 50s
Docker (tags) / test (push) Successful in 2m42s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 32s
2024-11-17 01:04:26 +01:00
fff4c7642d fix(infrastructure): Correct Docker image path in Dockerfile for improved build consistency. 2024-11-17 01:04:26 +01:00
dafe6574cc 4.3.15
Some checks failed
Docker (tags) / security (push) Successful in 1m1s
Docker (tags) / test (push) Successful in 2m47s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 28s
2024-11-17 00:00:56 +01:00
b70dad4996 fix(project setup): fixed incorrect configuration in npmextra.json 2024-11-17 00:00:55 +01:00
17b0b50fbd 4.3.14
Some checks failed
Docker (tags) / security (push) Successful in 50s
Docker (tags) / test (push) Successful in 2m50s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 33s
2024-11-16 22:31:17 +01:00
91a0272ab3 fix(docker tags): Comment out unused secret variables in docker_tags.yaml 2024-11-16 22:31:16 +01:00
efd22d4087 4.3.13
Some checks failed
Docker (tags) / security (push) Successful in 51s
Docker (tags) / test (push) Successful in 2m48s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 35s
2024-11-16 16:08:51 +01:00
c9e32540bf fix(package): Updated package dependencies 2024-11-16 16:08:50 +01:00
8344f96983 4.3.12
Some checks failed
Docker (tags) / security (push) Successful in 43s
Docker (tags) / test (push) Successful in 3m11s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 34s
2024-11-06 21:26:23 +01:00
3b77089d79 fix(workflow): Fix Docker image path in GitHub action workflow 2024-11-06 21:26:23 +01:00
b6bce76043 4.3.11
Some checks failed
Docker (tags) / security (push) Successful in 46s
Docker (tags) / test (push) Successful in 3m7s
Docker (tags) / release (push) Failing after 0s
Docker (tags) / metadata (push) Successful in 7s
2024-11-06 21:21:15 +01:00
cab57ab303 fix(overall): Refactor and improve code consistency across all modules 2024-11-06 21:21:14 +01:00
804f1f3b12 4.3.10
Some checks failed
Docker (tags) / security (push) Successful in 1m1s
Docker (tags) / test (push) Failing after 11s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 21:16:12 +01:00
f0144fdd5b fix(dependencies): Updated dependencies and fixed Docker Alpine image retrieval issue in tests 2024-11-06 21:16:12 +01:00
81f286cb2f 4.3.9
Some checks failed
Docker (tags) / security (push) Successful in 58s
Docker (tags) / test (push) Failing after 3m6s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 17:19:44 +01:00
1f12cb9f94 fix(test and dependencies): Corrected cloudlyUrl in test.apiclient and updated tapbundle dependency. 2024-11-06 17:19:43 +01:00
26490e8ddd 4.3.8
Some checks failed
Docker (tags) / security (push) Successful in 53s
Docker (tags) / test (push) Failing after 2m10s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 16:59:18 +01:00
38d2120c35 fix(api client): Fixed localhost URL issue in test.client.ts 2024-11-06 16:59:17 +01:00
f80b8decbc 4.3.7
Some checks failed
Docker (tags) / security (push) Successful in 59s
Docker (tags) / test (push) Failing after 2m4s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 16:53:22 +01:00
28cd6d1b49 fix(tests): Refactored test setup for consistency and isolated config initialization. 2024-11-06 16:53:21 +01:00
899e5b0a7d 4.3.6
Some checks failed
Docker (tags) / security (push) Successful in 55s
Docker (tags) / test (push) Failing after 2m8s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 16:22:38 +01:00
0eff7c7510 fix(test): Enhance test helpers with dynamic Hetzner token retrieval. 2024-11-06 16:22:38 +01:00
7789348f4e 4.3.5
Some checks failed
Docker (tags) / security (push) Successful in 1m2s
Docker (tags) / test (push) Failing after 2m8s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 16:13:55 +01:00
66a23a515b fix(helpers): Add missing sslMode configuration to Cloudly config. 2024-11-06 16:13:54 +01:00
7c1082f5a9 4.3.4
Some checks failed
Docker (tags) / security (push) Successful in 1m0s
Docker (tags) / test (push) Failing after 2m5s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-06 03:56:46 +01:00
15ea5adec6 fix(testing): Fixed Cloudly testing setup and dependencies 2024-11-06 03:56:46 +01:00
da0dddcceb 4.3.3
Some checks failed
Docker (tags) / security (push) Successful in 1m0s
Docker (tags) / test (push) Failing after 1m37s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-05 21:31:16 +01:00
b5433e412f fix(core): Fix configuration initialization by accepting a config argument 2024-11-05 21:31:15 +01:00
7eb6bf794c 4.3.2
Some checks failed
Docker (tags) / security (push) Successful in 42s
Docker (tags) / test (push) Failing after 1m46s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-05 02:45:04 +01:00
b244518fcb fix(npmextra): Updated npm registry URL in npmextra.json 2024-11-05 02:45:04 +01:00
95d0396abb 4.3.1
Some checks failed
Docker (tags) / security (push) Successful in 58s
Docker (tags) / test (push) Failing after 3m59s
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-11-05 02:21:06 +01:00
a830299cc9 fix(package): Update dependency version for @git.zone/tspublish 2024-11-05 02:21:06 +01:00
58 changed files with 11126 additions and 5907 deletions

View File

@ -10,9 +10,10 @@ env:
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}} NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}} NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}} # NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_LOGIN_DOCKER_GITEA: ${{ github.server_url }}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }} # NPMCI_LOGIN_DOCKER_GITEA: ${{ github.server_url }}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }}
NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }} NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }}
NPMCI_SECRET01: ${{ secrets.NPMCI_SECRET01 }}
jobs: jobs:
security: security:
@ -74,7 +75,7 @@ jobs:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: code.foss.global/hosttoday/ht-docker-dbase:npmci image: code.foss.global/host.today/ht-docker-dbase:npmci
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -89,8 +90,7 @@ jobs:
npmci docker login npmci docker login
npmci docker build npmci docker build
npmci docker test npmci docker test
# npmci docker push npmci docker push code.foss.global
npmci docker push
metadata: metadata:
needs: test needs: test

View File

@ -1,6 +1,6 @@
# gitzone dockerfile_service # gitzone dockerfile_service
## STAGE 1 // BUILD ## STAGE 1 // BUILD
FROM code.foss.global/hosttoday/ht-docker-node:npmci as node1 FROM code.foss.global/host.today/ht-docker-node:npmci as node1
COPY ./ /app COPY ./ /app
WORKDIR /app WORKDIR /app
ARG NPMCI_TOKEN_NPM2 ARG NPMCI_TOKEN_NPM2
@ -12,7 +12,7 @@ RUN pnpm run build
# gitzone dockerfile_service # gitzone dockerfile_service
## STAGE 2 // install production ## STAGE 2 // install production
FROM code.foss.global/hosttoday/ht-docker-node:npmci as node2 FROM code.foss.global/host.today/ht-docker-node:npmci as node2
WORKDIR /app WORKDIR /app
COPY --from=node1 /app /app COPY --from=node1 /app /app
RUN rm -rf .pnpm-store RUN rm -rf .pnpm-store
@ -24,7 +24,7 @@ RUN rm -rf node_modules/ && pnpm install --prod
## STAGE 3 // rebuild dependencies for alpine ## STAGE 3 // rebuild dependencies for alpine
FROM code.foss.global/hosttoday/ht-docker-node:alpinenpmci as node3 FROM code.foss.global/host.today/ht-docker-node:alpine_npmci as node3
WORKDIR /app WORKDIR /app
COPY --from=node2 /app /app COPY --from=node2 /app /app
ARG NPMCI_TOKEN_NPM2 ARG NPMCI_TOKEN_NPM2
@ -34,7 +34,7 @@ RUN pnpm config set store-dir .pnpm-store
RUN pnpm rebuild -r RUN pnpm rebuild -r
## STAGE 4 // the final production image with all dependencies in place ## STAGE 4 // the final production image with all dependencies in place
FROM code.foss.global/hosttoday/ht-docker-node:alpine as node4 FROM code.foss.global/host.today/ht-docker-node:alpine as node4
WORKDIR /app WORKDIR /app
COPY --from=node3 /app /app COPY --from=node3 /app /app

View File

@ -1,5 +1,283 @@
# Changelog # Changelog
## 2025-04-25 - 5.0.4 - fix(platformservice/mta)
Update getEmailStatus response schema: make details property optional
- Changed details property from required with fixed message to optional with a flexible message structure in IReq_GetEMailStats response
## 2025-04-25 - 5.0.3 - fix(mta)
update email status response type in MTA platform service
- Changed the response 'status' field in IRequest_CheckEmailStatus from a literal 'unknown' to a generic string for improved flexibility
## 2025-04-25 - 5.0.2 - fix(platformservice/mta)
Refactor email status response in MTA service
- Updated IReq_CheckEmailStatus response: replaced union type ('ok' | 'not ok') with fixed status 'unknown' and added a details object with message 'Email not found'.
## 2025-04-25 - 5.0.1 - fix(mta)
Update email stats response interface in mta platform service to include totalEmailsSent, totalEmailsDelivered, totalEmailsBounced, averageDeliveryTimeMs, and lastUpdated timestamp.
- Modified IReq_GetEMailStats response in ts_interfaces/platformservice/mta.ts from an empty status object to a detailed email statistics structure.
## 2025-04-25 - 5.0.0 - BREAKING CHANGE(ts_interfaces/platformservice/mta)
Rename mta interfaces and upgrade dependency versions
- Upgraded devDependencies: @git.zone/tsbuild, tsbundle, tsdoc, tstest, tswatch, and @push.rocks/tapbundle to newer versions.
- Upgraded dependencies: @design.estate/dees-catalog, dees-domtools, dees-element, @push.rocks/smartdata, smartexpect, smartfile, smartpromise, smartrequest, smartrx, and tsclass (v4.2.0 to v9.0.0).
- Added new packageManager field in package.json and introduced pnpm-workspace.yaml for additional workspace configuration.
- Refactored mta API interfaces: renamed IRequest_SendEmail to IReq_SendEmail and IRequestRegisterRecipient to IReq_RegisterRecipient; added IReq_CheckEmailStatus and IReq_GetEMailStats.
## 2025-01-20 - 4.13.0 - feat(service)
Add support for service creation, update, and deletion.
- Implemented TypedHandlers for creating a new service.
- Added features to update existing service details.
- Enabled deletion of services by their unique ID.
## 2025-01-20 - 4.12.2 - fix(service)
Fix secret bundle and service management bugs
- Corrected the field name from 'includedImages' to 'imageClaims' in secret bundles.
- Implemented 'getFlatKeyValueObject' for secret bundles and modified related API interactions.
- Enhanced the Service class with methods for handling secret bundle data by resolving related groups and environments.
## 2025-01-02 - 4.12.1 - fix(deps)
Updated @git.zone/tspublish to version ^1.9.1
## 2025-01-02 - 4.12.0 - feat(cli)
Add CLI support and external registries view
- Adds CLI client functionality
- Introduces a new view for External Registries in the dashboard
## 2024-12-30 - 4.11.0 - feat(external-registry)
Introduce external registry management
- Added ExternalRegistryManager to handle external registry operations.
- Implemented ability to create, retrieve, and delete external registries.
- Enhanced Cloudly class to include ExternalRegistryManager.
## 2024-12-29 - 4.10.0 - feat(apiclient)
Added support for managing external registries in the API client.
- Introduced methods to get a registry by ID, get all registries, and create a new registry in the externalRegistry object.
- Updated external registry request interfaces to match new API client capabilities.
## 2024-12-29 - 4.9.0 - feat(apiclient)
Add external registry management capabilities to Cloudly API client.
- Introduce ExternalRegistry class with methods for getting, creating, and updating external registries.
- Expand requests module to handle external registry management, including creation and deletion.
## 2024-12-28 - 4.8.1 - fix(interfaces)
Fix image location schema in IImage interface
- Refactored the 'external' object within IImage data to a 'location' object.
- Added 'internal' boolean to 'location' to specify internal/external status.
## 2024-12-28 - 4.8.0 - feat(manager.registry)
Add external registry management
- Introduced ExternalRegistry class for handling external registry configurations.
- Updated IExternalRegistry interface to include registry details.
- Enhanced IImage interface to support linking with external registries.
## 2024-12-28 - 4.7.1 - fix(secretmanagement)
Refactor secret bundle actions and improve authorization handling
- Refactored secret bundle handling by renaming methods and reorganizing static and instance methods in SecretBundle class.
- Added getSecretBundleByAuthorization method to SecretBundle.
- Improved getFlatKeyValueObjectForEnvironment to accurately retrieve key-value pairs for specified environments.
- Removed deprecated IEnvBundle interface and related request handler for better clarity and code usage.
- Updated request interfaces related to secret bundles for consistent method naming and arguments.
## 2024-12-22 - 4.7.0 - feat(apiclient)
Add method to flatten secret bundles into key-value objects.
- SecretBundle: Implemented toFlatKeyValueObject method to flatten secret groups into key-value pairs.
- Removed stale SecretManager class from apiclient.
## 2024-12-22 - 4.6.0 - feat(cloudlyapiclient)
Extend CloudlyApiClient with cluster, secretbundle, and secretgroup methods
- Added methods to CloudlyApiClient for managing clusters: getClusterById, getClusters, createCluster.
- Added methods to CloudlyApiClient for managing secret bundles: getSecretBundleById, getSecretBundles, createSecretBundle.
- Added methods to CloudlyApiClient for managing secret groups: getSecretGroupById, getSecretGroups, createSecretGroup.
## 2024-12-22 - 4.5.5 - fix(apiclient)
Fixed image creation method in cloudlyApiClient
- Corrected method call from 'images.createImage' to 'image.createImage' to ensure proper image creation.
- Updated cluster retrieval methods and ensured proper API routes are being called.
## 2024-12-21 - 4.5.4 - fix(ts_web)
Fix action type and data fields in appstate for CRUD operations
- Correct request method in createSecretGroupAction to accurately reflect the purpose.
- Align the deleteSecretGroupAction and deleteSecretBundleAction request types with proper interfaces.
- Ensure data payload matches backend requirements for secret group and secret bundle operations.
## 2024-12-21 - 4.5.3 - fix(secret-management)
Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups.
- Updated secret management logic to separate secret bundle and group APIs.
- Implemented new API client classes for managing secret bundles and groups.
- Fixed incorrect method usages for secret-related actions.
## 2024-12-20 - 4.5.2 - fix(apiclient)
Implemented IService interface in Service class and improved secret bundle documentation.
- Implemented plugins.servezoneInterfaces.data.IService interface in the Service class within ts_apiclient.
- Updated documentation comments for the type property in the ISecretBundle interface.
## 2024-12-17 - 4.5.1 - fix(core)
Updated dependencies in package.json to latest versions.
- Bumped @git.zone/tswatch to version ^2.0.37
- Bumped @types/node to version ^22.10.2
- Bumped @design.estate/dees-catalog to version ^1.3.2
- Bumped @push.rocks/smartfile to version ^11.0.23
- Bumped @tsclass/tsclass to version ^4.2.0
## 2024-12-14 - 4.5.0 - feat(services)
Add service management functionalities
- Integrated service-related API client methods including getServices, getServiceById, and createService.
- Updated the deployment data structure in the service manager.
- Enhanced service interface to incorporate additional fields for comprehensive data handling.
- Ensured secure token generation for Cloudly authentication processes.
## 2024-11-18 - 4.4.0 - feat(api-client)
Add static method getImageById for Image class in api-client
- Introduced a static method getImageById in the Image class.
- Updated CloudlyApiClient to include the getImageById method in the images interface.
## 2024-11-18 - 4.3.21 - fix(interfaces)
Remove deprecated deployment directive and update related interfaces
- Removed IDeploymentDirective from data and requests.
- Updated IDeployment to remove references to directives.
- Changed IRequest_Any_Cloudly_GetClusterConfig to return services instead of deployment directives.
- Removed deploymentDirectiveIds from IService data structure.
## 2024-11-18 - 4.3.20 - fix(apiclient)
Ensure mandatory parameter in CloudlyApiClient constructor
- Made the 'optionsArg' parameter mandatory in the constructor of CloudlyApiClient class.
## 2024-11-18 - 4.3.19 - fix(docker)
Fix improper Docker push command preventing push to the correct registry.
- Corrected the docker push command in the '.gitea/workflows/docker_tags.yaml' file to push images to the 'code.foss.global' registry.
## 2024-11-17 - 4.3.18 - fix(docker_tags)
Updated Docker configuration to include NPM tokens.
- Restored NPMCI_TOKEN_NPM and NPMCI_TOKEN_NPM2 environment variables in docker_tags.yaml for authentication purposes.
## 2024-11-17 - 4.3.17 - fix(Dockerfile)
Corrected docker base image tag in Dockerfile for alpine compatibility.
- Updated Dockerfile to use the correct base image tag for Alpine.
- Resolved any potential build issues related to incorrect image tag usage.
## 2024-11-17 - 4.3.16 - fix(infrastructure)
Correct Docker image path in Dockerfile for improved build consistency.
- Dockerfile: Updated base image paths from 'code.foss.global/hosttoday/ht-docker-node' to 'code.foss.global/host.today/ht-docker-node'.
## 2024-11-17 - 4.3.15 - fix(project setup)
fixed incorrect configuration in npmextra.json
- Removed unnecessary 'dockerBuildargEnvMap' entry for NPMCI_TOKEN_NPM2.
- Corrected the githost and gitscope in gitzone module configuration.
- Updated the license field to reflect the correct license.
## 2024-11-16 - 4.3.14 - fix(docker tags)
Comment out unused secret variables in docker_tags.yaml
- Modified docker_tags.yaml to comment out unused secret variables related to NPM and GitHub tokens.
## 2024-11-16 - 4.3.13 - fix(package)
Updated package dependencies
- Updated @design.estate/dees-catalog version to 1.3.1
## 2024-11-06 - 4.3.12 - fix(workflow)
Fix Docker image path in GitHub action workflow
- Corrected the path of the Docker image used in the GitHub action workflow from 'code.foss.global/hosttoday/ht-docker-dbase:npmci' to 'code.foss.global/host.today/ht-docker-dbase:npmci'.
## 2024-11-06 - 4.3.11 - fix(overall)
Refactor and improve code consistency across all modules
- Updated cloud configuration management for better reliability.
- Enhanced security measures in the authentication and authorization processes.
- Streamlined deployment logic in cluster management.
- Refactored code to improve maintainability and readability.
## 2024-11-06 - 4.3.10 - fix(dependencies)
Updated dependencies and fixed Docker Alpine image retrieval issue in tests
- Updated @push.rocks/tapbundle to version ^5.5.0 in devDependencies.
- Updated @push.rocks/smartrequest to version ^2.0.23 in dependencies.
- Ensured the Docker Alpine image is retrieved as a local tarball in cloudlyfactory.ts test helper.
## 2024-11-06 - 4.3.9 - fix(test and dependencies)
Corrected cloudlyUrl in test.apiclient and updated tapbundle dependency.
- Fixed cloudlyUrl assignment in the test.apiclient to use the correct helper method.
- Updated tapbundle dependency version from ^5.4.3 to ^5.4.4.
## 2024-11-06 - 4.3.8 - fix(api client)
Fixed localhost URL issue in test.client.ts
- Changed the cloudlyUrl in test.client.ts from 'localhost' to '127.0.0.1' to ensure consistency in network requests.
## 2024-11-06 - 4.3.7 - fix(tests)
Refactored test setup for consistency and isolated config initialization.
- test/helpers/cloudlyfactory.ts: Test configuration setup was refactored to ensure consistent initialization of cloudly configuration across tests.
- test/test.apiclient.ts: Updated cloudlyApiClient test setup to use testCloudlyConfig for dynamic port allocation.
## 2024-11-06 - 4.3.6 - fix(test)
Enhance test helpers with dynamic Hetzner token retrieval.
- Updated test/helpers/cloudlyfactory.ts to retrieve Hetzner token from environment variables.
- Expanded docker_tags workflow to securely handle and pass new environment secrets.
## 2024-11-06 - 4.3.5 - fix(helpers)
Add missing sslMode configuration to Cloudly config.
- Added the sslMode key with a value of 'none' to the Cloudly configuration object in test/helpers/cloudlyfactory.ts.
## 2024-11-06 - 4.3.4 - fix(testing)
Fixed Cloudly testing setup and dependencies
- Updated devDependency @push.rocks/tapbundle version from ^5.3.0 to ^5.4.3 in package.json.
- Updated devDependency @push.rocks/npmextra version from ^5.1.1 to ^5.1.2 in package.json.
- Improved the Cloudly test suite setup to ensure proper initialization of MongoDB and S3 services.
- Ensured asynchronous stopping and cleanup of MongoDB and S3 services post-test execution.
## 2024-11-05 - 4.3.3 - fix(core)
Fix configuration initialization by accepting a config argument
- Configuration initialization now accepts an optional config argument
- Updated test cloudly factory to use default public URL and port
- Updated dependencies versions
## 2024-11-05 - 4.3.2 - fix(npmextra)
Updated npm registry URL in npmextra.json
## 2024-11-05 - 4.3.1 - fix(package)
Update dependency version for @git.zone/tspublish
- Bump @git.zone/tspublish from version ^1.7.6 to ^1.7.7 in package.json
## 2024-11-05 - 4.3.0 - feat(dependencies) ## 2024-11-05 - 4.3.0 - feat(dependencies)
Upgrade dependencies and include publish orders Upgrade dependencies and include publish orders

View File

@ -2,23 +2,21 @@
"npmci": { "npmci": {
"npmGlobalTools": [], "npmGlobalTools": [],
"npmAccessLevel": "public", "npmAccessLevel": "public",
"npmRegistryUrl": "verdaccio.lossless.one", "npmRegistryUrl": "verdaccio.lossless.digital",
"dockerRegistryRepoMap": { "dockerRegistryRepoMap": {
"registry.gitlab.com": "losslessone/services/servezone/cloudly" "code.foss.global": "serve.zone/cloudly"
}, },
"dockerBuildargEnvMap": { "dockerBuildargEnvMap": {}
"NPMCI_TOKEN_NPM2": "NPMCI_TOKEN_NPM2"
}
}, },
"gitzone": { "gitzone": {
"projectType": "service", "projectType": "service",
"module": { "module": {
"githost": "gitlab.com", "githost": "code.foss.global",
"gitscope": "servezone/private", "gitscope": "serve.zone",
"gitrepo": "cloudly", "gitrepo": "cloudly",
"description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.", "description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.",
"npmPackagename": "@serve.zone/cloudly", "npmPackagename": "@serve.zone/cloudly",
"license": "UNLICENSED", "license": "MIT",
"keywords": [ "keywords": [
"multi-cloud management", "multi-cloud management",
"Docker Swarmkit", "Docker Swarmkit",

View File

@ -1,6 +1,6 @@
{ {
"name": "@serve.zone/cloudly", "name": "@serve.zone/cloudly",
"version": "4.3.0", "version": "5.0.4",
"private": false, "private": false,
"description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.", "description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.",
"type": "module", "type": "module",
@ -22,41 +22,41 @@
"docs": "tsdoc aidoc" "docs": "tsdoc aidoc"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.2.0", "@git.zone/tsbuild": "^2.3.2",
"@git.zone/tsbundle": "^2.1.0", "@git.zone/tsbundle": "^2.2.5",
"@git.zone/tsdoc": "^1.4.2", "@git.zone/tsdoc": "^1.4.4",
"@git.zone/tspublish": "^1.7.6", "@git.zone/tspublish": "^1.9.1",
"@git.zone/tstest": "^1.0.90", "@git.zone/tstest": "^1.0.96",
"@git.zone/tswatch": "^2.0.25", "@git.zone/tswatch": "^2.1.0",
"@push.rocks/tapbundle": "^5.3.0", "@push.rocks/tapbundle": "^5.6.3",
"@types/node": "^22.8.7" "@types/node": "^22.15.2"
}, },
"dependencies": { "dependencies": {
"@api.global/typedrequest": "3.1.10", "@api.global/typedrequest": "3.1.10",
"@api.global/typedrequest-interfaces": "^3.0.19", "@api.global/typedrequest-interfaces": "^3.0.19",
"@api.global/typedserver": "^3.0.51", "@api.global/typedserver": "^3.0.74",
"@api.global/typedsocket": "^3.0.1", "@api.global/typedsocket": "^3.0.1",
"@apiclient.xyz/cloudflare": "^6.0.1", "@apiclient.xyz/cloudflare": "^6.0.1",
"@apiclient.xyz/docker": "^1.2.7", "@apiclient.xyz/docker": "^1.3.0",
"@apiclient.xyz/hetznercloud": "^1.2.0", "@apiclient.xyz/hetznercloud": "^1.2.0",
"@apiclient.xyz/slack": "^3.0.9", "@apiclient.xyz/slack": "^3.0.9",
"@design.estate/dees-catalog": "^1.2.0", "@design.estate/dees-catalog": "^1.8.0",
"@design.estate/dees-domtools": "^2.0.64", "@design.estate/dees-domtools": "^2.3.2",
"@design.estate/dees-element": "^2.0.39", "@design.estate/dees-element": "^2.0.42",
"@git.zone/tsrun": "^1.3.3", "@git.zone/tsrun": "^1.3.3",
"@push.rocks/early": "^4.0.3", "@push.rocks/early": "^4.0.3",
"@push.rocks/npmextra": "^5.0.23", "@push.rocks/npmextra": "^5.1.2",
"@push.rocks/projectinfo": "^5.0.1", "@push.rocks/projectinfo": "^5.0.1",
"@push.rocks/qenv": "^6.0.5", "@push.rocks/qenv": "^6.1.0",
"@push.rocks/smartacme": "^5.0.0", "@push.rocks/smartacme": "^5.0.0",
"@push.rocks/smartbucket": "^3.0.23", "@push.rocks/smartbucket": "^3.3.7",
"@push.rocks/smartcli": "^4.0.11", "@push.rocks/smartcli": "^4.0.11",
"@push.rocks/smartclickhouse": "^2.0.17", "@push.rocks/smartclickhouse": "^2.0.17",
"@push.rocks/smartdata": "^5.2.10", "@push.rocks/smartdata": "^5.15.1",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartexit": "^1.0.23", "@push.rocks/smartexit": "^1.0.23",
"@push.rocks/smartexpect": "^1.2.1", "@push.rocks/smartexpect": "^1.6.1",
"@push.rocks/smartfile": "^11.0.21", "@push.rocks/smartfile": "^11.2.0",
"@push.rocks/smartguard": "^3.1.0", "@push.rocks/smartguard": "^3.1.0",
"@push.rocks/smartjson": "^5.0.19", "@push.rocks/smartjson": "^5.0.19",
"@push.rocks/smartjwt": "^2.2.1", "@push.rocks/smartjwt": "^2.2.1",
@ -64,17 +64,17 @@
"@push.rocks/smartlog-destination-clickhouse": "^1.0.13", "@push.rocks/smartlog-destination-clickhouse": "^1.0.13",
"@push.rocks/smartlog-interfaces": "^3.0.2", "@push.rocks/smartlog-interfaces": "^3.0.2",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.4", "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrequest": "^2.0.22", "@push.rocks/smartrequest": "^2.1.0",
"@push.rocks/smartrx": "^3.0.7", "@push.rocks/smartrx": "^3.0.10",
"@push.rocks/smartssh": "^2.0.1", "@push.rocks/smartssh": "^2.0.1",
"@push.rocks/smartstate": "^2.0.19", "@push.rocks/smartstate": "^2.0.19",
"@push.rocks/smartstream": "^3.2.4", "@push.rocks/smartstream": "^3.2.5",
"@push.rocks/smartstring": "^4.0.15", "@push.rocks/smartstring": "^4.0.15",
"@push.rocks/smartunique": "^3.0.9", "@push.rocks/smartunique": "^3.0.9",
"@push.rocks/taskbuffer": "^3.0.2", "@push.rocks/taskbuffer": "^3.0.2",
"@push.rocks/webjwt": "^1.0.9", "@push.rocks/webjwt": "^1.0.9",
"@tsclass/tsclass": "^4.1.2" "@tsclass/tsclass": "^9.0.0"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",
@ -126,5 +126,6 @@
"frontend", "frontend",
"backend", "backend",
"security" "security"
] ],
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
} }

14717
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
onlyBuiltDependencies:
- esbuild
- mongodb-memory-server
- puppeteer

View File

@ -3,25 +3,48 @@ const testQenv = new Qenv('./', './.nogit/');
import * as cloudly from '../../ts/index.js'; import * as cloudly from '../../ts/index.js';
const stopFunctions: Array<() => Promise<void>> = [];
const tapToolsNodeMod = await import('@push.rocks/tapbundle/node');
const smartmongo = await tapToolsNodeMod.tapNodeTools.createSmartmongo();
stopFunctions.push(async () => {
await smartmongo.stopAndDumpToDir('./.nogit/mongodump');
});
const smarts3 = await tapToolsNodeMod.tapNodeTools.createSmarts3();
await smarts3.createBucket('cloudly-test');
stopFunctions.push(async () => {
await smarts3.stop();
});
export const testCloudlyConfig: cloudly.ICloudlyConfig = {
cfToken: await testQenv.getEnvVarOnDemand('CF_TOKEN'),
environment: 'integration',
letsEncryptEmail: 'test@serve.zone',
publicUrl: '127.0.0.1',
publicPort: '8080',
mongoDescriptor: await smartmongo.getMongoDescriptor(),
s3Descriptor: await smarts3.getS3Descriptor(),
sslMode: 'none',
...(() => {
if (process.env.NPMCI_SECRET01) {
return {
hetznerToken: process.env.NPMCI_SECRET01,
};
}
})(),
};
await tapToolsNodeMod.tapNodeTools.testFileProvider.getDockerAlpineImageAsLocalTarball();
export const createCloudly = async () => { export const createCloudly = async () => {
const cloudlyConfig: cloudly.ICloudlyConfig = { const cloudlyInstance = new cloudly.Cloudly(testCloudlyConfig);
cfToken: await testQenv.getEnvVarOnDemand('CF_TOKEN'),
environment: 'integration',
letsEncryptEmail: await testQenv.getEnvVarOnDemand('LETSENCRYPT_EMAIL'),
publicUrl: await testQenv.getEnvVarOnDemand('SERVEZONE_URL'),
publicPort: await testQenv.getEnvVarOnDemand('SERVEZONE_PORT'),
mongoDescriptor: {
mongoDbName: await testQenv.getEnvVarOnDemand('MONGODB_DATABASE'),
mongoDbUser: await testQenv.getEnvVarOnDemand('MONGODB_USER'),
mongoDbPass: await testQenv.getEnvVarOnDemand('MONGODB_PASSWORD'),
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGODB_URL'),
},
};
const cloudlyInstance = new cloudly.Cloudly();
return cloudlyInstance; return cloudlyInstance;
} };
export const stopCloudly = async () => {
await Promise.all(stopFunctions.map((stopFunction) => stopFunction()));
};
export const getEnvVarOnDemand = async (envVarName: string) => { export const getEnvVarOnDemand = async (envVarName: string) => {
return testQenv.getEnvVarOnDemand(envVarName); return testQenv.getEnvVarOnDemand(envVarName);
} };

View File

@ -33,7 +33,7 @@ tap.preTask('should create a new machine user for testing', async () => {
tap.test('should create a new cloudlyApiClient', async () => { tap.test('should create a new cloudlyApiClient', async () => {
testClient = new cloudlyApiClient.CloudlyApiClient({ testClient = new cloudlyApiClient.CloudlyApiClient({
registerAs: 'api', registerAs: 'api',
cloudlyUrl: `http://localhost:${await helpers.getEnvVarOnDemand('SERVEZONE_PORT')}`, cloudlyUrl: `http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`,
}); });
await testClient.start(); await testClient.start();
expect(testClient).toBeTruthy(); expect(testClient).toBeTruthy();
@ -57,7 +57,7 @@ tap.test('should get an identity', async () => {
let image: Image; let image: Image;
tap.test('should create and upload an image', async () => { tap.test('should create and upload an image', async () => {
image = await testClient.images.createImage({ image = await testClient.image.createImage({
name: 'test', name: 'test',
description: 'test' description: 'test'
}); });
@ -73,6 +73,7 @@ tap.test('should upload an image version', async () => {
tap.test('should stop the apiclient', async (toolsArg) => { tap.test('should stop the apiclient', async (toolsArg) => {
await toolsArg.delayFor(10000); await toolsArg.delayFor(10000);
await helpers.stopCloudly();
await testClient.stop(); await testClient.stop();
await testCloudly.stop(); await testCloudly.stop();
}) })

View File

@ -14,8 +14,10 @@ tap.test('should init cloudly', async () => {
}); });
tap.test('should end the service', async (tools) => { tap.test('should end the service', async (tools) => {
await tools.delayFor(5000);
await helpers.stopCloudly();
await testCloudly.stop(); await testCloudly.stop();
tools.delayFor(1000).then(() => process.exit()) tools.delayFor(1000).then(() => process.exit());
}); });
tap.start(); tap.start();

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/cloudly', name: '@serve.zone/cloudly',
version: '4.3.0', version: '5.0.4',
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.' description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
} }

View File

@ -63,7 +63,7 @@ for (let i = 0; i < demoSecretGroups.length; i++) {
id: `configBundleId${i + 1}`, id: `configBundleId${i + 1}`,
data: { data: {
name: `Demo Config Bundle ${i + 1}`, name: `Demo Config Bundle ${i + 1}`,
includedImages: [], imageClaims: [],
type: 'external', type: 'external',
description: 'Demo Purpose', description: 'Demo Purpose',
includedSecretGroupIds: [secretGroup.id], includedSecretGroupIds: [secretGroup.id],

View File

@ -20,6 +20,7 @@ import { CloudlyTaskmanager } from './manager.task/taskmanager.js';
import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js'; import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js';
import { CloudlyServerManager } from './manager.server/classes.servermanager.js'; import { CloudlyServerManager } from './manager.server/classes.servermanager.js';
import { ExternalApiManager } from './manager.status/statusmanager.js'; import { ExternalApiManager } from './manager.status/statusmanager.js';
import { ExternalRegistryManager } from './manager.externalregistry/index.js';
import { ImageManager } from './manager.image/classes.imagemanager.js'; import { ImageManager } from './manager.image/classes.imagemanager.js';
import { logger } from './logger.js'; import { logger } from './logger.js';
import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js'; import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js';
@ -54,13 +55,16 @@ export class Cloudly {
public clusterManager: ClusterManager; public clusterManager: ClusterManager;
public coreflowManager: CloudlyCoreflowManager; public coreflowManager: CloudlyCoreflowManager;
public externalApiManager: ExternalApiManager; public externalApiManager: ExternalApiManager;
public externalRegistryManager: ExternalRegistryManager;
public imageManager: ImageManager; public imageManager: ImageManager;
public taskManager: CloudlyTaskmanager; public taskManager: CloudlyTaskmanager;
public serverManager: CloudlyServerManager; public serverManager: CloudlyServerManager;
private readyDeferred = new plugins.smartpromise.Deferred(); private readyDeferred = new plugins.smartpromise.Deferred();
constructor() { private configOptions: plugins.servezoneInterfaces.data.ICloudlyConfig;
constructor(configArg?: plugins.servezoneInterfaces.data.ICloudlyConfig) {
this.configOptions = configArg;
this.cloudlyInfo = new CloudlyInfo(this); this.cloudlyInfo = new CloudlyInfo(this);
this.config = new CloudlyConfig(this); this.config = new CloudlyConfig(this);
@ -78,6 +82,7 @@ export class Cloudly {
this.clusterManager = new ClusterManager(this); this.clusterManager = new ClusterManager(this);
this.coreflowManager = new CloudlyCoreflowManager(this); this.coreflowManager = new CloudlyCoreflowManager(this);
this.externalApiManager = new ExternalApiManager(this); this.externalApiManager = new ExternalApiManager(this);
this.externalRegistryManager = new ExternalRegistryManager(this);
this.imageManager = new ImageManager(this); this.imageManager = new ImageManager(this);
this.taskManager = new CloudlyTaskmanager(this); this.taskManager = new CloudlyTaskmanager(this);
this.secretManager = new CloudlySecretManager(this); this.secretManager = new CloudlySecretManager(this);
@ -90,7 +95,7 @@ export class Cloudly {
*/ */
public async start() { public async start() {
// config // config
await this.config.init(); await this.config.init(this.configOptions);
// manageers // manageers
await this.authManager.start(); await this.authManager.start();

View File

@ -15,7 +15,7 @@ export class CloudlyConfig {
this.cloudlyRef = cloudlyRefArg; this.cloudlyRef = cloudlyRefArg;
} }
public async init() { public async init(configArg?: plugins.servezoneInterfaces.data.ICloudlyConfig) {
this.appData = this.appData =
await plugins.npmextra.AppData.createAndInit<plugins.servezoneInterfaces.data.ICloudlyConfig>( await plugins.npmextra.AppData.createAndInit<plugins.servezoneInterfaces.data.ICloudlyConfig>(
{ {
@ -54,6 +54,7 @@ export class CloudlyConfig {
'environment', 'environment',
'mongoDescriptor', 'mongoDescriptor',
], ],
overwriteObject: configArg,
}, },
); );

View File

@ -38,13 +38,13 @@ export class ClusterManager {
console.log(await cluster.createSavableObject()); console.log(await cluster.createSavableObject());
this.cloudlyRef.serverManager.ensureServerInfrastructure(); this.cloudlyRef.serverManager.ensureServerInfrastructure();
return { return {
clusterConfig: await cluster.createSavableObject(), cluster: await cluster.createSavableObject(),
}; };
}), }),
); );
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_GetAllClusters>( this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
new plugins.typedrequest.TypedHandler('getAllClusters', async (dataArg) => { new plugins.typedrequest.TypedHandler('getClusters', async (dataArg) => {
// TODO: do authentication here // TODO: do authentication here
const clusters = await this.getAllClusters(); const clusters = await this.getAllClusters();
return { return {
@ -56,12 +56,12 @@ export class ClusterManager {
); );
// delete cluster // delete cluster
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_DeleteCluster>( this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_DeleteClusterById>(
new plugins.typedrequest.TypedHandler('deleteCluster', async (reqDataArg, toolsArg) => { new plugins.typedrequest.TypedHandler('deleteClusterById', async (reqDataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqDataArg); await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqDataArg);
await this.deleteCluster(reqDataArg.clusterId); await this.deleteCluster(reqDataArg.clusterId);
return { return {
success: true, ok: true,
}; };
}), }),
); );

View File

@ -0,0 +1,40 @@
import * as plugins from '../plugins.js';
import * as paths from '../paths.js';
import type { Cloudly } from 'ts/classes.cloudly.js';
import type { ExternalRegistryManager } from './classes.externalregistrymanager.js';
export class ExternalRegistry extends plugins.smartdata.SmartDataDbDoc<ExternalRegistry, plugins.servezoneInterfaces.data.IExternalRegistry, ExternalRegistryManager> {
// STATIC
public static async getRegistryById(registryIdArg: string) {
const externalRegistry = await this.getInstance({
id: registryIdArg,
});
return externalRegistry;
}
public static async getRegistries() {
const externalRegistries = await this.getInstances({});
return externalRegistries;
}
public static async createExternalRegistry(registryDataArg: Partial<plugins.servezoneInterfaces.data.IExternalRegistry['data']>) {
const externalRegistry = new ExternalRegistry();
externalRegistry.id = await ExternalRegistry.getNewId();
Object.assign(externalRegistry, registryDataArg);
await externalRegistry.save();
return externalRegistry;
}
// INSTANCE
@plugins.smartdata.svDb()
public id: string;
@plugins.smartdata.svDb()
public data: plugins.servezoneInterfaces.data.IExternalRegistry['data'];
constructor() {
super();
}
}

View File

@ -0,0 +1,51 @@
import * as plugins from '../plugins.js';
import { Cloudly } from '../classes.cloudly.js';
import { ExternalRegistry } from './classes.externalregistry.js';
export class ExternalRegistryManager {
public cloudlyRef: Cloudly;
public typedrouter = new plugins.typedrequest.TypedRouter();
public CExternalRegistry = plugins.smartdata.setDefaultManagerForDoc(this, ExternalRegistry);
get db() {
return this.cloudlyRef.mongodbConnector.smartdataDb;
}
constructor(cloudlyRef: Cloudly) {
this.cloudlyRef = cloudlyRef;
}
public async start() {
// lets set up a typedrouter
this.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistryById>(
new plugins.typedrequest.TypedHandler('getExternalRegistryById', async (dataArg) => {
const registry = await ExternalRegistry.getRegistryById(dataArg.id);
return {
registry: await registry.createSavableObject(),
};
})
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistries>(
new plugins.typedrequest.TypedHandler('getExternalRegistries', async (dataArg) => {
const registries = await ExternalRegistry.getRegistries();
return {
registries: await Promise.all(
registries.map((registry) => registry.createSavableObject())
),
};
})
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_CreateRegistry>(
new plugins.typedrequest.TypedHandler('createExternalRegistry', async (dataArg) => {
const registry = await ExternalRegistry.createExternalRegistry(dataArg.registryData);
return {
registry: await registry.createSavableObject(),
};
})
);
}
}

View File

@ -0,0 +1,2 @@
export * from './classes.externalregistrymanager.js';
export * from './classes.externalregistry.js';

View File

@ -59,4 +59,16 @@ export class SecretBundle extends plugins.smartdata.SmartDataDbDoc<
} }
return returnObject; return returnObject;
} }
public async getFlatKeyValueObject(environmentArg: string) {
if (!environmentArg) {
throw new Error('environment is required');
}
const secretGroups = await this.getSecretGroups();
const returnObject = {};
for (const secretGroup of secretGroups) {
returnObject[secretGroup.data.key] = secretGroup.data.environments[environmentArg].value;
}
return returnObject;
}
} }

View File

@ -35,20 +35,71 @@ export class CloudlySecretManager {
this.typedrouter = new plugins.typedrequest.TypedRouter(); this.typedrouter = new plugins.typedrequest.TypedRouter();
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter); this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler( // secretbundle routes
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>( this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
'adminGetConfigBundlesAndSecretGroups', new plugins.typedrequest.TypedHandler(
'getSecretBundles',
async (dataArg, toolsArg) => { async (dataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg); await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
dataArg.identity.jwt; dataArg.identity.jwt;
const secretBundles = await SecretBundle.getInstances({}); const secretBundles = await SecretBundle.getInstances({});
const secretGroups = await SecretGroup.getInstances({});
return { return {
secretBundles: [ secretBundles: [
...(await Promise.all( ...(await Promise.all(
secretBundles.map((configBundle) => configBundle.createSavableObject()), secretBundles.map((configBundle) => configBundle.createSavableObject()),
)), )),
], ],
};
},
),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_CreateSecretBundle>(
new plugins.typedrequest.TypedHandler('createSecretBundle', async (dataArg) => {
const secretBundle = new SecretBundle();
secretBundle.id = plugins.smartunique.shortId(8);
secretBundle.data = dataArg.secretBundle.data;
await secretBundle.save();
return {
resultSecretBundle: await secretBundle.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
new plugins.typedrequest.TypedHandler('updateSecretBundle', async (dataArg) => {
const secretBundle = await SecretBundle.getInstance({
id: dataArg.secretBundle.id,
});
secretBundle.data = dataArg.secretBundle.data;
await secretBundle.save();
return {
resultSecretBundle: await secretBundle.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
new plugins.typedrequest.TypedHandler('deleteSecretBundleById', async (dataArg) => {
const secretBundle = await SecretBundle.getInstance({
id: dataArg.secretBundleId,
});
await secretBundle.delete();
return {
ok: true,
};
}),
);
// secretgroup routes
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroups>(
new plugins.typedrequest.TypedHandler(
'getSecretGroups',
async (dataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
dataArg.identity.jwt;
const secretGroups = await SecretGroup.getInstances({});
return {
secretGroups: [ secretGroups: [
...(await Promise.all( ...(await Promise.all(
secretGroups.map((secretGroup) => secretGroup.createSavableObject()), secretGroups.map((secretGroup) => secretGroup.createSavableObject()),
@ -59,73 +110,64 @@ export class CloudlySecretManager {
), ),
); );
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>( this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_CreateSecretGroup>(
new plugins.typedrequest.TypedHandler( new plugins.typedrequest.TypedHandler('createSecretGroup', async (dataArg) => {
'adminCreateConfigBundlesAndSecretGroups', const secretGroup = new SecretGroup();
async (dataArg) => { secretGroup.id = plugins.smartunique.shortId(8);
for (const secretGroupObject of dataArg.secretGroups) { secretGroup.data = dataArg.secretGroup.data;
const secretGroup = new SecretGroup(); await secretGroup.save();
secretGroup.id = plugins.smartunique.shortId(8); return {
secretGroup.data = secretGroupObject.data; resultSecretGroup: await secretGroup.createSavableObject(),
await secretGroup.save(); };
} }),
return { );
ok: true,
}; this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_UpdateSecretGroup>(
}, new plugins.typedrequest.TypedHandler('updateSecretGroup', async (dataArg) => {
), const secretGroup = await SecretGroup.getInstance({
id: dataArg.secretGroup.id,
});
secretGroup.data = dataArg.secretGroup.data;
await secretGroup.save();
return {
resultSecretGroup: await secretGroup.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
new plugins.typedrequest.TypedHandler('deleteSecretGroupById', async (dataArg) => {
const secretGroup = await SecretGroup.getInstance({
id: dataArg.secretGroupId,
});
await secretGroup.delete();
return {
ok: true,
};
}),
); );
this.typedrouter.addTypedHandler( this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>( new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
'adminDeleteConfigBundlesAndSecretGroups', 'getFlatKeyValueObject',
async (dataArg) => {
for (const secretGroupId of dataArg.secretGroupIds) {
const secretGroup = await SecretGroup.getInstance({
id: secretGroupId,
});
await secretGroup.delete();
}
for (const secretBundleId of dataArg.secretBundleIds) {
const configBundle = await SecretBundle.getInstance({
id: secretBundleId,
});
await configBundle.delete();
console.log(`deleted configbundle ${secretBundleId}`);
}
return {
ok: true,
};
},
),
);
// lets add typedrouter routes for accessing the configvailt from apps
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_GetEnvBundle>(
'getEnvBundle',
async (dataArg) => { async (dataArg) => {
const wantedBundle = await SecretBundle.getInstance({ const wantedBundle = await SecretBundle.getInstance({
data: { data: {
authorizations: { authorizations: {
// @ts-ignore // @ts-ignore
$elemMatch: { $elemMatch: {
secretAccessKey: dataArg.authorization, secretAccessKey: dataArg.secretBundleAuthorization.secretAccessKey,
}, },
}, },
}, },
}); });
const authorization = await wantedBundle.getAuthorizationFromAuthKey( const authorization = await wantedBundle.getAuthorizationFromAuthKey(
dataArg.authorization, dataArg.secretBundleAuthorization.secretAccessKey,
); );
return { return {
envBundle: { flatKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
configKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment( authorization.environment,
authorization.environment, ),
),
environment: authorization.environment,
timeSensitive: false,
},
}; };
}, },
), ),

View File

@ -1,3 +1,4 @@
import { SecretBundle } from 'ts/manager.secret/classes.secretbundle.js';
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
import { ServiceManager } from './classes.servicemanager.js'; import { ServiceManager } from './classes.servicemanager.js';
@ -6,9 +7,51 @@ export class Service extends plugins.smartdata.SmartDataDbDoc<
plugins.servezoneInterfaces.data.IService, plugins.servezoneInterfaces.data.IService,
ServiceManager ServiceManager
> { > {
// STATIC
public static async getServiceById(serviceIdArg: string) {
const service = await this.getInstance({
id: serviceIdArg,
});
return service;
}
public static async getServices() {
const services = await this.getInstances({});
return services;
}
public static async createService(serviceDataArg: Partial<plugins.servezoneInterfaces.data.IService['data']>) {
const service = new Service();
service.id = await Service.getNewId();
Object.assign(service, serviceDataArg);
await service.save();
return service;
}
// INSTANCE
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public id: string; public id: string;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public data: plugins.servezoneInterfaces.data.IService['data']; public data: plugins.servezoneInterfaces.data.IService['data'];
/**
* a service runs in a specific environment
* so -> this method returns the secret bundles as a flat object accordingly.
* in other words, it resolves secret groups for the relevant environment
* @param environmentArg
*/
public async getSecretBundlesAsFlatObject(environmentArg: string = 'production') {
const secreBundleIds = this.data.additionalSecretBundleIds || [];
secreBundleIds.push(this.data.secretBundleId); // put this last, so it overwrites any other secret bundles.
let finalFlatObject = {};
for (const secretBundleId of secreBundleIds) {
const secretBundle = await SecretBundle.getInstance({
id: secretBundleId,
});
const flatObject = await secretBundle.getFlatKeyValueObject(environmentArg);
Object.assign(finalFlatObject, flatObject);
}
return finalFlatObject;
}
} }

View File

@ -14,5 +14,87 @@ export class ServiceManager {
constructor(cloudlyRef: Cloudly) { constructor(cloudlyRef: Cloudly) {
this.cloudlyRef = cloudlyRef; this.cloudlyRef = cloudlyRef;
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
'getServices',
async (reqArg) => {
await plugins.smartguard.passGuardsOrReject(reqArg, [
this.cloudlyRef.authManager.validIdentityGuard,
]);
const services = await this.CService.getInstances({});
return {
services: await Promise.all(
services.map((service) => {
return service.createSavableObject();
})
),
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject>(
'getServiceSecretBundlesAsFlatObject',
async (dataArg) => {
const service = await Service.getInstance({
id: dataArg.serviceId,
});
const flatKeyValueObject = await service.getSecretBundlesAsFlatObject(dataArg.environment);
return {
flatKeyValueObject: flatKeyValueObject,
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_CreateService>(
'createService',
async (dataArg) => {
const service = await Service.createService(dataArg.serviceData);
return {
service: await service.createSavableObject(),
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_UpdateService>(
'updateService',
async (dataArg) => {
const service = await Service.getInstance({
id: dataArg.serviceId,
});
service.data = {
...service.data,
...dataArg.serviceData,
};
await service.save();
return {
service: await service.createSavableObject(),
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_DeleteServiceById>(
'deleteServiceById',
async (dataArg) => {
const service = await Service.getInstance({
id: dataArg.serviceId,
});
await service.delete();
return {
success: true,
};
}
)
);
} }
} }

View File

@ -3,6 +3,11 @@ import * as plugins from './plugins.js';
export type TClientType = 'api' | 'ci' | 'coreflow' | 'cli' | 'serverconfig'; export type TClientType = 'api' | 'ci' | 'coreflow' | 'cli' | 'serverconfig';
import { Image } from './classes.image.js'; import { Image } from './classes.image.js';
import { Service } from './classes.service.js';
import { Cluster } from './classes.cluster.js';
import { SecretBundle } from './classes.secretbundle.js';
import { SecretGroup } from './classes.secretgroup.js';
import { ExternalRegistry } from './classes.externalregistry.js';
export class CloudlyApiClient { export class CloudlyApiClient {
private cloudlyUrl: string; private cloudlyUrl: string;
@ -20,7 +25,7 @@ export class CloudlyApiClient {
plugins.servezoneInterfaces.requests.server.IRequest_TriggerServerAction['request'] plugins.servezoneInterfaces.requests.server.IRequest_TriggerServerAction['request']
>(); >();
constructor(optionsArg?: { constructor(optionsArg: {
registerAs: TClientType; registerAs: TClientType;
cloudlyUrl?: string; cloudlyUrl?: string;
}) { }) {
@ -155,8 +160,24 @@ export class CloudlyApiClient {
return typedResponse.certificate; return typedResponse.certificate;
} }
public images = { public externalRegistry = {
// ExternalRegistry
getRegistryById: async (registryNameArg: string) => {
return ExternalRegistry.getExternalRegistryById(this, registryNameArg);
},
getRegistries: async () => {
return ExternalRegistry.getExternalRegistries(this);
},
createRegistry: async (optionsArg: Parameters<typeof ExternalRegistry.createExternalRegistry>[1]) => {
return ExternalRegistry.createExternalRegistry(this, optionsArg);
}
}
public image = {
// Images // Images
getImageById: async (imageIdArg: string) => {
return Image.getImageById(this, imageIdArg);
},
getImages: async () => { getImages: async () => {
return Image.getImages(this); return Image.getImages(this);
}, },
@ -164,4 +185,56 @@ export class CloudlyApiClient {
return Image.createImage(this, optionsArg); return Image.createImage(this, optionsArg);
} }
} }
public services = {
// Services
getServiceById: async (serviceIdArg: string) => {
return Service.getServiceById(this, serviceIdArg);
},
getServices: async () => {
return Service.getServices(this);
},
createService: async (optionsArg: Parameters<typeof Service.createService>[1]) => {
return Service.createService(this, optionsArg);
}
}
public cluster = {
// Clusters
getClusterById: async (clusterIdArg: string) => {
return Cluster.getClusterById(this, clusterIdArg);
},
getClusters: async () => {
return Cluster.getClusters(this);
},
createCluster: async (optionsArg: Parameters<typeof Cluster.createCluster>[1]) => {
return Cluster.createCluster(this, optionsArg);
}
}
public secretbundle = {
// SecretBundles
getSecretBundleById: async (secretBundleIdArg: string) => {
return SecretBundle.getSecretBundleById(this, secretBundleIdArg);
},
getSecretBundles: async () => {
return SecretBundle.getSecretBundles(this);
},
createSecretBundle: async (optionsArg: Parameters<typeof SecretBundle.createSecretBundle>[1]) => {
return SecretBundle.createSecretBundle(this, optionsArg);
}
}
public secretgroup = {
// SecretGroups
getSecretGroupById: async (secretGroupIdArg: string) => {
return SecretGroup.getSecretGroupById(this, secretGroupIdArg);
},
getSecretGroups: async () => {
return SecretGroup.getSecretGroups(this);
},
createSecretGroup: async (optionsArg: Parameters<typeof SecretGroup.createSecretGroup>[1]) => {
return SecretGroup.createSecretGroup(this, optionsArg);
}
}
} }

View File

@ -1,6 +1,84 @@
import { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
export class Cluster { export class Cluster implements plugins.servezoneInterfaces.data.ICluster {
public getServers() {} // STATIC
public static async getClusterById(cloudlyClientRef: CloudlyApiClient, clusterIdArg: string) {
const getClusterByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusterById>(
'getClusterById'
);
const response = await getClusterByIdTR.fire({
identity: cloudlyClientRef.identity,
clusterId: clusterIdArg,
});
const newCluster = new Cluster(cloudlyClientRef);
Object.assign(newCluster, response.cluster);
return newCluster;
}
public static async getClusters(cloudlyClientRef: CloudlyApiClient) {
const getClustersTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
'getClusters'
);
const response = await getClustersTR.fire({
identity: cloudlyClientRef.identity,
});
const clusterConfigs: Cluster[] = [];
for (const clusterConfig of response.clusters) {
const newCluster = new Cluster(cloudlyClientRef);
Object.assign(newCluster, clusterConfig);
clusterConfigs.push(newCluster);
}
return clusterConfigs;
}
public static async createCluster(cloudlyClientRef: CloudlyApiClient, clusterNameArg: string) {
const createClusterTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IRequest_CreateCluster>(
'createCluster'
);
const response = await createClusterTR.fire({
identity: cloudlyClientRef.identity,
clusterName: clusterNameArg,
});
const newCluster = new Cluster(cloudlyClientRef);
Object.assign(newCluster, response.cluster);
return newCluster;
}
// INSTANCE
public id: string;
public data: plugins.servezoneInterfaces.data.ICluster['data'];
public cloudlyClientRef: CloudlyApiClient;
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async update() {
const updateClusterTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_UpdateCluster>(
'updateCluster'
);
const response = await updateClusterTR.fire({
identity: this.cloudlyClientRef.identity,
clusterData: this.data,
});
const resultClusterData = response.resultCluster.data;
plugins.smartexpect.expect(resultClusterData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, clusterIdArg: string) {
const deleteClusterTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_DeleteClusterById>(
'deleteClusterById'
);
const response = await deleteClusterTR.fire({
identity: cloudlyClientRef.identity,
clusterId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
} }

View File

@ -0,0 +1,83 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class ExternalRegistry implements plugins.servezoneInterfaces.data.IExternalRegistry {
// STATIC
public static async getExternalRegistryById(cloudlyClientRef: CloudlyApiClient, registryNameArg: string) {
const getRegistryByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistryById>(
'getExternalRegistryById'
);
const response = await getRegistryByIdTR.fire({
identity: cloudlyClientRef.identity,
id: registryNameArg,
});
const newRegistry = new ExternalRegistry(cloudlyClientRef);
Object.assign(newRegistry, response.registry);
return newRegistry;
}
public static async getExternalRegistries(cloudlyClientRef: CloudlyApiClient) {
const getRegistriesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistries>(
'getExternalRegistries'
);
const response = await getRegistriesTR.fire({
identity: cloudlyClientRef.identity,
});
const registryConfigs: ExternalRegistry[] = [];
for (const registryConfig of response.registries) {
const newRegistry = new ExternalRegistry(cloudlyClientRef);
Object.assign(newRegistry, registryConfig);
registryConfigs.push(newRegistry);
}
return registryConfigs;
}
public static async createExternalRegistry(cloudlyClientRef: CloudlyApiClient, registryDataArg: Partial<plugins.servezoneInterfaces.data.IExternalRegistry['data']>) {
const createRegistryTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_CreateRegistry>(
'createExternalRegistry'
);
const response = await createRegistryTR.fire({
identity: cloudlyClientRef.identity,
registryData: registryDataArg as plugins.servezoneInterfaces.data.IExternalRegistry['data'],
});
const newRegistry = new ExternalRegistry(cloudlyClientRef);
Object.assign(newRegistry, response.registry);
return newRegistry;
}
// INSTANCE
public id: string;
public data: plugins.servezoneInterfaces.data.IExternalRegistry['data'];
public cloudlyClientRef: CloudlyApiClient;
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async update() {
const updateRegistryTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_UpdateRegistry>(
'updateExternalRegistry'
);
const response = await updateRegistryTR.fire({
identity: this.cloudlyClientRef.identity,
registryData: this.data,
});
const resultRegistryData = response.resultRegistry.data;
plugins.smartexpect.expect(resultRegistryData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, registryIdArg: string) {
const deleteRegistryTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_DeleteRegistryById>(
'deleteExternalRegistryById'
);
const response = await deleteRegistryTR.fire({
identity: cloudlyClientRef.identity,
registryId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
}

View File

@ -18,6 +18,19 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
return resultImages; return resultImages;
} }
public static async getImageById(cloudlyClientRef: CloudlyApiClient, imageIdArg: string) {
const getImageByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_GetImage>(
'getImage'
);
const response = await getImageByIdTR.fire({
identity: cloudlyClientRef.identity,
imageId: imageIdArg,
});
const newImage = new Image(cloudlyClientRef);
Object.assign(newImage, response.image);
return newImage;
}
/** /**
* creates a new image * creates a new image
*/ */

View File

@ -0,0 +1,135 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import { SecretGroup } from './classes.secretgroup.js';
export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBundle {
// STATIC
public static async getSecretBundleById(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
const getSecretBundleByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleById>(
'getSecretBundleById'
);
const response = await getSecretBundleByIdTR.fire({
identity: cloudlyClientRef.identity,
secretBundleId: secretBundleIdArg,
});
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, response.secretBundle);
return newSecretBundle;
}
public static async getSecretBundleByAuthorization(cloudlyClientRef: CloudlyApiClient, secretBundleAuthorizationArg: plugins.servezoneInterfaces.data.ISecretBundleAuthorization) {
const getSecretBundleByAuthorizationTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleByAuthorization>(
'getSecretBundleByAuthorization'
);
const response = await getSecretBundleByAuthorizationTR.fire({
identity: cloudlyClientRef.identity,
secretBundleAuthorization: secretBundleAuthorizationArg,
});
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, response.secretBundle);
return newSecretBundle;
}
public static async getSecretBundles(cloudlyClientRef: CloudlyApiClient) {
const getSecretBundlesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
'getSecretBundles'
);
const response = await getSecretBundlesTR.fire({
identity: cloudlyClientRef.identity,
});
const secretBundles: SecretBundle[] = [];
for (const secretBundle of response.secretBundles) {
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, secretBundle);
secretBundles.push(newSecretBundle);
}
return secretBundles;
}
public static async createSecretBundle(cloudlyClientRef: CloudlyApiClient, secretBundleDataArg: Partial<plugins.servezoneInterfaces.data.ISecretBundle['data']>) {
const createSecretBundleTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_CreateSecretBundle>(
'createSecretBundle'
);
const response = await createSecretBundleTR.fire({
identity: cloudlyClientRef.identity,
secretBundle: {
id: null,
data: {
name: secretBundleDataArg.name,
description: secretBundleDataArg.description,
type: secretBundleDataArg.type,
authorizations: secretBundleDataArg.authorizations,
imageClaims: secretBundleDataArg.imageClaims,
includedSecretGroupIds: secretBundleDataArg.includedSecretGroupIds,
includedTags: secretBundleDataArg.includedTags,
},
},
});
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, response.resultSecretBundle);
return newSecretBundle;
}
// INSTANCE
public cloudlyClientRef: CloudlyApiClient;
public id: string;
public data: plugins.servezoneInterfaces.data.ISecretBundle['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async update() {
const updateSecretBundleTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
'updateSecretBundle'
);
const response = await updateSecretBundleTR.fire({
identity: this.cloudlyClientRef.identity,
secretBundle: {
id: this.id,
data: this.data,
},
});
const resultSecretBundleData = response.resultSecretBundle.data;
plugins.smartexpect.expect(resultSecretBundleData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
const deleteSecretBundleTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
'deleteSecretBundleById'
);
const response = await deleteSecretBundleTR.fire({
identity: cloudlyClientRef.identity,
secretBundleId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
public async getFlatKeyValueObjectForEnvironment(environmentArg: string = 'production') {
const bundleAuthorization = this.data.authorizations.find(authorization => {
return authorization.environment === environmentArg;
});
if (bundleAuthorization) {
throw new Error(`no matching environment >>${environmentArg} found in secret bundle`);
}
const getFlatKeyValueObjectTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
'getFlatKeyValueObject'
);
const response = await getFlatKeyValueObjectTR.fire({
identity: this.cloudlyClientRef.identity,
seccretBundleId: this.id,
secretBundleAuthorization: bundleAuthorization,
});
const flatKeyValueObject: {[key: string]: string} = response.flatKeyValueObject;
return flatKeyValueObject;
}
}

View File

@ -0,0 +1,96 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class SecretGroup implements plugins.servezoneInterfaces.data.ISecretGroup {
public cloudlyClientRef: CloudlyApiClient;
public id: string;
public data: plugins.servezoneInterfaces.data.ISecretGroup['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public static async getSecretGroupById(cloudlyClientRef: CloudlyApiClient, secretGroupIdArg: string) {
const getSecretGroupByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroupById>(
'getSecretGroupById'
);
const response = await getSecretGroupByIdTR.fire({
identity: cloudlyClientRef.identity,
secretGroupId: secretGroupIdArg,
});
const newSecretGroup = new SecretGroup(cloudlyClientRef);
Object.assign(newSecretGroup, response.secretGroup);
return newSecretGroup;
}
public static async getSecretGroups(cloudlyClientRef: CloudlyApiClient) {
const getSecretGroupsTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroups>(
'getSecretGroups'
);
const response = await getSecretGroupsTR.fire({
identity: cloudlyClientRef.identity,
});
const secretGroups: SecretGroup[] = [];
for (const secretGroup of response.secretGroups) {
const newSecretGroup = new SecretGroup(cloudlyClientRef);
Object.assign(newSecretGroup, secretGroup);
secretGroups.push(newSecretGroup);
}
return secretGroups;
}
public static async createSecretGroup(cloudlyClientRef: CloudlyApiClient, secretGroupDataArg: Partial<plugins.servezoneInterfaces.data.ISecretGroup['data']>) {
const createSecretGroupTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_CreateSecretGroup>(
'createSecretGroup'
);
const response = await createSecretGroupTR.fire({
identity: cloudlyClientRef.identity,
secretGroup: {
id: null,
data: {
name: secretGroupDataArg.name,
description: secretGroupDataArg.description,
environments: secretGroupDataArg.environments,
key: secretGroupDataArg.key,
tags: secretGroupDataArg.tags,
priority: secretGroupDataArg.priority,
},
},
});
const newSecretGroup = new SecretGroup(cloudlyClientRef);
Object.assign(newSecretGroup, response.resultSecretGroup);
return newSecretGroup;
}
// INSTANCE
public async update() {
const updateSecretGroupTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_UpdateSecretGroup>(
'updateSecretGroup'
);
const response = await updateSecretGroupTR.fire({
identity: this.cloudlyClientRef.identity,
secretGroup: {
id: this.id,
data: this.data,
},
});
const resultSecretGroupData = response.resultSecretGroup.data;
plugins.smartexpect.expect(resultSecretGroupData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, secretGroupIdArg: string) {
const deleteSecretGroupTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
'deleteSecretGroupById'
);
const response = await deleteSecretGroupTR.fire({
identity: cloudlyClientRef.identity,
secretGroupId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
}

View File

@ -1,5 +1,78 @@
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class Service { export class Service implements plugins.servezoneInterfaces.data.IService {
public static async getServices(cloudlyClientRef: CloudlyApiClient) {
const getAllServicesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
'getServices'
);
const response = await getAllServicesTR.fire({
identity: cloudlyClientRef.identity,
});
const resultServices: Service[] = [];
for (const service of response.services) {
const newService = new Service(cloudlyClientRef);
Object.assign(newService, service);
resultServices.push(newService);
}
return resultServices;
}
public static async getServiceById(cloudlyClientRef: CloudlyApiClient, serviceIdArg: string) {
const getServiceByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceById>(
'getServiceById'
);
const response = await getServiceByIdTR.fire({
identity: cloudlyClientRef.identity,
serviceId: serviceIdArg,
});
const newService = new Service(cloudlyClientRef);
Object.assign(newService, response.service);
return newService;
}
/**
* creates a new service
*/
public static async createService(cloudlyClientRef: CloudlyApiClient, serviceDataArg: Partial<plugins.servezoneInterfaces.data.IService['data']>) {
const createServiceTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_CreateService>(
'createService'
);
const response = await createServiceTR.fire({
identity: cloudlyClientRef.identity,
serviceData: serviceDataArg as plugins.servezoneInterfaces.data.IService['data'],
});
const newService = new Service(cloudlyClientRef);
Object.assign(newService, response.service);
return newService;
}
// INSTANCE
cloudlyClientRef: CloudlyApiClient;
public id: string;
public data: plugins.servezoneInterfaces.data.IService['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
/**
* The service has a secret bundle.
* This function essentially returns the secret bundle as a flat object.
* In other words, it resolves secret groups and
*/
public async getSecretBundleAsFlatObject(environmentArg: string = 'production') {
const getServiceSecretBundlesAsFlatObjectTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject>(
'getServiceSecretBundlesAsFlatObject'
);
const response = await getServiceSecretBundlesAsFlatObjectTR.fire({
identity: this.cloudlyClientRef.identity,
serviceId: this.id,
environment: environmentArg,
});
const flatKeyValueObject: {[key: string]: string} = response.flatKeyValueObject;
return flatKeyValueObject;
}
} }

View File

@ -6,11 +6,13 @@ export {
} }
// @push.rocks scope // @push.rocks scope
import * as smartexpect from '@push.rocks/smartexpect';
import * as smartpromise from '@push.rocks/smartpromise'; import * as smartpromise from '@push.rocks/smartpromise';
import * as smartrx from '@push.rocks/smartrx'; import * as smartrx from '@push.rocks/smartrx';
import * as webstream from '@push.rocks/smartstream/web'; import * as webstream from '@push.rocks/smartstream/web';
export { export {
smartexpect,
smartpromise, smartpromise,
smartrx, smartrx,
webstream, webstream,

View File

@ -0,0 +1,15 @@
import * as plugins from './plugins.js';
import { CloudlyApiClient } from '@serve.zone/api';
export class CliClient {
public cloudlyApiClient: CloudlyApiClient;
constructor(cloudlyApiClientArg: CloudlyApiClient) {
this.cloudlyApiClient = cloudlyApiClientArg;
}
public async getClusters() {
const clusters = await this.cloudlyApiClient.cluster.getClusters();
console.log(clusters);
}
}

View File

@ -1 +1,11 @@
console.log('this is the cli client.'); import * as plugins from './plugins.js';
import { CliClient } from "./classes.cliclient.js";
export const runCli = async () => {
const cliQenv = new plugins.qenv.Qenv();
const apiClient = new plugins.servezoneApi.CloudlyApiClient({
registerAs: 'cli',
cloudlyUrl: await cliQenv.getEnvVarOnDemand('CLOUDLY_URL'),
});
const cliClient = new CliClient(apiClient);
};

17
ts_cliclient/plugins.ts Normal file
View File

@ -0,0 +1,17 @@
// @serve.zone scope
import * as servezoneApi from '@serve.zone/api';
import * as servezoneInterfaces from '@serve.zone/interfaces';
export {
servezoneApi,
servezoneInterfaces
}
// @push.rocks scope
import * as projectinfo from '@push.rocks/projectinfo';
import * as qenv from '@push.rocks/qenv';
export {
projectinfo,
qenv,
}

View File

@ -1,8 +1,15 @@
{ {
"name": "@serve.zone/cli", "name": "@serve.zone/cli",
"dependencies": [], "dependencies": [
"@serve.zone/api",
"@serve.zone/interfaces",
"@push.rocks/projectinfo",
"@push.rocks/qenv",
"@push.rocks/smartcli"
],
"registries": [ "registries": [
"registry.npmjs.org:public", "registry.npmjs.org:public",
"verdaccio.lossless.digital:public" "verdaccio.lossless.digital:public"
] ],
"bin": ["servezone"]
} }

View File

@ -1,12 +1,11 @@
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
/** /**
* results from a DeploymentDirective * a deployment happens when a service is deployed
* tracks the status of a deployment * tracks the status of a deployment
*/ */
export interface IDeployment { export interface IDeployment {
id: string; id: string;
deploymentDirectiveId: string;
affectedServiceIds: string[]; affectedServiceIds: string[];
usedImageId: string; usedImageId: string;
deploymentLog: string[]; deploymentLog: string[];

View File

@ -1,14 +0,0 @@
import type { IServiceRessources } from "./docker.js";
/**
* used for tellilng a cluster about a disired deployment
* and specifies its configuration
*/
export interface IDeploymentDirective {
id: string;
name: string;
imageClaim: string;
ports: { hostPort: number; containerPort: number }[];
environment: { [key: string]: string };
resources?: IServiceRessources;
}

View File

@ -1,6 +0,0 @@
export interface IEnvBundle {
environment: string;
timeSensitive: boolean;
configKeyValueObject: {[key: string]: string};
}

View File

@ -0,0 +1,12 @@
import * as plugins from '../plugins.js';
export interface IExternalRegistry {
id: string;
data: {
type: 'docker' | 'npm';
name: string;
url: string;
username: string;
password: string;
};
}

View File

@ -4,6 +4,11 @@ export interface IImage {
id: string; id: string;
data: { data: {
name: string; name: string;
location: {
internal: boolean;
externalRegistryId: string;
externalImageTag: string;
}
description: string; description: string;
versions: Array<{ versions: Array<{
versionString: string; versionString: string;

View File

@ -2,10 +2,9 @@ export * from './cloudlyconfig.js';
export * from './cluster.js'; export * from './cluster.js';
export * from './config.js'; export * from './config.js';
export * from './deployment.js'; export * from './deployment.js';
export * from './deploymentdirective.js';
export * from './docker.js'; export * from './docker.js';
export * from './env.js';
export * from './event.js'; export * from './event.js';
export * from './externalregistry.js';
export * from './image.js'; export * from './image.js';
export * from './secretbundle.js'; export * from './secretbundle.js';
export * from './secretgroup.js' export * from './secretgroup.js'

View File

@ -7,16 +7,33 @@ export interface ISecretBundle {
/** /**
* determines if the secret is a service or an external secret * determines if the secret is a service or an external secret
* if external secret additional checks are put in place to protect the secret * if external secret additional checks are put in place to protect the secret
*
* * service:
* the bundle belongs to a service and can only be used by that service
* * npmci:
* the bundle is a secret bundle that is used by an npmci pipeline
* production secrets will be omitted in any case
* * gitzone:
* the bundle is a secret bundle that is used by a gitzone.
* Only local environment variables are allowed
* * external:
* the bundle is a secret bundle that is used by an external service
*/ */
type: 'service' | 'npmci' | 'gitzone' | 'external'; type: 'service' | 'npmci' | 'gitzone' | 'external';
/**
* set this if the secretBundle belongs to a service
*/
serviceId?: string;
/** /**
* You can add specific secret groups using this * You can add specific secret groups using this
*/ */
includedSecretGroupIds: string[]; includedSecretGroupIds: string[];
/** /**
* You can add specific tags using this * access to this secretBundle also grants access to resources with matching tags
*/ */
includedTags: { includedTags: {
key: string; key: string;
@ -24,19 +41,21 @@ export interface ISecretBundle {
}[]; }[];
/** /**
* add images * access to this secretBundle also grants access to the images
*/ */
includedImages: { imageClaims: {
imageId: string; imageId: string;
permissions: ('read' | 'write')[]; permissions: ('read' | 'write')[];
}[]; }[];
/** /**
* authrozations select a specific environment of a config bundle * authrozations select a specific environment of a config bundle
*/ */
authorizations: Array<{ authorizations: Array<ISecretBundleAuthorization>;
secretAccessKey: string;
environment: string;
}>;
}; };
} }
export interface ISecretBundleAuthorization {
secretAccessKey: string;
environment: string;
}

View File

@ -4,10 +4,19 @@ export interface IService {
id: string; id: string;
data: { data: {
name: string; name: string;
description: string;
imageId: string; imageId: string;
imageVersion: string; imageVersion: string;
environment: { [key: string]: string }; environment: { [key: string]: string };
/**
* the main secret bundle id, exclusive to the service
*/
secretBundleId: string; secretBundleId: string;
/**
* those secret bundle ids do not belong to the service itself
* and thus live past the service lifecycle
*/
additionalSecretBundleIds?: string[];
scaleFactor: number; scaleFactor: number;
balancingStrategy: 'round-robin' | 'least-connections'; balancingStrategy: 'round-robin' | 'least-connections';
ports: { ports: {
@ -21,6 +30,5 @@ export interface IService {
protocol?: 'http' | 'https' | 'ssh'; protocol?: 'http' | 'https' | 'ssh';
}[]; }[];
deploymentIds: string[]; deploymentIds: string[];
deploymentDirectiveIds: string[];
}; };
} }

View File

@ -2,9 +2,9 @@ import * as plugins from '../plugins.js';
export type TTemplates = 'default' | 'linkaction' | 'notification'; export type TTemplates = 'default' | 'linkaction' | 'notification';
export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_SendEmail extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendEmail IReq_SendEmail
> { > {
method: 'sendEmail'; method: 'sendEmail';
request: { request: {
@ -25,9 +25,9 @@ export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.imple
}; };
} }
export interface IRequestRegisterRecipient extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_RegisterRecipient extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequestRegisterRecipient IReq_RegisterRecipient
> { > {
method: 'registerRecepient'; method: 'registerRecepient';
request: { request: {
@ -37,3 +37,34 @@ export interface IRequestRegisterRecipient extends plugins.typedrequestInterface
status: 'ok' | 'not ok'; status: 'ok' | 'not ok';
}; };
} }
export interface IReq_CheckEmailStatus extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CheckEmailStatus
> {
method: 'checkEmailStatus';
request: {
emailId: string;
};
response: {
status: string,
details?: { message: string; }
};
}
export interface IReq_GetEMailStats extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetEMailStats
> {
method: 'getEmailStats';
request: {
jwt: string;
};
response: {
totalEmailsSent: number;
totalEmailsDelivered: number;
totalEmailsBounced: number;
averageDeliveryTimeMs: number;
lastUpdated: string;
};
}

View File

@ -0,0 +1,16 @@
import * as plugins from '../plugins.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_LoginWithUsernameAndPassword
> {
method: 'adminLoginWithUsernameAndPassword';
request: {
username: string;
password: string;
};
response: {
identity: userInterfaces.IIdentity;
}
}

View File

@ -5,11 +5,11 @@ import * as plugins from '../plugins.js';
/** /**
* get all clusters * get all clusters
*/ */
export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_Any_Cloudly_GetClusters extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_GetAllClusters IReq_Any_Cloudly_GetClusters
> { > {
method: 'getAllClusters'; method: 'getClusters';
request: { request: {
identity: userInterfaces.IIdentity; identity: userInterfaces.IIdentity;
}; };
@ -18,6 +18,21 @@ export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.
}; };
} }
export interface IReq_Any_Cloudly_GetClusterById
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Any_Cloudly_GetClusterById
> {
method: 'getClusterById';
request: {
identity: userInterfaces.IIdentity;
clusterId: string;
};
response: {
cluster: clusterInterfaces.ICluster;
};
}
export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.implementsTR< export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_CreateCluster IRequest_CreateCluster
@ -28,40 +43,40 @@ export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.i
clusterName: string; clusterName: string;
}; };
response: { response: {
clusterConfig: clusterInterfaces.ICluster; cluster: clusterInterfaces.ICluster;
}; };
} }
/** /**
* updates a cluster * updates a cluster
*/ */
export interface IRequest_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_Any_Cloudly_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_UpdateCluster IReq_Any_Cloudly_UpdateCluster
> { > {
method: 'updateCluster'; method: 'updateCluster';
request: { request: {
identity: userInterfaces.IIdentity; identity: userInterfaces.IIdentity;
clusterConfig: clusterInterfaces.ICluster; clusterData: clusterInterfaces.ICluster['data'];
}; };
response: { response: {
clusterConfig: clusterInterfaces.ICluster; resultCluster: clusterInterfaces.ICluster;
}; };
} }
/** /**
* deletes a cluster * deletes a cluster
*/ */
export interface IRequest_DeleteCluster extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_Any_Cloudly_DeleteClusterById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_DeleteCluster IReq_Any_Cloudly_DeleteClusterById
> { > {
method: 'deleteCluster'; method: 'deleteClusterById';
request: { request: {
identity: userInterfaces.IIdentity; identity: userInterfaces.IIdentity;
clusterId: string; clusterId: string;
}; };
response: { response: {
success: boolean; ok: boolean;
}; };
} }

View File

@ -3,7 +3,6 @@ import * as clusterInterfaces from '../data/cluster.js';
import * as serverInterfaces from '../data/server.js'; import * as serverInterfaces from '../data/server.js';
import * as userInterfaces from '../data/user.js'; import * as userInterfaces from '../data/user.js';
import type { IService } from '../data/service.js'; import type { IService } from '../data/service.js';
import type { IDeploymentDirective } from '../data/deploymentdirective.js';
export interface IRequest_Any_Cloudly_GetServerConfig export interface IRequest_Any_Cloudly_GetServerConfig
extends plugins.typedrequestInterfaces.implementsTR< extends plugins.typedrequestInterfaces.implementsTR<
@ -31,7 +30,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
}; };
response: { response: {
configData: clusterInterfaces.ICluster; configData: clusterInterfaces.ICluster;
deploymentDirectives: IDeploymentDirective[]; services: IService[];
}; };
} }
@ -43,7 +42,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
method: 'pushClusterConfig'; method: 'pushClusterConfig';
request: { request: {
configData: clusterInterfaces.ICluster; configData: clusterInterfaces.ICluster;
deploymentDirectives: IDeploymentDirective[]; services: IService[];
}; };
response: {}; response: {};
} }

View File

@ -0,0 +1,72 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetRegistryById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetRegistryById
> {
method: 'getExternalRegistryById';
request: {
identity: userInterfaces.IIdentity;
id: string;
};
response: {
registry: data.IExternalRegistry;
};
}
export interface IReq_GetRegistries extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetRegistries
> {
method: 'getExternalRegistries';
request: {
identity: userInterfaces.IIdentity;
};
response: {
registries: data.IExternalRegistry[];
};
}
export interface IReq_CreateRegistry extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateRegistry
> {
method: 'createExternalRegistry';
request: {
identity: userInterfaces.IIdentity;
registryData: data.IExternalRegistry['data'];
};
response: {
registry: data.IExternalRegistry;
};
}
export interface IReq_UpdateRegistry extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_UpdateRegistry
> {
method: 'updateExternalRegistry';
request: {
identity: userInterfaces.IIdentity;
registryData: data.IExternalRegistry['data'];
};
response: {
resultRegistry: data.IExternalRegistry;
};
}
export interface IReq_DeleteRegistryById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_DeleteRegistryById
> {
method: 'deleteExternalRegistryById';
request: {
identity: userInterfaces.IIdentity;
registryId: string;
};
response: {
ok: boolean;
};
}

View File

@ -18,6 +18,7 @@ export interface IRequest_GetAllImages extends plugins.typedrequestInterfaces.im
/** /**
* gets a single image * gets a single image
* authentication can happen via imageClaim or identity
*/ */
export interface IRequest_GetImage extends plugins.typedrequestInterfaces.implementsTR< export interface IRequest_GetImage extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,

View File

@ -1,31 +1,39 @@
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
import * as adminRequests from './admin.js';
import * as certificateRequests from './certificate.js'; import * as certificateRequests from './certificate.js';
import * as clusterRequests from './cluster.js'; import * as clusterRequests from './cluster.js';
import * as configRequests from './config.js'; import * as configRequests from './config.js';
import * as externalRegistryRequests from './externalregistry.js';
import * as identityRequests from './identity.js'; import * as identityRequests from './identity.js';
import * as imageRequests from './image.js'; import * as imageRequests from './image.js';
import * as informRequests from './inform.js'; import * as informRequests from './inform.js';
import * as logRequests from './log.js'; import * as logRequests from './log.js';
import * as networkRequests from './network.js'; import * as networkRequests from './network.js';
import * as routingRequests from './routing.js'; import * as routingRequests from './routing.js';
import * as secretRequests from './secret.js'; import * as secretBundleRequests from './secretbundle.js';
import * as secretGroupRequests from './secretgroup.js';
import * as serverRequests from './server.js'; import * as serverRequests from './server.js';
import * as serviceRequests from './service.js';
import * as statusRequests from './status.js'; import * as statusRequests from './status.js';
import * as versionRequests from './version.js'; import * as versionRequests from './version.js';
export { export {
adminRequests as admin,
certificateRequests as certificate, certificateRequests as certificate,
clusterRequests as cluster, clusterRequests as cluster,
configRequests as config, configRequests as config,
externalRegistryRequests as externalRegistry,
identityRequests as identity, identityRequests as identity,
imageRequests as image, imageRequests as image,
informRequests as inform, informRequests as inform,
logRequests as log, logRequests as log,
networkRequests as network, networkRequests as network,
routingRequests as routing, routingRequests as routing,
secretRequests as secret, secretBundleRequests as secretbundle,
secretGroupRequests as secretgroup,
serverRequests as server, serverRequests as server,
serviceRequests as service,
statusRequests as status, statusRequests as status,
versionRequests as version, versionRequests as version,
}; };

View File

@ -1,94 +0,0 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetEnvBundle extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetEnvBundle
> {
method: 'getEnvBundle';
request: {
authorization: string;
/**
* specify this if you want to get a warning, if the envBundle is for an unexpected environment
*/
environment?: string;
};
response: {
envBundle: data.IEnvBundle;
};
}
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_LoginWithUsernameAndPassword
> {
method: 'adminLoginWithUsernameAndPassword';
request: {
username: string;
password: string;
};
response: {
identity: userInterfaces.IIdentity;
}
}
export interface IReq_Admin_GetConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_GetConfigBundlesAndSecretGroups
> {
method: 'adminGetConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
};
response: {
secretBundles: data.ISecretBundle[];
secretGroups: data.ISecretGroup[];
};
}
export interface IReq_Admin_CreateConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_CreateConfigBundlesAndSecretGroups
> {
method: 'adminCreateConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
secretBundles: data.ISecretBundle[];
secretGroups: data.ISecretGroup[];
};
response: {
ok: boolean;
};
}
export interface IReq_Admin_UpdateConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_UpdateConfigBundlesAndSecretGroups
> {
method: 'adminUpdateConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
configBundles: data.ISecretBundle[];
secretGroups: data.ISecretGroup[];
};
response: {
ok: boolean;
};
}
export interface IReq_Admin_DeleteConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_DeleteConfigBundlesAndSecretGroups
> {
method: 'adminDeleteConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
secretBundleIds: string[];
secretGroupIds: string[];
};
response: {
ok: boolean;
};
}

View File

@ -0,0 +1,103 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetSecretBundles extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundles
> {
method: 'getSecretBundles';
request: {
identity: userInterfaces.IIdentity;
};
response: {
secretBundles: data.ISecretBundle[];
};
}
export interface IReq_GetSecretBundleById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundleById
> {
method: 'getSecretBundleById';
request: {
identity: userInterfaces.IIdentity;
secretBundleId: string;
};
response: {
secretBundle: data.ISecretBundle;
};
}
export interface IReq_CreateSecretBundle extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateSecretBundle
> {
method: 'createSecretBundle';
request: {
identity: userInterfaces.IIdentity;
secretBundle: data.ISecretBundle;
};
response: {
resultSecretBundle: data.ISecretBundle;
};
}
export interface IReq_UpdateSecretBundle extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_UpdateSecretBundle
> {
method: 'updateSecretBundle';
request: {
identity: userInterfaces.IIdentity;
secretBundle: data.ISecretBundle;
};
response: {
resultSecretBundle: data.ISecretBundle;
};
}
export interface IReq_DeleteSecretBundleById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_DeleteSecretBundleById
> {
method: 'deleteSecretBundleById';
request: {
identity: userInterfaces.IIdentity;
secretBundleId: string;
};
response: {
ok: boolean;
};
}
export interface IReq_GetSecretBundleByAuthorization extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundleByAuthorization
> {
method: 'getSecretBundleByAuthorization';
request: {
identity: userInterfaces.IIdentity;
secretBundleAuthorization: data.ISecretBundleAuthorization;
};
response: {
secretBundle: data.ISecretBundle;
};
}
export interface IReq_GetFlatKeyValueObject extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetFlatKeyValueObject
> {
method: 'getFlatKeyValueObject';
request: {
identity: userInterfaces.IIdentity;
seccretBundleId: string;
secretBundleAuthorization: data.ISecretBundleAuthorization;
};
response: {
flatKeyValueObject: {[key: string]: string};
};
}

View File

@ -0,0 +1,74 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretGroups
> {
method: 'getSecretGroups';
request: {
identity: userInterfaces.IIdentity;
};
response: {
secretGroups: data.ISecretGroup[];
};
}
export interface IReq_GetSecretGroupById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretGroupById
> {
method: 'getSecretGroupById';
request: {
identity: userInterfaces.IIdentity;
secretGroupId: string;
};
response: {
secretGroup: data.ISecretGroup;
};
}
export interface IReq_CreateSecretGroup extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateSecretGroup
> {
method: 'createSecretGroup';
request: {
identity: userInterfaces.IIdentity;
secretGroup: data.ISecretGroup;
};
response: {
resultSecretGroup: data.ISecretGroup;
};
}
export interface IReq_UpdateSecretGroup extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_UpdateSecretGroup
> {
method: 'updateSecretGroup';
request: {
identity: userInterfaces.IIdentity;
secretGroup: data.ISecretGroup;
};
response: {
resultSecretGroup: data.ISecretGroup;
};
}
export interface IReq_DeleteSecretGroupById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_DeleteSecretGroupById
> {
method: 'deleteSecretGroupById';
request: {
identity: userInterfaces.IIdentity;
secretGroupId: string;
};
response: {
ok: boolean;
};
}

View File

@ -0,0 +1,95 @@
import * as plugins from '../plugins.js';
import type { IService } from '../data/service.js';
import type { IIdentity } from '../data/user.js';
import type { IServiceRessources } from '../data/docker.js';
export interface IRequest_Any_Cloudly_GetServiceById
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServiceById
> {
method: 'getServiceById';
request: {
identity: IIdentity;
serviceId: string;
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_GetServices
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServices
> {
method: 'getServices';
request: {
identity: IIdentity;
};
response: {
services: IService[];
};
}
export interface IRequest_Any_Cloudly_CreateService
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_CreateService
> {
method: 'createService';
request: {
identity: IIdentity;
serviceData: IService['data'];
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_UpdateService
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_UpdateService
> {
method: 'updateService';
request: {
identity: IIdentity;
serviceId: string;
serviceData: IService['data'];
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_DeleteServiceById
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_DeleteServiceById
> {
method: 'deleteServiceById';
request: {
identity: IIdentity;
serviceId: string;
};
response: {
success: boolean;
};
}
export interface IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject
> {
method: 'getServiceSecretBundlesAsFlatObject';
request: {
identity: IIdentity;
serviceId: string;
environment: string;
};
response: {
flatKeyValueObject: {[key: string]: string};
};
}

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/cloudly', name: '@serve.zone/cloudly',
version: '4.3.0', version: '5.0.4',
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.' description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
} }

View File

@ -15,7 +15,7 @@ export const loginAction = loginStatePart.createAction<{ username: string; passw
async (statePartArg, payloadArg) => { async (statePartArg, payloadArg) => {
const currentState = statePartArg.getState(); const currentState = statePartArg.getState();
const trLogin = const trLogin =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_LoginWithUsernameAndPassword>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.admin.IReq_Admin_LoginWithUsernameAndPassword>(
'/typedrequest', '/typedrequest',
'adminLoginWithUsernameAndPassword' 'adminLoginWithUsernameAndPassword'
); );
@ -77,20 +77,34 @@ export const dataState = await appstate.getStatePart<IDataState>(
); );
// Getting data // Getting data
export const getAllDataAction = dataState.createAction(async (statePartArg, partialArg?: 'secrets' | 'images') => { export const getAllDataAction = dataState.createAction(async (statePartArg) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
// Secrets // SecretsGroups
const trGetSecrets = const trGetSecretGroups =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_GetSecretGroups>(
'/typedrequest', '/typedrequest',
'adminGetConfigBundlesAndSecretGroups' 'getSecretGroups'
); );
const response = await trGetSecrets.fire({ const response = await trGetSecretGroups.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
}); });
currentState = { currentState = {
...currentState, ...currentState,
...response, secretGroups: response.secretGroups,
};
// SecretBundles
const trGetSecretBundles =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_GetSecretBundles>(
'/typedrequest',
'getSecretBundles'
);
const responseSecretBundles = await trGetSecretBundles.fire({
identity: loginStatePart.getState().identity,
});
currentState = {
...currentState,
secretBundles: responseSecretBundles.secretBundles,
}; };
// images // images
@ -104,14 +118,14 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
}); });
currentState = { currentState = {
...currentState, ...currentState,
...responseImages, images: responseImages.images,
}; };
// Clusters // Clusters
const trGetClusters = const trGetClusters =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.cluster.IRequest_GetAllClusters>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
'/typedrequest', '/typedrequest',
'getAllClusters' 'getClusters'
); );
const responseClusters = await trGetClusters.fire({ const responseClusters = await trGetClusters.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
@ -119,7 +133,7 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
currentState = { currentState = {
...currentState, ...currentState,
...responseClusters, clusters: responseClusters.clusters,
} }
return currentState; return currentState;
@ -130,14 +144,13 @@ export const createSecretGroupAction = dataState.createAction(
async (statePartArg, payloadArg: plugins.interfaces.data.ISecretGroup) => { async (statePartArg, payloadArg: plugins.interfaces.data.ISecretGroup) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
const trCreateSecretGroup = const trCreateSecretGroup =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_CreateSecretGroup>(
'/typedrequest', '/typedrequest',
'adminCreateConfigBundlesAndSecretGroups' 'createSecretGroup'
); );
const response = await trCreateSecretGroup.fire({ const response = await trCreateSecretGroup.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
secretBundles: [], secretGroup: payloadArg,
secretGroups: [payloadArg],
}); });
currentState = await dataState.dispatchAction(getAllDataAction, null); currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState; return currentState;
@ -149,14 +162,13 @@ export const deleteSecretGroupAction = dataState.createAction(
async (statePartArg, payloadArg: { secretGroupId: string }) => { async (statePartArg, payloadArg: { secretGroupId: string }) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
const trDeleteSecretGroup = const trDeleteSecretGroup =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
'/typedrequest', '/typedrequest',
'adminDeleteConfigBundlesAndSecretGroups' 'deleteSecretGroupById'
); );
const response = await trDeleteSecretGroup.fire({ const response = await trDeleteSecretGroup.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
secretBundleIds: [], secretGroupId: payloadArg.secretGroupId,
secretGroupIds: [payloadArg.secretGroupId],
}); });
currentState = await dataState.dispatchAction(getAllDataAction, null); currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState; return currentState;
@ -168,14 +180,13 @@ export const deleteSecretBundleAction = dataState.createAction(
async (statePartArg, payloadArg: { configBundleId: string }) => { async (statePartArg, payloadArg: { configBundleId: string }) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
const trDeleteConfigBundle = const trDeleteConfigBundle =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
'/typedrequest', '/typedrequest',
'adminDeleteConfigBundlesAndSecretGroups' 'deleteSecretBundleById'
); );
const response = await trDeleteConfigBundle.fire({ const response = await trDeleteConfigBundle.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
secretBundleIds: [payloadArg.configBundleId], secretBundleId: payloadArg.configBundleId,
secretGroupIds: [],
}); });
currentState = await dataState.dispatchAction(getAllDataAction, null); currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState; return currentState;
@ -249,7 +260,7 @@ export const addClusterAction = dataState.createAction(
currentState = { currentState = {
...currentState, ...currentState,
...{ ...{
clusters: [...currentState.clusters, response.clusterConfig], clusters: [...currentState.clusters, response.cluster],
}, },
} }
return currentState; return currentState;

View File

@ -24,6 +24,7 @@ import { CloudlyViewS3 } from './cloudly-view-s3.js';
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js'; import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js'; import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
import { CloudlyViewServices } from './cloudly-view-services.js'; import { CloudlyViewServices } from './cloudly-view-services.js';
import { CloudlyViewExternalRegistries } from './cloudly-view-externalregistries.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@ -89,6 +90,10 @@ export class CloudlyDashboard extends DeesElement {
name: 'Clusters', name: 'Clusters',
element: CloudlyViewClusters, element: CloudlyViewClusters,
}, },
{
name: 'ExternalRegistries',
element: CloudlyViewExternalRegistries,
},
{ {
name: 'Images', name: 'Images',
element: CloudlyViewImages, element: CloudlyViewImages,

View File

@ -0,0 +1,129 @@
import * as plugins from '../plugins.js';
import * as shared from '../elements/shared/index.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-externalregistries')
export class CloudlyViewExternalRegistries extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
shared.viewHostCss,
css`
`,
];
public render() {
return html`
<cloudly-sectionheading>External Registries</cloudly-sectionheading>
<dees-table
.heading1=${'External Registries'}
.heading2=${'decoded in client'}
.data=${this.data.deployments}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -18,11 +18,28 @@ export class CloudlySectionheading extends DeesElement {
public static styles = [ public static styles = [
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
:host {
display: grid;
grid-template-columns: min-content min-content;
}
h1 { h1 {
font-family: 'Cal Sans'; font-family: 'Cal Sans';
letter-spacing: 0.025em; letter-spacing: 0.025em;
margin: 0px; margin: 0px;
margin-bottom: 16px; margin-bottom: 16px;
white-space: nowrap;
}
.flag {
border-radius: 4px;
background: #8a0183;
height: 20px;
padding: 2px 4px;
margin-left: 16px;
font-size: 12px;
transform: translateY(12px);
white-space: nowrap;
} }
`, `,
] ]
@ -30,6 +47,7 @@ export class CloudlySectionheading extends DeesElement {
public render() { public render() {
return html` return html`
<h1><slot></slot></h1> <h1><slot></slot></h1>
<div class="flag">stability: alpha</div>
`; `;
} }
} }