blob: 604bcc4ceeee7275206cd4bf95e6c7531f7b6cea [file] [log] [blame]
import { z } from "zod";
import { Node } from "@xyflow/react";
import { Domain, ServiceType, VolumeType } from "./types.js";
export const serviceAnalyzisSchema = z.object({
name: z.string(),
location: z.string(),
configVars: z.array(
z.object({
name: z.string(),
category: z.enum(["CommandLineFlag", "EnvironmentVariable"]),
type: z.optional(z.enum(["String", "Number", "Boolean"])),
semanticType: z.optional(
z.enum([
"EXPANDED_ENV_VAR",
"PORT",
"FILESYSTEM_PATH",
"DATABASE_URL",
"SQLITE_PATH",
"POSTGRES_URL",
"POSTGRES_PASSWORD",
"POSTGRES_USER",
"POSTGRES_DB",
"POSTGRES_PORT",
"POSTGRES_HOST",
"POSTGRES_SSL",
"MONGO_URL",
"MONGO_PASSWORD",
"MONGO_USER",
"MONGO_DB",
"MONGO_PORT",
"MONGO_HOST",
"MONGO_SSL",
]),
),
}),
),
});
export type BoundEnvVar =
| {
id: string;
source: string | null;
}
| {
id: string;
source: string | null;
name: string;
isEditting: boolean;
}
| {
id: string;
source: string | null;
name: string;
alias: string;
isEditting: boolean;
}
| {
id: string;
source: string | null;
portId: string;
name: string;
alias: string;
isEditting: boolean;
};
export type EnvVar = {
name: string;
value: string;
};
export type InitData = {
label: string;
envVars: BoundEnvVar[];
ports: Port[];
};
export type NodeData = InitData & {
activeField?: string | undefined;
state?: string | null;
};
export type PortConnectedTo = {
serviceId: string;
portId: string;
};
export type NetworkData = NodeData & {
domain: string;
};
export type NetworkNode = Node<NetworkData> & {
type: "network";
};
export type GatewayHttpsData = NodeData & {
readonly?: boolean;
network?: string;
subdomain?: string;
https?: PortConnectedTo;
auth?: {
enabled: boolean;
groups: string[];
noAuthPathPatterns: string[];
};
};
export type GatewayHttpsNode = Node<GatewayHttpsData> & {
type: "gateway-https";
};
export type GatewayTCPData = NodeData & {
readonly?: boolean;
network?: string;
subdomain?: string;
exposed: PortConnectedTo[];
selected?: {
serviceId?: string;
portId?: string;
};
};
export type GatewayTCPNode = Node<GatewayTCPData> & {
type: "gateway-tcp";
};
export type Port = {
id: string;
name: string;
value: number;
};
export type ServiceData = NodeData & {
type: ServiceType;
repository?:
| {
id: number;
repoNodeId: string;
}
| {
id: number;
repoNodeId: string;
branch: string;
}
| {
id: number;
repoNodeId: string;
branch: string;
rootDir: string;
};
env: string[];
volume: string[];
preBuildCommands: string;
isChoosingPortToConnect: boolean;
dev?:
| {
enabled: false;
expose?: Domain;
}
| {
enabled: true;
expose?: Domain;
codeServerNodeId: string;
sshNodeId: string;
};
agent?: {
geminiApiKey?: string;
};
info?: z.infer<typeof serviceAnalyzisSchema>;
};
export type ServiceNode = Node<ServiceData> & {
type: "app";
};
export type VolumeData = NodeData & {
type: VolumeType;
size: string;
attachedTo: string[];
};
export type VolumeNode = Node<VolumeData> & {
type: "volume";
};
export type PostgreSQLData = NodeData & {
volumeId: string;
};
export type PostgreSQLNode = Node<PostgreSQLData> & {
type: "postgresql";
};
export type MongoDBData = NodeData & {
volumeId: string;
};
export type MongoDBNode = Node<MongoDBData> & {
type: "mongodb";
};
export type GithubData = NodeData & {
repository?: {
id: number;
sshURL: string;
fullName: string;
};
};
export type GithubNode = Node<GithubData> & {
type: "github";
};
export type NANode = Node<NodeData> & {
type: undefined;
};
export type AppNode =
| NetworkNode
| GatewayHttpsNode
| GatewayTCPNode
| ServiceNode
| VolumeNode
| PostgreSQLNode
| MongoDBNode
| GithubNode
| NANode;
export type NodeType = Exclude<Pick<AppNode, "type">["type"], undefined>;
export const networkSchema = z.object({
name: z.string().min(1),
domain: z.string().min(1),
hasAuth: z.boolean(),
});
export type Network = z.infer<typeof networkSchema>;
export const accessSchema = z.discriminatedUnion("type", [
z.object({
type: z.literal("https"),
name: z.string(),
address: z.string(),
agentName: z.string().optional(),
}),
z.object({
type: z.literal("ssh"),
name: z.string(),
host: z.string(),
port: z.number(),
}),
z.object({
type: z.literal("tcp"),
name: z.string(),
host: z.string(),
port: z.number(),
}),
z.object({
type: z.literal("udp"),
name: z.string(),
host: z.string(),
port: z.number(),
}),
z.object({
type: z.literal("postgresql"),
name: z.string(),
host: z.string(),
port: z.number(),
database: z.string(),
username: z.string(),
password: z.string(),
}),
z.object({
type: z.literal("mongodb"),
name: z.string(),
host: z.string(),
port: z.number(),
database: z.string(),
username: z.string(),
password: z.string(),
}),
]);
export const serviceInfoSchema = z.object({
name: z.string(),
workers: z.array(
z.object({
id: z.string(),
commit: z
.object({
hash: z.string(),
message: z.string(),
})
.nullable()
.optional(),
commands: z
.array(
z.object({
command: z.string(),
state: z.string(),
}),
)
.optional(),
}),
),
});
export const envSchema = z.object({
instanceId: z.optional(z.string().min(1)),
deployKeyPublic: z.optional(z.nullable(z.string().min(1))),
networks: z.array(networkSchema).default([]),
integrations: z.object({
github: z.boolean(),
gemini: z.boolean(),
}),
services: z.array(serviceInfoSchema),
user: z.object({
id: z.string(),
username: z.string(),
}),
access: z.array(accessSchema),
});
export type ServiceInfo = z.infer<typeof serviceInfoSchema>;
export type Env = z.infer<typeof envSchema>;
export type Access = z.infer<typeof accessSchema>;