| 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 | }), |
| gio | 8323a05 | 2025-08-04 06:12:26 +0000 | [diff] [blame] | 47 | z.object({ |
| 48 | type: z.literal("env_var"), |
| 49 | name: z.string(), |
| 50 | var: z.string(), |
| 51 | }), |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 52 | ]); |
| 53 | |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 54 | export const DeployResponseSchema = z.object({ |
| 55 | id: z.string(), |
| 56 | deployKey: z.string(), |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 57 | access: z.array(accessSchema), |
| gio | e085d5b | 2025-07-08 07:51:36 +0000 | [diff] [blame] | 58 | envVars: z.array(z.object({ name: z.string(), value: z.string() })), |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 59 | }); |
| 60 | |
| 61 | export type DeployResponse = z.infer<typeof DeployResponseSchema>; |
| 62 | |
| 63 | export class AppManager { |
| 64 | private baseUrl: string; |
| 65 | |
| 66 | constructor(baseUrl: string = "http://appmanager.hgrz-appmanager.svc.cluster.local") { |
| 67 | this.baseUrl = baseUrl; |
| 68 | } |
| 69 | |
| 70 | async deploy(config: unknown): Promise<DeployResponse> { |
| 71 | const response = await axios.request({ |
| 72 | url: `${this.baseUrl}/api/dodo-app`, |
| 73 | method: "post", |
| 74 | data: { config }, |
| 75 | }); |
| 76 | if (response.status !== 200) { |
| 77 | throw new Error(`Failed to deploy application: ${response.statusText}`); |
| 78 | } |
| 79 | const result = DeployResponseSchema.safeParse(response.data); |
| 80 | if (!result.success) { |
| 81 | throw new Error(`Invalid deploy response format: ${result.error.message}`); |
| 82 | } |
| 83 | return result.data; |
| 84 | } |
| 85 | |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 86 | async update(instanceId: string, config: unknown): Promise<DeployResponse> { |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 87 | const response = await axios.request({ |
| 88 | url: `${this.baseUrl}/api/dodo-app/${instanceId}`, |
| 89 | method: "put", |
| 90 | data: { config }, |
| 91 | }); |
| gio | b77cb93 | 2025-05-19 09:37:14 +0000 | [diff] [blame] | 92 | if (response.status !== 200) { |
| 93 | throw new Error(`Failed to update application: ${response.statusText}`); |
| 94 | } |
| 95 | const result = DeployResponseSchema.safeParse(response.data); |
| 96 | if (!result.success) { |
| 97 | throw new Error(`Invalid update response format: ${result.error.message}`); |
| 98 | } |
| 99 | return result.data; |
| gio | 3ed5959 | 2025-05-14 16:51:09 +0000 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | async getStatus(instanceId: string): Promise<unknown> { |
| 103 | const response = await axios.request({ |
| 104 | url: `${this.baseUrl}/api/instance/${instanceId}/status`, |
| 105 | method: "get", |
| 106 | }); |
| 107 | if (response.status !== 200) { |
| 108 | throw new Error(`Failed to get application status: ${response.statusText}`); |
| 109 | } |
| 110 | return response.data; |
| 111 | } |
| 112 | |
| 113 | async removeInstance(instanceId: string): Promise<boolean> { |
| 114 | const response = await axios.request({ |
| 115 | url: `${this.baseUrl}/api/instance/${instanceId}/remove`, |
| 116 | method: "post", |
| 117 | }); |
| 118 | return response.status === 200; |
| 119 | } |
| 120 | } |