1import { z } from "zod";
2import i18n from "i18next";
3
4const numberInterval = (v: string | null | undefined) => {
5 return v ? /^[\d-]{1,32}$/.test(v) : false;
6};
7
8const packetsInterval = (v: string | null | undefined) => {
9 return v ? /^(:?tlshello|[\d-]{1,32})$/.test(v) : false;
10};
11
12export const alpnOptions = [
13 "none",
14 "h2",
15 "h3",
16 "h3,h2",
17 "http/1.1",
18 "h2,http/1.1",
19 "h3,h2,http/1.1"
20]
21
22export const HostSchema = z.object({
23 remark: z.string().min(1, "Remark is required"),
24 address: z.string().min(1, "Address is required"),
25 port: z.coerce
26 .number()
27 .gte(1, "Port must be more than 1")
28 .lte(65535, "Port can not be more than 65535")
29 .or(z.string())
30 .nullable()
31 .optional(),
32 path: z.string().nullable().optional(),
33 sni: z.string().nullable().optional(),
34 host: z.string().nullable().optional(),
35 mux: z.boolean().nullable().optional(),
36 fragment: z
37 .object({
38 interval: z
39 .string()
40 .refine(
41 (v) => numberInterval(v),
42 i18n.t("page.hosts.fragment.interval-error"),
43 ),
44 length: z
45 .string()
46 .refine(
47 (v) => numberInterval(v),
48 i18n.t("page.hosts.fragment.length-error"),
49 ),
50 packets: z
51 .string()
52 .refine(
53 (v) => packetsInterval(v),
54 i18n.t("page.hosts.fragment.packets-error"),
55 ),
56 })
57 .nullable()
58 .optional(),
59 security: z
60 .enum(["inbound_default", "none", "tls"])
61 .default("inbound_default"),
62 alpn: z
63 .enum(["", ...alpnOptions])
64 .optional()
65 .default("none"),
66 allowinsecure: z.boolean().default(false).optional(),
67 fingerprint: z
68 .enum([
69 "",
70 "none",
71 "chrome",
72 "firefox",
73 "safari",
74 "ios",
75 "android",
76 "edge",
77 "360",
78 "qq",
79 "random",
80 "randomized",
81 ])
82 .optional()
83 .default("none"),
84 is_disabled: z.boolean(),
85});