blob: c259d8f58afa23e196997295224ed416df028e59 [file] [log] [blame]
gioc31bf142025-06-16 07:48:20 +00001import { z } from "zod";
2import { Node } from "@xyflow/react";
3import { Domain, ServiceType, VolumeType } from "./types.js";
4
5export const serviceAnalyzisSchema = z.object({
6 name: z.string(),
7 location: z.string(),
8 configVars: z.array(
9 z.object({
10 name: z.string(),
11 category: z.enum(["CommandLineFlag", "EnvironmentVariable"]),
12 type: z.optional(z.enum(["String", "Number", "Boolean"])),
13 semanticType: z.optional(
14 z.enum([
15 "EXPANDED_ENV_VAR",
16 "PORT",
17 "FILESYSTEM_PATH",
18 "DATABASE_URL",
19 "SQLITE_PATH",
20 "POSTGRES_URL",
21 "POSTGRES_PASSWORD",
22 "POSTGRES_USER",
23 "POSTGRES_DB",
24 "POSTGRES_PORT",
25 "POSTGRES_HOST",
26 "POSTGRES_SSL",
27 "MONGO_URL",
28 "MONGO_PASSWORD",
29 "MONGO_USER",
30 "MONGO_DB",
31 "MONGO_PORT",
32 "MONGO_HOST",
33 "MONGO_SSL",
34 ]),
35 ),
36 }),
37 ),
38});
39
40export type BoundEnvVar =
41 | {
42 id: string;
43 source: string | null;
44 }
45 | {
46 id: string;
47 source: string | null;
48 name: string;
49 isEditting: boolean;
50 }
51 | {
52 id: string;
53 source: string | null;
54 name: string;
55 alias: string;
56 isEditting: boolean;
57 }
58 | {
59 id: string;
60 source: string | null;
61 portId: string;
62 name: string;
63 alias: string;
64 isEditting: boolean;
65 };
66
67export type EnvVar = {
68 name: string;
69 value: string;
70};
71
72export type InitData = {
73 label: string;
74 envVars: BoundEnvVar[];
75 ports: Port[];
76};
77
78export type NodeData = InitData & {
79 activeField?: string | undefined;
80 state?: string | null;
81};
82
83export type PortConnectedTo = {
84 serviceId: string;
85 portId: string;
86};
87
88export type NetworkData = NodeData & {
89 domain: string;
90};
91
92export type NetworkNode = Node<NetworkData> & {
93 type: "network";
94};
95
96export type GatewayHttpsData = NodeData & {
97 readonly?: boolean;
98 network?: string;
99 subdomain?: string;
100 https?: PortConnectedTo;
101 auth?: {
102 enabled: boolean;
103 groups: string[];
104 noAuthPathPatterns: string[];
105 };
106};
107
108export type GatewayHttpsNode = Node<GatewayHttpsData> & {
109 type: "gateway-https";
110};
111
112export type GatewayTCPData = NodeData & {
113 readonly?: boolean;
114 network?: string;
115 subdomain?: string;
116 exposed: PortConnectedTo[];
117 selected?: {
118 serviceId?: string;
119 portId?: string;
120 };
121};
122
123export type GatewayTCPNode = Node<GatewayTCPData> & {
124 type: "gateway-tcp";
125};
126
127export type Port = {
128 id: string;
129 name: string;
130 value: number;
131};
132
133export type ServiceData = NodeData & {
134 type: ServiceType;
135 repository?:
136 | {
137 id: number;
138 repoNodeId: string;
139 }
140 | {
141 id: number;
142 repoNodeId: string;
143 branch: string;
144 }
145 | {
146 id: number;
147 repoNodeId: string;
148 branch: string;
149 rootDir: string;
150 };
151 env: string[];
152 volume: string[];
153 preBuildCommands: string;
154 isChoosingPortToConnect: boolean;
155 dev?:
156 | {
157 enabled: false;
158 expose?: Domain;
159 }
160 | {
161 enabled: true;
162 expose?: Domain;
163 codeServerNodeId: string;
164 sshNodeId: string;
165 };
gio69148322025-06-19 23:16:12 +0400166 agent?: {
167 geminiApiKey?: string;
168 };
gioc31bf142025-06-16 07:48:20 +0000169 info?: z.infer<typeof serviceAnalyzisSchema>;
170};
171
172export type ServiceNode = Node<ServiceData> & {
173 type: "app";
174};
175
176export type VolumeData = NodeData & {
177 type: VolumeType;
178 size: string;
179 attachedTo: string[];
180};
181
182export type VolumeNode = Node<VolumeData> & {
183 type: "volume";
184};
185
186export type PostgreSQLData = NodeData & {
187 volumeId: string;
188};
189
190export type PostgreSQLNode = Node<PostgreSQLData> & {
191 type: "postgresql";
192};
193
194export type MongoDBData = NodeData & {
195 volumeId: string;
196};
197
198export type MongoDBNode = Node<MongoDBData> & {
199 type: "mongodb";
200};
201
202export type GithubData = NodeData & {
203 repository?: {
204 id: number;
205 sshURL: string;
206 fullName: string;
207 };
208};
209
210export type GithubNode = Node<GithubData> & {
211 type: "github";
212};
213
214export type NANode = Node<NodeData> & {
215 type: undefined;
216};
217
218export type AppNode =
219 | NetworkNode
220 | GatewayHttpsNode
221 | GatewayTCPNode
222 | ServiceNode
223 | VolumeNode
224 | PostgreSQLNode
225 | MongoDBNode
226 | GithubNode
227 | NANode;
228
229export type NodeType = Exclude<Pick<AppNode, "type">["type"], undefined>;
230
231export const networkSchema = z.object({
232 name: z.string().min(1),
233 domain: z.string().min(1),
234 hasAuth: z.boolean(),
235});
236
237export type Network = z.infer<typeof networkSchema>;
238
239export const accessSchema = z.discriminatedUnion("type", [
240 z.object({
241 type: z.literal("https"),
242 name: z.string(),
243 address: z.string(),
244 }),
245 z.object({
246 type: z.literal("ssh"),
247 name: z.string(),
248 host: z.string(),
249 port: z.number(),
250 }),
251 z.object({
252 type: z.literal("tcp"),
253 name: z.string(),
254 host: z.string(),
255 port: z.number(),
256 }),
257 z.object({
258 type: z.literal("udp"),
259 name: z.string(),
260 host: z.string(),
261 port: z.number(),
262 }),
263 z.object({
264 type: z.literal("postgresql"),
265 name: z.string(),
266 host: z.string(),
267 port: z.number(),
268 database: z.string(),
269 username: z.string(),
270 password: z.string(),
271 }),
272 z.object({
273 type: z.literal("mongodb"),
274 name: z.string(),
275 host: z.string(),
276 port: z.number(),
277 database: z.string(),
278 username: z.string(),
279 password: z.string(),
280 }),
281]);
282
283export const serviceInfoSchema = z.object({
284 name: z.string(),
285 workers: z.array(
286 z.object({
287 id: z.string(),
288 commit: z.optional(
289 z.object({
290 hash: z.string(),
291 message: z.string(),
292 }),
293 ),
294 commands: z.optional(
295 z.array(
296 z.object({
297 command: z.string(),
298 state: z.string(),
299 }),
300 ),
301 ),
302 }),
303 ),
304});
305
306export const envSchema = z.object({
gioc31bf142025-06-16 07:48:20 +0000307 instanceId: z.optional(z.string().min(1)),
308 deployKeyPublic: z.optional(z.nullable(z.string().min(1))),
309 networks: z.array(networkSchema).default([]),
310 integrations: z.object({
311 github: z.boolean(),
gio69148322025-06-19 23:16:12 +0400312 gemini: z.boolean(),
gioc31bf142025-06-16 07:48:20 +0000313 }),
314 services: z.array(serviceInfoSchema),
315 user: z.object({
316 id: z.string(),
317 username: z.string(),
318 }),
319 access: z.array(accessSchema),
320});
321
322export type ServiceInfo = z.infer<typeof serviceInfoSchema>;
323export type Env = z.infer<typeof envSchema>;