mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-02 10:29:34 +00:00
Mainline migration goal — replace class-based xray models with Zod schemas as the single source of truth + drive all forms through AntD `Form.useForm` + `antdRule(schema.shape.X)` — is complete. Remaining items are incremental polish.
5.6 KiB
5.6 KiB
3x-ui Frontend Zod Migration — Status
Branch: feat/frontend-zod-validation · 83 commits ahead of main
Last updated: 2026-05-26
What this is
The work tracked here is the migration described in
C:\Users\Hossein Sanaei\.claude\plans\zod-soft-feather.md — replacing the
class-based xray models (models/inbound.ts, models/outbound.ts) with Zod
schemas as the single source of truth, standardizing every form on AntD
Form.useForm + antdRule(schema.shape.X), and tightening
@typescript-eslint/no-explicit-any to error.
Verify state: npm run typecheck clean, npm run lint clean,
npm run test 302/302, snapshot baselines 172/172.
Done
Foundations
- API-boundary Zod validation in TanStack Query hooks (
parseMsghelper) - Backend request-body validation via
go-playground/validator - Go-first codegen tool (
tools/openapigen) emittingzod.ts+types.ts antdRule(schema)helper bridging Zod issues to AntD form rules- Five secondary modals migrated to Pattern A (Login, 2FA, Geo, Balancer, Rule)
- Pre-save schema guard on Inbound/Outbound form submits
Schemas — frontend/src/schemas/
primitives/— port, protocol, sniffing, atomic dictionariesprotocols/inbound/*— 10 protocols as leaf schemasprotocols/outbound/*— 11 protocols as leaf schemasprotocols/stream/*— 7 networks (tcp/kcp/ws/grpc/httpupgrade/xhttp/hysteria)protocols/security/*— 3 securities (none/tls/reality)forms/inbound-form.ts—InboundFormValuesdiscriminated unionforms/outbound-form.ts—OutboundFormValuesdiscriminated union- Stream + security families wired as
z.discriminatedUnionwith intersection
Pure-function ports — frontend/src/lib/xray/
headers.ts—toHeaders,toV2Headers,getHeaderValueinbound-link.ts—genVmessLink,genVlessLink,genTrojanLink,genShadowsocksLink,genHysteriaLink, Wireguard link/configoutbound-link-parser.ts— vmess/vless/trojan/shadowsocks/hysteria2inbound-defaults.ts—createDefault{Vmess,Vless,...}{Client,InboundSettings}outbound-defaults.ts— settings factories + dispatcheroutbound-form-adapter.ts— raw ↔OutboundFormValuesround-tripprotocol-capabilities.ts— capability predicates as pure functions
Form modals on Pattern A
InboundFormModal.tsx— full rewrite, atomic-swapped from.new.tsx- Tabs: Basic, Sniffing, Protocol, Stream, Security, Advanced JSON, Fallbacks
- All 10 protocols (VLESS, VMess, Trojan, Shadowsocks, HTTP, Mixed, Tunnel, TUN, Wireguard, Hysteria)
- Full Stream tab (TCP, KCP, WS, gRPC, HTTPUpgrade, XHTTP, Hysteria)
- Full Security tab (TLS list, Reality, ECH, mldsa65)
- 18-field sockopt section, full TLS cert list, external-proxy section
OutboundFormModal.tsx— full rewrite, atomic-swapped from.new.tsx- All 12 protocols (vmess/vless/trojan/shadowsocks/socks/http/hysteria/ freedom/blackhole/dns/loopback/wireguard)
- Full Stream tab with XHTTP advanced fields + xmux sub-form
- Full Security tab (TLS + Reality + Vision flow)
- Sockopt section (17 knobs)
- Mux section
- JSON tab for advanced fields
- Link import (vmess/vless/trojan/ss/hysteria2) with full XHTTP round-trip (padding obfs + session/seq/uplink keys + all post-size knobs)
FinalMaskFormrewritten to Pattern A (Form.List-driven) and wired into both stream tabs (Inbound + Outbound). Covers TCP/UDP mask arrays, all 13 UDP mask types, header-custom nested groups, noise items, and the QUIC params sub-form.
Tests
- Golden-file fixture suite (
test/golden/fixtures/) - Snapshot-baseline regression tests for inbound-full / outbound / stream / security DUs
- Shadow-parse harness asserting legacy class and Zod converge
- Link-parser tests (15 round-trip cases including XHTTP padding-obfs)
- Outbound form-adapter tests (15 round-trip cases)
- 302 tests across 12 files, 172 snapshots
Build infrastructure
@typescript-eslint/no-explicit-any: 'error'enforced.github/workflows/ci.ymlrunstypecheck+testbeforebuild- Vite pinned to 8.0.13 (dev-mode dep-optimizer regression in 8.0.14)
Remaining
Out of migration scope (per plan)
DBInbound,Status,AllSettinglegacy classes — flagged as out of scope inzod-soft-feather.md. The mainline migration ofmodels/inbound.ts/models/outbound.tscannot delete them entirely whileDBInbound.toInbound()still imports.- The plan accepts this and treats parity via snapshot baselines instead.
Nice-to-haves — would not block ship
- Reality
sid=multi-value parsing in share-link import (outbound reality only carries a single shortId — this is server-side state) fm=(FinalMask) param in share-link import- VMess link
xmuxnested JSON parsing (currently round-trips at the XHTTP top level; nested xmux object is left empty) - Tighter
.loose()removal inschemas/api/inbound.ts,schemas/api/client.ts,schemas/xray.ts— gated on Step 6 of the plan (currently held because the codegen tool still emits one or two loose fields the panel writes back)
How to pick up where this left off
git checkout feat/frontend-zod-validationcd frontend && npm install && npm run typecheck && npm run test- Open
C:\Users\Hossein Sanaei\.claude\plans\zod-soft-feather.md— Steps 1–5 are done. Step 6 (tighten.loose()) and Step 7 (lint/CI tightening) are partially done. - Nothing in this list blocks ship. The mainline migration goal (replace class-based models with Zod schemas + Pattern A forms) is done; remaining work is incremental polish.