diff --git a/frontend/src/lib/xray/inbound-from-db.ts b/frontend/src/lib/xray/inbound-from-db.ts index 3e01d22b..c29abc38 100644 --- a/frontend/src/lib/xray/inbound-from-db.ts +++ b/frontend/src/lib/xray/inbound-from-db.ts @@ -1,20 +1,9 @@ import type { Inbound } from '@/schemas/api/inbound'; import { InboundSettingsSchema } from '@/schemas/protocols/inbound'; -import { - GrpcStreamSettingsSchema, - HttpUpgradeStreamSettingsSchema, - HysteriaStreamSettingsSchema, - KcpStreamSettingsSchema, - TcpStreamSettingsSchema, - WsStreamSettingsSchema, - XHttpStreamSettingsSchema, -} from '@/schemas/protocols/stream'; -import { - RealityStreamSettingsSchema, - TlsStreamSettingsSchema, -} from '@/schemas/protocols/security'; import { coerceInboundJsonField } from '@/models/dbinbound'; +import { fillStreamDefaults } from './stream-defaults'; + export interface DbInboundLike { port: number; listen: string; @@ -31,62 +20,6 @@ export interface DbInboundLike { total?: number; } -const NETWORK_KEY_MAP = { - tcp: 'tcpSettings', - kcp: 'kcpSettings', - ws: 'wsSettings', - grpc: 'grpcSettings', - httpupgrade: 'httpupgradeSettings', - xhttp: 'xhttpSettings', - hysteria: 'hysteriaSettings', -} as const; - -type SchemaWithParse = { safeParse: (v: unknown) => { success: boolean; data?: unknown } }; - -function parseOrDefault(schema: SchemaWithParse, value: unknown): unknown { - const parsed = schema.safeParse(value ?? {}); - if (parsed.success) return parsed.data; - const fallback = schema.safeParse({}); - return fallback.success ? fallback.data : value; -} - -function networkSchemaFor(network: string): SchemaWithParse | null { - switch (network) { - case 'tcp': return TcpStreamSettingsSchema; - case 'kcp': return KcpStreamSettingsSchema; - case 'ws': return WsStreamSettingsSchema; - case 'grpc': return GrpcStreamSettingsSchema; - case 'httpupgrade': return HttpUpgradeStreamSettingsSchema; - case 'xhttp': return XHttpStreamSettingsSchema; - case 'hysteria': return HysteriaStreamSettingsSchema; - default: return null; - } -} - -function securitySchemaFor(security: string): { key: string; schema: SchemaWithParse } | null { - switch (security) { - case 'tls': return { key: 'tlsSettings', schema: TlsStreamSettingsSchema }; - case 'reality': return { key: 'realitySettings', schema: RealityStreamSettingsSchema }; - default: return null; - } -} - -function fillStreamDefaults(stream: Record): Record { - const network = (stream.network as string | undefined) ?? 'tcp'; - const security = (stream.security as string | undefined) ?? 'none'; - const out: Record = { ...stream, network, security }; - const subKey = NETWORK_KEY_MAP[network as keyof typeof NETWORK_KEY_MAP]; - const netSchema = networkSchemaFor(network); - if (subKey && netSchema) { - out[subKey] = parseOrDefault(netSchema, out[subKey]); - } - const sec = securitySchemaFor(security); - if (sec) { - out[sec.key] = parseOrDefault(sec.schema, out[sec.key]); - } - return out; -} - function fillProtocolSettingsDefaults(protocol: string, settings: Record): Record { const parsed = InboundSettingsSchema.safeParse({ protocol, settings }); if (parsed.success) { diff --git a/frontend/src/lib/xray/stream-defaults.ts b/frontend/src/lib/xray/stream-defaults.ts new file mode 100644 index 00000000..f962796e --- /dev/null +++ b/frontend/src/lib/xray/stream-defaults.ts @@ -0,0 +1,69 @@ +import { + GrpcStreamSettingsSchema, + HttpUpgradeStreamSettingsSchema, + HysteriaStreamSettingsSchema, + KcpStreamSettingsSchema, + TcpStreamSettingsSchema, + WsStreamSettingsSchema, + XHttpStreamSettingsSchema, +} from '@/schemas/protocols/stream'; +import { + RealityStreamSettingsSchema, + TlsStreamSettingsSchema, +} from '@/schemas/protocols/security'; + +const NETWORK_KEY_MAP = { + tcp: 'tcpSettings', + kcp: 'kcpSettings', + ws: 'wsSettings', + grpc: 'grpcSettings', + httpupgrade: 'httpupgradeSettings', + xhttp: 'xhttpSettings', + hysteria: 'hysteriaSettings', +} as const; + +type SchemaWithParse = { safeParse: (v: unknown) => { success: boolean; data?: unknown } }; + +function parseOrDefault(schema: SchemaWithParse, value: unknown): unknown { + const parsed = schema.safeParse(value ?? {}); + if (parsed.success) return parsed.data; + const fallback = schema.safeParse({}); + return fallback.success ? fallback.data : value; +} + +function networkSchemaFor(network: string): SchemaWithParse | null { + switch (network) { + case 'tcp': return TcpStreamSettingsSchema; + case 'kcp': return KcpStreamSettingsSchema; + case 'ws': return WsStreamSettingsSchema; + case 'grpc': return GrpcStreamSettingsSchema; + case 'httpupgrade': return HttpUpgradeStreamSettingsSchema; + case 'xhttp': return XHttpStreamSettingsSchema; + case 'hysteria': return HysteriaStreamSettingsSchema; + default: return null; + } +} + +function securitySchemaFor(security: string): { key: string; schema: SchemaWithParse } | null { + switch (security) { + case 'tls': return { key: 'tlsSettings', schema: TlsStreamSettingsSchema }; + case 'reality': return { key: 'realitySettings', schema: RealityStreamSettingsSchema }; + default: return null; + } +} + +export function fillStreamDefaults(stream: Record): Record { + const network = (stream.network as string | undefined) ?? 'tcp'; + const security = (stream.security as string | undefined) ?? 'none'; + const out: Record = { ...stream, network, security }; + const subKey = NETWORK_KEY_MAP[network as keyof typeof NETWORK_KEY_MAP]; + const netSchema = networkSchemaFor(network); + if (subKey && netSchema) { + out[subKey] = parseOrDefault(netSchema, out[subKey]); + } + const sec = securitySchemaFor(security); + if (sec) { + out[sec.key] = parseOrDefault(sec.schema, out[sec.key]); + } + return out; +}