import { z } from 'zod'; import { RealityStreamSettingsSchema } from './reality'; import { TlsStreamSettingsSchema } from './tls'; export * from './none'; export * from './reality'; export * from './tls'; export const SecuritySchema = z.enum(['none', 'tls', 'reality']); export type Security = z.infer; // Tagged-wrapper DU on `security`. Wire shape: when security==='tls' only // `tlsSettings` is present, when 'reality' only `realitySettings`, when // 'none' neither key appears. The Xray panel's StreamSettings class emits // `undefined` for the inactive branch which strips the key during JSON // serialization, so this DU faithfully describes what's on disk. // // Tunnel (dokodemo-door / TProxy) is transportless and may carry only // `sockopt` — its streamSettings has no `security` key at all. The // transportless branch accepts that shape, mirroring NetworkSettingsSchema's // `network: never().optional()` handling. A present-but-invalid security // still fails both branches so a typo can't slip through. export const SecuritySettingsSchema = z.union([ z.discriminatedUnion('security', [ z.object({ security: z.literal('none') }), z.object({ security: z.literal('tls'), tlsSettings: TlsStreamSettingsSchema }), z.object({ security: z.literal('reality'), realitySettings: RealityStreamSettingsSchema }), ]), z.object({ security: z.never().optional() }), ]); export type SecuritySettings = z.infer;