fix(frontend): QUIC udpHop.interval is a range string, not a number (B19)

User report: "streamSettings.finalmask.quicParams.udpHop.interval:
Invalid input: expected string, received number".

Three-part fix:
- FinalMaskForm: Hop Interval input changed from InputNumber to
  Input with "e.g. 5-10" placeholder. xray-core spec says interval
  is a range string like '5-10' (seconds between min-max hops),
  not a single number.
- FinalMaskForm: defaultQuicParams() seeds interval: '5-10' instead
  of the broken `interval: 5`.
- QuicUdpHopSchema: preprocess coerces number → string for legacy
  DB rows that were written by the now-fixed buggy UI. Stops the
  load-time validation crash on existing inbounds.

Tests still 296/296.
This commit is contained in:
MHSanaei
2026-05-26 20:11:28 +02:00
parent 2b4686de99
commit ce2fd2f0dd
2 changed files with 11 additions and 5 deletions

View File

@@ -91,7 +91,7 @@ function defaultQuicParams(): Record<string, unknown> {
brutalUp: 0,
brutalDown: 0,
hasUdpHop: false,
udpHop: { ports: '20000-50000', interval: 5 },
udpHop: { ports: '20000-50000', interval: '5-10' },
maxIdleTimeout: 30,
keepAlivePeriod: 10,
disablePathMTUDiscovery: false,
@@ -707,7 +707,7 @@ function QuicParamsForm({ base, form }: { base: (string | number)[]; form: FormI
<Input placeholder="e.g. 20000-50000" />
</Form.Item>
<Form.Item label="Hop Interval (s)" name={[...base, 'udpHop', 'interval']}>
<InputNumber min={5} />
<Input placeholder="e.g. 5-10" />
</Form.Item>
</>
)}

View File

@@ -47,10 +47,16 @@ export type QuicCongestion = z.infer<typeof QuicCongestionSchema>;
// udpHop randomizes the QUIC port between a range every `interval` seconds
// to dodge port-based blocking. Both fields are dash-range strings on the
// wire (e.g. '20000-50000', '5-10').
// wire (e.g. '20000-50000', '5-10'). preprocess coerces legacy DB rows
// where interval was stored as a number (UI bug — see B19 in commit history).
const StringRangeSchema = z.preprocess(
(v) => (typeof v === 'number' ? String(v) : v),
z.string(),
);
export const QuicUdpHopSchema = z.object({
ports: z.string().default('20000-50000'),
interval: z.string().default('5-10'),
ports: StringRangeSchema.default('20000-50000'),
interval: StringRangeSchema.default('5-10'),
});
export type QuicUdpHop = z.infer<typeof QuicUdpHopSchema>;