| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 1 | import axios from "axios"; |
| 2 | import { z } from "zod"; |
| 3 | |
| gio | cc5ce58 | 2025-06-25 07:45:21 +0400 | [diff] [blame] | 4 | export const accessSchema = z.discriminatedUnion("type", [ |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 5 | z.object({ |
| 6 | type: z.literal("https"), |
| 7 | name: z.string(), |
| 8 | address: z.string(), |
| gio | cc5ce58 | 2025-06-25 07:45:21 +0400 | [diff] [blame] | 9 | agentName: z.string().optional(), |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 10 | }), |
| 11 | z.object({ |
| 12 | type: z.literal("ssh"), |
| 13 | name: z.string(), |
| 14 | host: z.string(), |
| 15 | port: z.number(), |
| 16 | }), |
| 17 | z.object({ |
| 18 | type: z.literal("tcp"), |
| 19 | name: z.string(), |
| 20 | host: z.string(), |
| 21 | port: z.number(), |
| 22 | }), |
| 23 | z.object({ |
| 24 | type: z.literal("udp"), |
| 25 | name: z.string(), |
| 26 | host: z.string(), |
| 27 | port: z.number(), |
| 28 | }), |
| 29 | z.object({ |
| 30 | type: z.literal("postgresql"), |
| 31 | name: z.string(), |
| 32 | host: z.string(), |
| 33 | port: z.number(), |
| 34 | database: z.string(), |
| 35 | username: z.string(), |
| 36 | password: z.string(), |
| 37 | }), |
| 38 | z.object({ |
| 39 | type: z.literal("mongodb"), |
| 40 | name: z.string(), |
| 41 | host: z.string(), |
| 42 | port: z.number(), |
| 43 | database: z.string(), |
| 44 | username: z.string(), |
| 45 | password: z.string(), |
| 46 | }), |
| 47 | ]); |
| 48 | |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 49 | export const DeployResponseSchema = z.object({ |
| 50 | id: z.string(), |
| 51 | deployKey: z.string(), |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 52 | access: z.array(accessSchema), |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 53 | }); |
| 54 | |
| 55 | export type DeployResponse = z.infer<typeof DeployResponseSchema>; |
| 56 | |
| 57 | export class AppManager { |
| 58 | private baseUrl: string; |
| 59 | |
| 60 | constructor(baseUrl: string = "http://appmanager.hgrz-appmanager.svc.cluster.local") { |
| 61 | this.baseUrl = baseUrl; |
| 62 | } |
| 63 | |
| 64 | async deploy(config: unknown): Promise<DeployResponse> { |
| 65 | const response = await axios.request({ |
| 66 | url: `${this.baseUrl}/api/dodo-app`, |
| 67 | method: "post", |
| 68 | data: { config }, |
| 69 | }); |
| 70 | if (response.status !== 200) { |
| 71 | throw new Error(`Failed to deploy application: ${response.statusText}`); |
| 72 | } |
| 73 | const result = DeployResponseSchema.safeParse(response.data); |
| 74 | if (!result.success) { |
| 75 | throw new Error(`Invalid deploy response format: ${result.error.message}`); |
| 76 | } |
| 77 | return result.data; |
| 78 | } |
| 79 | |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 80 | async update(instanceId: string, config: unknown): Promise<DeployResponse> { |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 81 | const response = await axios.request({ |
| 82 | url: `${this.baseUrl}/api/dodo-app/${instanceId}`, |
| 83 | method: "put", |
| 84 | data: { config }, |
| 85 | }); |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 86 | if (response.status !== 200) { |
| 87 | throw new Error(`Failed to update application: ${response.statusText}`); |
| 88 | } |
| 89 | const result = DeployResponseSchema.safeParse(response.data); |
| 90 | if (!result.success) { |
| 91 | throw new Error(`Invalid update response format: ${result.error.message}`); |
| 92 | } |
| 93 | return result.data; |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | async getStatus(instanceId: string): Promise<unknown> { |
| 97 | const response = await axios.request({ |
| 98 | url: `${this.baseUrl}/api/instance/${instanceId}/status`, |
| 99 | method: "get", |
| 100 | }); |
| 101 | if (response.status !== 200) { |
| 102 | throw new Error(`Failed to get application status: ${response.statusText}`); |
| 103 | } |
| 104 | return response.data; |
| 105 | } |
| 106 | |
| 107 | async removeInstance(instanceId: string): Promise<boolean> { |
| 108 | const response = await axios.request({ |
| 109 | url: `${this.baseUrl}/api/instance/${instanceId}/remove`, |
| 110 | method: "post", |
| 111 | }); |
| 112 | return response.status === 200; |
| 113 | } |
| 114 | } |