A Docker-like CLI and HTTP API for managing headless VMs
1import z from "@zod/zod";
2
3export type STATUS = "RUNNING" | "STOPPED";
4
5export const MachineParamsSchema = z.object({
6 portForward: z.array(z.string().regex(/^\d+:\d+$/)).optional(),
7 cpu: z.string().optional(),
8 cpus: z.number().min(1).optional(),
9 memory: z
10 .string()
11 .regex(/^\d+(M|G)$/)
12 .optional(),
13});
14
15export type MachineParams = z.infer<typeof MachineParamsSchema>;
16
17export const NewMachineSchema = MachineParamsSchema.extend({
18 portForward: z
19 .array(
20 z
21 .string()
22 .trim()
23 .regex(/^\d+:\d+$/),
24 )
25 .optional(),
26 cpu: z.string().trim().default("host").optional(),
27 cpus: z.number().min(1).default(8).optional(),
28 memory: z
29 .string()
30 .trim()
31 .regex(/^\d+(M|G)$/)
32 .default("2G")
33 .optional(),
34 image: z
35 .string()
36 .trim()
37 .regex(
38 /^([a-zA-Z0-9\-\.]+\/)?([a-zA-Z0-9\-\.]+\/)?[a-zA-Z0-9\-\.]+(:[\w\.\-]+)?$/,
39 ),
40 volume: z.string().trim().optional(),
41 bridge: z.string().trim().optional(),
42 seed: z.string().trim().optional(),
43 users: z
44 .array(
45 z.object({
46 name: z
47 .string()
48 .regex(/^[a-zA-Z0-9_-]+$/)
49 .trim()
50 .min(1),
51 shell: z
52 .string()
53 .regex(
54 /^\/(usr\/bin|bin|usr\/local\/bin|usr\/pkg\/bin)\/[a-zA-Z0-9_-]+$/,
55 )
56 .trim()
57 .default("/bin/bash")
58 .optional(),
59 sudo: z
60 .array(z.string())
61 .optional()
62 .default(["ALL=(ALL) NOPASSWD:ALL"]),
63 sshAuthorizedKeys: z
64 .array(
65 z
66 .string()
67 .regex(
68 /^(ssh-(rsa|ed25519|dss|ecdsa) AAAA[0-9A-Za-z+/]+[=]{0,3}( [^\n\r]*)?|ecdsa-sha2-nistp(256|384|521) AAAA[0-9A-Za-z+/]+[=]{0,3}( [^\n\r]*)?)$/,
69 )
70 .trim(),
71 )
72 .min(1),
73 }),
74 )
75 .optional(),
76 instanceId: z.string().trim().optional(),
77 localHostname: z.string().trim().optional(),
78 hostname: z.string().trim().optional(),
79});
80
81export type NewMachine = z.infer<typeof NewMachineSchema>;
82
83export const NewVolumeSchema = z.object({
84 name: z.string().trim(),
85 baseImage: z
86 .string()
87 .trim()
88 .regex(
89 /^([a-zA-Z0-9\-\.]+\/)?([a-zA-Z0-9\-\.]+\/)?[a-zA-Z0-9\-\.]+(:[\w\.\-]+)?$/,
90 ),
91 size: z
92 .string()
93 .trim()
94 .regex(/^\d+(M|G|T)$/)
95 .optional(),
96});
97
98export type NewVolume = z.infer<typeof NewVolumeSchema>;
99
100export const NewImageSchema = z.object({
101 from: z.string().trim(),
102 image: z
103 .string()
104 .trim()
105 .regex(
106 /^([a-zA-Z0-9\-\.]+\/)?([a-zA-Z0-9\-\.]+\/)?[a-zA-Z0-9\-\.]+(:[\w\.\-]+)?$/,
107 ),
108});
109
110export type NewImage = z.infer<typeof NewImageSchema>;