From c93beef2677dd4ed6dcb6474577a329e529215e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouzbeh=E2=80=A0?= <78313022+rqzbeh@users.noreply.github.com> Date: Wed, 24 Jun 2026 12:54:05 +0200 Subject: [PATCH] fix(inbounds): accept null rewritePort in tunnel settings (#5516) (#5525) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clearing the Rewrite port field makes AntD InputNumber write null into the form store. The tunnel schema declared rewritePort as PortSchema.optional(), which accepts undefined but not null, so saving (or the JSON tab reflecting null) failed validation with "settings.rewritePort — Invalid input". Accept null and collapse it to undefined so the field is simply omitted from the serialized payload, matching the behavior of deleting the key by hand. The trailing .optional() keeps the key optional in the inferred type. Closes #5516 --- .../src/schemas/protocols/inbound/tunnel.ts | 7 ++++- frontend/src/test/tunnel-rewriteport.test.ts | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 frontend/src/test/tunnel-rewriteport.test.ts diff --git a/frontend/src/schemas/protocols/inbound/tunnel.ts b/frontend/src/schemas/protocols/inbound/tunnel.ts index 5ce839ad5..d1a72de85 100644 --- a/frontend/src/schemas/protocols/inbound/tunnel.ts +++ b/frontend/src/schemas/protocols/inbound/tunnel.ts @@ -11,7 +11,12 @@ export type TunnelNetwork = z.infer; // with arr=false. export const TunnelInboundSettingsSchema = z.object({ rewriteAddress: z.string().optional(), - rewritePort: PortSchema.optional(), + // AntD InputNumber writes null when cleared; accept it and collapse to + // undefined so the field is omitted from the payload instead of crashing + // validation with "Invalid input" (issue #5516). The trailing .optional() + // keeps the key optional in the inferred type (a bare .transform() would + // make it required). + rewritePort: PortSchema.nullable().transform((v) => v ?? undefined).optional(), portMap: z.record(z.string(), z.string()).default({}), allowedNetwork: TunnelNetworkSchema.default('tcp,udp'), followRedirect: z.boolean().default(false), diff --git a/frontend/src/test/tunnel-rewriteport.test.ts b/frontend/src/test/tunnel-rewriteport.test.ts new file mode 100644 index 000000000..8e4afd9d5 --- /dev/null +++ b/frontend/src/test/tunnel-rewriteport.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from 'vitest'; + +import { TunnelInboundSettingsSchema } from '@/schemas/protocols/inbound/tunnel'; + +// Regression for issue #5516: AntD InputNumber writes null when the Rewrite +// port field is cleared, which used to crash validation with "Invalid input". +describe('TunnelInboundSettingsSchema rewritePort', () => { + it('accepts null (cleared field) and omits the port', () => { + const parsed = TunnelInboundSettingsSchema.parse({ rewritePort: null }); + expect(parsed.rewritePort).toBeUndefined(); + }); + + it('accepts a missing field', () => { + const parsed = TunnelInboundSettingsSchema.parse({}); + expect(parsed.rewritePort).toBeUndefined(); + }); + + it('preserves a valid port', () => { + const parsed = TunnelInboundSettingsSchema.parse({ rewritePort: 8443 }); + expect(parsed.rewritePort).toBe(8443); + }); + + it('still rejects out-of-range ports', () => { + expect(() => TunnelInboundSettingsSchema.parse({ rewritePort: 70000 })).toThrow(); + }); +});