3x-ui/frontend/src/schemas/setting.ts
MHSanaei 08fca9ed66
feat(sub): modern xray JSON format with unified finalmask editor
Drop the legacy JSON subscription format entirely and always emit the
modern xray shape:

- Flatten proxy outbounds (no vnext/servers) for vless/vmess/trojan/
  shadowsocks; hysteria was already flat.
- Express fragment/noise via streamSettings.finalmask instead of the
  legacy direct_out freedom dialer + dialerProxy sockopt.

The global finalmask (tcp/udp masks + quicParams) is stored as a single
setting (subJsonFinalMask) and merged into every generated stream,
replacing the separate subJsonFragment/subJsonNoises/subJsonQuicParams
settings.

Reuse the existing FinalMaskForm (used by inbound/outbound) for the
settings UI via a small bridge component; add a showAll prop so all
TCP/UDP/QUIC sections render for the global case. This supersedes the
hand-rolled Fragment/Noises/quicParams tabs with the full mask editor
(all mask types).

Note: this is a breaking change — JSON subscriptions now require a
recent xray client on the consumer side.
2026-06-04 23:16:43 +02:00

94 lines
3.7 KiB
TypeScript

import { z } from 'zod';
const port = z.number().int().min(1).max(65535);
const nonNegativeInt = z.number().int().min(0);
const absolutePath = z.string().regex(/^\//, 'pages.settings.validation.pathLeadingSlash');
export const AllSettingSchema = z.object({
webListen: z.string().optional(),
webDomain: z.string().optional(),
webPort: port.optional(),
webCertFile: z.string().optional(),
webKeyFile: z.string().optional(),
webBasePath: absolutePath.optional(),
sessionMaxAge: z.number().int().min(1).max(525600).optional(),
trustedProxyCIDRs: z.string().optional(),
panelProxy: z.string().optional(),
pageSize: z.number().int().min(0).max(1000).optional(),
expireDiff: nonNegativeInt.optional(),
trafficDiff: nonNegativeInt.max(100).optional(),
remarkModel: z.string().optional(),
datepicker: z.enum(['gregorian', 'jalalian']).optional(),
tgBotEnable: z.boolean().optional(),
tgBotToken: z.string().optional(),
tgBotProxy: z.string().optional(),
tgBotAPIServer: z.string().optional(),
tgBotChatId: z.string().optional(),
tgRunTime: z.string().optional(),
tgBotBackup: z.boolean().optional(),
tgBotLoginNotify: z.boolean().optional(),
tgCpu: z.number().int().min(0).max(100).optional(),
tgLang: z.string().optional(),
twoFactorEnable: z.boolean().optional(),
twoFactorToken: z.string().optional(),
xrayTemplateConfig: z.string().optional(),
subEnable: z.boolean().optional(),
subJsonEnable: z.boolean().optional(),
subTitle: z.string().optional(),
subSupportUrl: z.string().optional(),
subProfileUrl: z.string().optional(),
subAnnounce: z.string().optional(),
subEnableRouting: z.boolean().optional(),
subRoutingRules: z.string().optional(),
subListen: z.string().optional(),
subPort: port.optional(),
subPath: absolutePath.optional(),
subJsonPath: absolutePath.optional(),
subClashEnable: z.boolean().optional(),
subClashPath: absolutePath.optional(),
subDomain: z.string().optional(),
externalTrafficInformEnable: z.boolean().optional(),
externalTrafficInformURI: z.string().optional(),
restartXrayOnClientDisable: z.boolean().optional(),
subCertFile: z.string().optional(),
subKeyFile: z.string().optional(),
subUpdates: z.number().int().min(1).max(168).optional(),
subEncrypt: z.boolean().optional(),
subShowInfo: z.boolean().optional(),
subEmailInRemark: z.boolean().optional(),
subURI: z.string().optional(),
subJsonURI: z.string().optional(),
subClashURI: z.string().optional(),
subJsonMux: z.string().optional(),
subJsonRules: z.string().optional(),
subJsonFinalMask: z.string().optional(),
timeLocation: z.string().optional(),
ldapEnable: z.boolean().optional(),
ldapHost: z.string().optional(),
ldapPort: port.optional(),
ldapUseTLS: z.boolean().optional(),
ldapBindDN: z.string().optional(),
ldapPassword: z.string().optional(),
ldapBaseDN: z.string().optional(),
ldapUserFilter: z.string().optional(),
ldapUserAttr: z.string().optional(),
ldapVlessField: z.string().optional(),
ldapSyncCron: z.string().optional(),
ldapFlagField: z.string().optional(),
ldapTruthyValues: z.string().optional(),
ldapInvertFlag: z.boolean().optional(),
ldapInboundTags: z.string().optional(),
ldapAutoCreate: z.boolean().optional(),
ldapAutoDelete: z.boolean().optional(),
ldapDefaultTotalGB: nonNegativeInt.optional(),
ldapDefaultExpiryDays: nonNegativeInt.optional(),
ldapDefaultLimitIP: nonNegativeInt.optional(),
hasTgBotToken: z.boolean().optional(),
hasTwoFactorToken: z.boolean().optional(),
hasLdapPassword: z.boolean().optional(),
hasApiToken: z.boolean().optional(),
hasWarpSecret: z.boolean().optional(),
hasNordSecret: z.boolean().optional(),
}).loose();
export type AllSettingInput = z.infer<typeof AllSettingSchema>;