init: init proj
This commit is contained in:
99
shared/src/schemas.ts
Normal file
99
shared/src/schemas.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { z } from 'zod';
|
||||
import { PROTOCOLS } from './protocols.js';
|
||||
|
||||
export const nodeInputSchema = z
|
||||
.object({
|
||||
name: z.string().min(1).max(64),
|
||||
protocol: z.enum(PROTOCOLS),
|
||||
server: z.string().min(1),
|
||||
port: z.number().int().min(1).max(65535),
|
||||
network: z.enum(['tcp', 'ws']).default('tcp'),
|
||||
wsPath: z.string().startsWith('/').optional().nullable(),
|
||||
wsHost: z.string().optional().nullable(),
|
||||
tls: z.boolean().default(false),
|
||||
sni: z.string().optional().nullable(),
|
||||
skipCertVerify: z.boolean().default(false),
|
||||
uuid: z.string().uuid().optional().nullable(),
|
||||
alterId: z.number().int().min(0).default(0),
|
||||
security: z.string().default('auto'),
|
||||
password: z.string().optional().nullable(),
|
||||
method: z.string().optional().nullable(),
|
||||
obfsType: z.enum(['salamander']).optional().nullable(),
|
||||
obfsPassword: z.string().optional().nullable(),
|
||||
upMbps: z.number().int().positive().optional().nullable(),
|
||||
downMbps: z.number().int().positive().optional().nullable(),
|
||||
region: z.string().max(8).optional().nullable(),
|
||||
tags: z.array(z.string()).default([]),
|
||||
enabled: z.boolean().default(true),
|
||||
sortOrder: z.number().int().default(0),
|
||||
})
|
||||
.superRefine((v, ctx) => {
|
||||
if (v.protocol === 'vmess' && !v.uuid) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['uuid'], message: 'VMess 需要 UUID' });
|
||||
}
|
||||
if ((v.protocol === 'trojan' || v.protocol === 'shadowsocks' || v.protocol === 'hysteria2') && !v.password) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['password'], message: '该协议需要密码' });
|
||||
}
|
||||
if (v.protocol === 'shadowsocks' && !v.method) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['method'], message: 'Shadowsocks 需要加密方式' });
|
||||
}
|
||||
if (v.network === 'ws' && !v.wsPath) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['wsPath'], message: 'WebSocket 传输需要路径' });
|
||||
}
|
||||
});
|
||||
|
||||
export type NodeInput = z.input<typeof nodeInputSchema>;
|
||||
export type NodeParsed = z.output<typeof nodeInputSchema>;
|
||||
|
||||
export const groupInputSchema = z.object({
|
||||
name: z.string().min(1).max(64),
|
||||
type: z.enum(['select', 'url-test', 'fallback']),
|
||||
testUrl: z.string().url().optional().nullable(),
|
||||
interval: z.number().int().positive().optional().nullable(),
|
||||
tolerance: z.number().int().positive().optional().nullable(),
|
||||
filterRegex: z.string().optional().nullable(),
|
||||
includeAllNodes: z.boolean().default(false),
|
||||
sortOrder: z.number().int().default(0),
|
||||
members: z
|
||||
.array(
|
||||
z.object({
|
||||
kind: z.enum(['node', 'group', 'builtin']),
|
||||
nodeId: z.string().optional().nullable(),
|
||||
refName: z.string().optional().nullable(),
|
||||
})
|
||||
)
|
||||
.default([]),
|
||||
});
|
||||
export type GroupInput = z.input<typeof groupInputSchema>;
|
||||
|
||||
export const RULE_TYPES = [
|
||||
'RULE-SET',
|
||||
'DOMAIN-SET',
|
||||
'DOMAIN',
|
||||
'DOMAIN-SUFFIX',
|
||||
'DOMAIN-KEYWORD',
|
||||
'IP-CIDR',
|
||||
'IP-CIDR6',
|
||||
'IP-ASN',
|
||||
'GEOIP',
|
||||
'PROCESS-NAME',
|
||||
'USER-AGENT',
|
||||
'URL-REGEX',
|
||||
'AND',
|
||||
'OR',
|
||||
'NOT',
|
||||
'FINAL',
|
||||
] as const;
|
||||
|
||||
export const ruleInputSchema = z.object({
|
||||
type: z.enum(RULE_TYPES),
|
||||
value: z.string().optional().nullable(),
|
||||
policy: z.string().min(1),
|
||||
params: z.array(z.string()).default([]),
|
||||
enabled: z.boolean().default(true),
|
||||
});
|
||||
export type RuleInput = z.input<typeof ruleInputSchema>;
|
||||
|
||||
export const tokenInputSchema = z.object({
|
||||
name: z.string().min(1).max(64),
|
||||
});
|
||||
Reference in New Issue
Block a user