3x-ui/frontend/src/schemas/protocols/stream/external-proxy.ts
MHSanaei 470efb7a64
fix(schemas): accept empty-string fingerprint on externalProxy
The External Proxy form offers a "Default" option with value '' for the
uTLS fingerprint dropdown, but UtlsFingerprintSchema.optional() rejects
empty strings (only undefined or a valid enum member). Saving an inbound
with externalProxy rows failed with `expected one of "360"|"chrome"|...`.

Preprocess '' to undefined before the optional enum, matching the existing
pattern used for VmessSecuritySchema.
2026-05-27 21:22:09 +02:00

26 lines
1 KiB
TypeScript

import { z } from 'zod';
import { PortSchema } from '@/schemas/primitives';
import { AlpnSchema, UtlsFingerprintSchema } from '@/schemas/protocols/security/tls';
export const ExternalProxyForceTlsSchema = z.enum(['same', 'tls', 'none']);
export type ExternalProxyForceTls = z.infer<typeof ExternalProxyForceTlsSchema>;
// An inbound can advertise external proxy fronts (CDN edges, mirror nodes)
// that share its config but vary the dest+port+SNI for the share link. The
// panel form ships rows of this shape; link generators iterate them when
// stream.externalProxy is non-empty.
export const ExternalProxyEntrySchema = z.object({
forceTls: ExternalProxyForceTlsSchema.default('same'),
dest: z.string().default(''),
port: PortSchema.default(443),
remark: z.string().default(''),
sni: z.string().optional(),
fingerprint: z.preprocess(
(val) => (val === '' ? undefined : val),
UtlsFingerprintSchema.optional(),
),
alpn: z.array(AlpnSchema).optional(),
});
export type ExternalProxyEntry = z.infer<typeof ExternalProxyEntrySchema>;