mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-28 16:09:36 +00:00
fix(frontend): seed full Zod-schema defaults for stream slices + QUIC params (B17)
XHTTP showed blank Selects for Session Placement / Sequence Placement /
Padding Method / Uplink HTTP Method (and several other knobs). Those
fields have a literal "" (empty string) value in the schema, which the
Select renders as "Default (path)" / "Default (repeat-x)" / etc.
The form field was `undefined`, not `""`, so the Select showed blank
instead of the labelled default option.
newStreamSlice in InboundFormModal hand-rolled per-network seed
objects with only a handful of fields. Replaced with
{Tcp,Kcp,Ws,Grpc,HttpUpgrade,XHttp}StreamSettingsSchema.parse({}) so
every default declared in the schema populates the form on network
switch. Same change in buildAddModeValues for the initial TCP state.
QUIC Params (FinalMaskForm) had the same shape on a smaller scale —
defaultQuicParams() only seeded congestion + debug + udpHop. The
schema's other fields are .optional() (no Zod default) so a schema
parse won't help. Hard-coded the xray-core / hysteria recommended
values (maxIdleTimeout 30, keepAlivePeriod 10, brutalUp/Down 0,
maxIncomingStreams 1024, four window sizes) so the InputNumber
controls render with usable starting values instead of blank.
This commit is contained in:
@@ -80,10 +80,26 @@ function defaultNoiseItem(): Record<string, unknown> {
|
||||
}
|
||||
|
||||
function defaultQuicParams(): Record<string, unknown> {
|
||||
// Seeded with the xray-core / hysteria recommended defaults so the QUIC
|
||||
// Params sub-form doesn't show blank InputNumber fields when first
|
||||
// enabled. The schema declares these as .optional() (no Zod default)
|
||||
// because the wire shape omits them when xray's built-in default
|
||||
// applies — but the panel needs values to render the controls.
|
||||
return {
|
||||
congestion: 'bbr',
|
||||
debug: false,
|
||||
brutalUp: 0,
|
||||
brutalDown: 0,
|
||||
hasUdpHop: false,
|
||||
udpHop: { ports: '20000-50000', interval: 5 },
|
||||
maxIdleTimeout: 30,
|
||||
keepAlivePeriod: 10,
|
||||
disablePathMTUDiscovery: false,
|
||||
maxIncomingStreams: 1024,
|
||||
initStreamReceiveWindow: 8388608,
|
||||
maxStreamReceiveWindow: 8388608,
|
||||
initConnectionReceiveWindow: 20971520,
|
||||
maxConnectionReceiveWindow: 20971520,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,12 @@ import { SockoptStreamSettingsSchema } from '@/schemas/protocols/stream/sockopt'
|
||||
import { TlsStreamSettingsSchema } from '@/schemas/protocols/security/tls';
|
||||
import { RealityStreamSettingsSchema } from '@/schemas/protocols/security/reality';
|
||||
import { SniffingSchema } from '@/schemas/primitives/sniffing';
|
||||
import { TcpStreamSettingsSchema } from '@/schemas/protocols/stream/tcp';
|
||||
import { KcpStreamSettingsSchema } from '@/schemas/protocols/stream/kcp';
|
||||
import { WsStreamSettingsSchema } from '@/schemas/protocols/stream/ws';
|
||||
import { GrpcStreamSettingsSchema } from '@/schemas/protocols/stream/grpc';
|
||||
import { HttpUpgradeStreamSettingsSchema } from '@/schemas/protocols/stream/httpupgrade';
|
||||
import { XHttpStreamSettingsSchema } from '@/schemas/protocols/stream/xhttp';
|
||||
import DateTimePicker from '@/components/DateTimePicker';
|
||||
import FinalMaskForm from '@/components/FinalMaskForm';
|
||||
import HeaderMapEditor from '@/components/HeaderMapEditor';
|
||||
@@ -264,7 +270,7 @@ function buildAddModeValues(): InboundFormValues {
|
||||
streamSettings: {
|
||||
network: 'tcp',
|
||||
security: 'none',
|
||||
tcpSettings: { header: { type: 'none' } },
|
||||
tcpSettings: TcpStreamSettingsSchema.parse({ header: { type: 'none' } }),
|
||||
},
|
||||
sniffing: SniffingSchema.parse({}),
|
||||
port: RandomUtil.randomInteger(10000, 60000),
|
||||
@@ -1305,29 +1311,22 @@ export default function InboundFormModal({
|
||||
// network's blob and seed the new one with the schema defaults so the
|
||||
// Form.Items inside it have valid initial values (KCP needs MTU=1350
|
||||
// etc., not empty strings).
|
||||
// Seed each network's settings blob with its Zod schema defaults so
|
||||
// every Form.Item inside the network sub-form has a defined starting
|
||||
// value. XHTTP in particular has ~20 fields (sessionPlacement,
|
||||
// seqPlacement, xPaddingMethod, uplinkHTTPMethod, ...) whose value
|
||||
// is the literal "" sentinel meaning "let xray-core pick its
|
||||
// default". Without seeding "", the Form.Item reads `undefined` and
|
||||
// the Select shows blank instead of the "Default (path)" option.
|
||||
const newStreamSlice = (n: string): Record<string, unknown> => {
|
||||
switch (n) {
|
||||
case 'tcp':
|
||||
return { header: { type: 'none' } };
|
||||
case 'kcp':
|
||||
return {
|
||||
mtu: 1350, tti: 20,
|
||||
uplinkCapacity: 5, downlinkCapacity: 20,
|
||||
cwndMultiplier: 1, maxSendingWindow: 2097152,
|
||||
};
|
||||
case 'ws':
|
||||
return { path: '/', host: '', headers: {}, heartbeatPeriod: 0 };
|
||||
case 'grpc':
|
||||
return { serviceName: '', authority: '', multiMode: false };
|
||||
case 'httpupgrade':
|
||||
return { path: '/', host: '', headers: {} };
|
||||
case 'xhttp':
|
||||
return {
|
||||
path: '/', host: '', mode: 'auto', headers: {},
|
||||
xPaddingBytes: '100-1000', scMaxEachPostBytes: '1000000',
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
case 'tcp': return TcpStreamSettingsSchema.parse({ header: { type: 'none' } });
|
||||
case 'kcp': return KcpStreamSettingsSchema.parse({});
|
||||
case 'ws': return WsStreamSettingsSchema.parse({});
|
||||
case 'grpc': return GrpcStreamSettingsSchema.parse({});
|
||||
case 'httpupgrade': return HttpUpgradeStreamSettingsSchema.parse({});
|
||||
case 'xhttp': return XHttpStreamSettingsSchema.parse({});
|
||||
default: return {};
|
||||
}
|
||||
};
|
||||
const onNetworkChange = (next: string) => {
|
||||
|
||||
Reference in New Issue
Block a user