refactor(frontend): lift Protocols + TLS_FLOW_CONTROL consts to schemas/primitives

Step 4b. The Protocols and TLS_FLOW_CONTROL enums on models/inbound.ts
were dragging five page files into that 3,300-line module just to read
literal string constants. Lifting them to schemas/primitives lets those
pages drop the @/models/inbound import entirely.

  - schemas/primitives/protocol.ts now exports a Protocols const map
    alongside the existing ProtocolSchema. TUN stays in the const for
    parity (legacy panel deployments may have saved TUN inbounds) even
    though the Go validator no longer accepts it as a new write.
  - schemas/primitives/flow.ts now exports TLS_FLOW_CONTROL. The
    empty-string default isn't keyed because the legacy never had a
    NONE entry — call sites compare against the two real flow values.

Updated five consumers:
  - useInbounds.ts: TRACKED_PROTOCOLS now annotated readonly string[]
    so .includes(string) keeps narrowing through the array literal
  - QrCodeModal.tsx, InboundInfoModal.tsx: Protocols
  - ClientFormModal.tsx, ClientBulkAddModal.tsx: TLS_FLOW_CONTROL

Suite: 89 tests across 8 files; typecheck + lint clean.

models/inbound.ts is now imported by:
  - InboundFormModal.tsx (heavy use of Inbound class + getSettings)
  - test/inbound-link.test.ts + test/shadow.test.ts + test/headers.test.ts
    (intentional — these are parity tests against the legacy class)

OutboundFormModal still imports from models/outbound. Both form modals
are the multi-day Pattern A rewrites the plan scopes separately.
This commit is contained in:
MHSanaei 2026-05-26 00:51:52 +02:00
parent bd03f1a117
commit 4ce2503c1e
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
7 changed files with 34 additions and 6 deletions

View file

@ -6,7 +6,7 @@ import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs'; import type { Dayjs } from 'dayjs';
import { HttpUtil, RandomUtil, SizeFormatter } from '@/utils'; import { HttpUtil, RandomUtil, SizeFormatter } from '@/utils';
import { TLS_FLOW_CONTROL } from '@/models/inbound'; import { TLS_FLOW_CONTROL } from '@/schemas/primitives';
import DateTimePicker from '@/components/DateTimePicker'; import DateTimePicker from '@/components/DateTimePicker';
import type { InboundOption } from '@/hooks/useClients'; import type { InboundOption } from '@/hooks/useClients';
import { ClientBulkAddFormSchema, type ClientBulkAddFormValues } from '@/schemas/client'; import { ClientBulkAddFormSchema, type ClientBulkAddFormValues } from '@/schemas/client';

View file

@ -19,7 +19,7 @@ import type { Dayjs } from 'dayjs';
import { HttpUtil, RandomUtil } from '@/utils'; import { HttpUtil, RandomUtil } from '@/utils';
import DateTimePicker from '@/components/DateTimePicker'; import DateTimePicker from '@/components/DateTimePicker';
import { TLS_FLOW_CONTROL } from '@/models/inbound'; import { TLS_FLOW_CONTROL } from '@/schemas/primitives';
import type { ClientRecord, InboundOption } from '@/hooks/useClients'; import type { ClientRecord, InboundOption } from '@/hooks/useClients';
import { ClientFormSchema, ClientCreateFormSchema } from '@/schemas/client'; import { ClientFormSchema, ClientCreateFormSchema } from '@/schemas/client';
import './ClientFormModal.css'; import './ClientFormModal.css';

View file

@ -12,7 +12,7 @@ import {
ClipboardManager, ClipboardManager,
FileManager, FileManager,
} from '@/utils'; } from '@/utils';
import { Protocols } from '@/models/inbound'; import { Protocols } from '@/schemas/primitives';
import InfinityIcon from '@/components/InfinityIcon'; import InfinityIcon from '@/components/InfinityIcon';
import { useDatepicker } from '@/hooks/useDatepicker'; import { useDatepicker } from '@/hooks/useDatepicker';
import type { SubSettings } from './useInbounds'; import type { SubSettings } from './useInbounds';

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Collapse, Modal } from 'antd'; import { Collapse, Modal } from 'antd';
import type { CollapseProps } from 'antd'; import type { CollapseProps } from 'antd';
import { Protocols } from '@/models/inbound'; import { Protocols } from '@/schemas/primitives';
import QrPanel from './QrPanel'; import QrPanel from './QrPanel';
import type { SubSettings } from './useInbounds'; import type { SubSettings } from './useInbounds';

View file

@ -4,7 +4,7 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
import { HttpUtil } from '@/utils'; import { HttpUtil } from '@/utils';
import { parseMsg } from '@/utils/zodValidate'; import { parseMsg } from '@/utils/zodValidate';
import { DBInbound } from '@/models/dbinbound'; import { DBInbound } from '@/models/dbinbound';
import { Protocols } from '@/models/inbound'; import { Protocols } from '@/schemas/primitives';
import { setDatepicker } from '@/hooks/useDatepicker'; import { setDatepicker } from '@/hooks/useDatepicker';
import { keys } from '@/api/queryKeys'; import { keys } from '@/api/queryKeys';
import { SlimInboundListSchema, LastOnlineMapSchema, InboundDetailSchema } from '@/schemas/inbound'; import { SlimInboundListSchema, LastOnlineMapSchema, InboundDetailSchema } from '@/schemas/inbound';
@ -31,7 +31,7 @@ interface ClientRollup {
comments: Map<string, string>; comments: Map<string, string>;
} }
const TRACKED_PROTOCOLS = [ const TRACKED_PROTOCOLS: readonly string[] = [
Protocols.VMESS, Protocols.VMESS,
Protocols.VLESS, Protocols.VLESS,
Protocols.TROJAN, Protocols.TROJAN,

View file

@ -6,3 +6,11 @@ export const FlowSchema = z.enum([
'xtls-rprx-vision-udp443', 'xtls-rprx-vision-udp443',
]); ]);
export type Flow = z.infer<typeof FlowSchema>; export type Flow = z.infer<typeof FlowSchema>;
// Const map matching the legacy models/inbound.ts `TLS_FLOW_CONTROL`
// export. The empty-string default isn't keyed here — the legacy never
// carried a NONE key and call sites compare against the two real flows.
export const TLS_FLOW_CONTROL = Object.freeze({
VISION: 'xtls-rprx-vision',
VISION_UDP443: 'xtls-rprx-vision-udp443',
}) satisfies Record<string, Exclude<Flow, ''>>;

View file

@ -13,3 +13,23 @@ export const ProtocolSchema = z.enum([
'tunnel', 'tunnel',
]); ]);
export type Protocol = z.infer<typeof ProtocolSchema>; export type Protocol = z.infer<typeof ProtocolSchema>;
// Const map matching the legacy models/inbound.ts `Protocols` export so
// call sites can swap the import without touching `Protocols.VLESS`-style
// references throughout the codebase. Frozen so downstream code can't
// mutate the dispatch table. TUN is kept here for parity even though the
// Go backend's validator no longer accepts it — existing panel deployments
// may still have TUN inbounds saved that we want to render.
export const Protocols = Object.freeze({
VMESS: 'vmess',
VLESS: 'vless',
TROJAN: 'trojan',
SHADOWSOCKS: 'shadowsocks',
WIREGUARD: 'wireguard',
HYSTERIA: 'hysteria',
HYSTERIA2: 'hysteria2',
HTTP: 'http',
MIXED: 'mixed',
TUNNEL: 'tunnel',
TUN: 'tun',
});