From 9d1a21b48491f9de32bbc95e68c57cd7f6b37cc6 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sun, 5 Jul 2026 21:17:12 +0200 Subject: [PATCH] fix(ui): keep an explicit zero happy-eyeballs delay across the round trip Follow-up found in review: the wire normalizer still stripped tryDelayMs when it equaled 0, but with the schema default now 250 a reload rehydrates the missing field as 250 - a user who explicitly set 0 ("disabled", per the field's own placeholder) would see 250 and any subsequent save would silently enable a delay they turned off. Keep tryDelayMs on the wire unconditionally; it is the one happy-eyeballs field whose presence changes xray's behavior. Refs #5780 --- frontend/src/lib/xray/stream-wire-normalize.ts | 1 - frontend/src/test/stream-wire-normalize.test.ts | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/xray/stream-wire-normalize.ts b/frontend/src/lib/xray/stream-wire-normalize.ts index fddb1c6a4..4dee44196 100644 --- a/frontend/src/lib/xray/stream-wire-normalize.ts +++ b/frontend/src/lib/xray/stream-wire-normalize.ts @@ -267,7 +267,6 @@ export function normalizeSockoptForWire( const he = out.happyEyeballs; if (isRecord(he)) { const heOut: Record = { ...he }; - if (heOut.tryDelayMs === 0) delete heOut.tryDelayMs; if (heOut.prioritizeIPv6 === false) delete heOut.prioritizeIPv6; if (heOut.interleave === 1) delete heOut.interleave; if (heOut.maxConcurrentTry === 4) delete heOut.maxConcurrentTry; diff --git a/frontend/src/test/stream-wire-normalize.test.ts b/frontend/src/test/stream-wire-normalize.test.ts index cac527736..16e9f88bb 100644 --- a/frontend/src/test/stream-wire-normalize.test.ts +++ b/frontend/src/test/stream-wire-normalize.test.ts @@ -213,6 +213,14 @@ describe('normalizeSockoptForWire', () => { expect(out?.happyEyeballs).toEqual({ tryDelayMs: 250 }); }); + + it('keeps an explicit tryDelayMs of 0 so it cannot rehydrate as the 250 default', () => { + const out = normalizeSockoptForWire({ + happyEyeballs: { tryDelayMs: 0, prioritizeIPv6: true, interleave: 1, maxConcurrentTry: 4 }, + }); + + expect(out?.happyEyeballs).toEqual({ tryDelayMs: 0, prioritizeIPv6: true }); + }); }); describe('normalizeStreamSettingsForWire reality', () => {