refactor(frontend): lift OutboundProtocols + OutboundDomainStrategies to schemas/primitives

Moves the two outbound-side consts out of models/outbound.ts and into
schemas/primitives/outbound-protocol.ts. Renames the export to
OutboundProtocols to disambiguate from the inbound Protocols const
(different key casing — PascalCase vs ALL CAPS — and partly different
member set, so they cannot share a single const).

OutboundsTab.tsx keeps its 15+ Protocols.X call sites by aliasing
the import. FinalMaskForm.tsx and BasicsTab.tsx swap directly.
Drops a stale `as string[]` cast in BasicsTab that no longer fits
the new readonly-tuple typing.

After this commit only the two big form modals
(InboundFormModal/OutboundFormModal) plus three intentional parity
tests still import from @/models/.
This commit is contained in:
MHSanaei
2026-05-26 01:07:02 +02:00
parent 4ce2503c1e
commit 40ca58d42e
5 changed files with 36 additions and 5 deletions

View File

@@ -3,7 +3,7 @@ import { Button, Divider, Form, Input, InputNumber, Select, Switch } from 'antd'
import { DeleteOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
import { RandomUtil } from '@/utils';
import { Protocols } from '@/models/outbound';
import { OutboundProtocols } from '@/schemas/primitives';
interface StreamShape {
network?: string;
@@ -84,7 +84,7 @@ function newNoiseItem(): ItemRow {
}
export default function FinalMaskForm({ stream, protocol, onChange }: FinalMaskFormProps) {
const isHysteria = protocol === Protocols.Hysteria || protocol === 'hysteria';
const isHysteria = protocol === OutboundProtocols.Hysteria || protocol === 'hysteria';
const network = stream?.network || '';
const showTcp = useMemo(

View File

@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Alert, Button, Collapse, Input, Modal, Select, Space, Switch } from 'antd';
import { CloudOutlined, ApiOutlined } from '@ant-design/icons';
import { OutboundDomainStrategies } from '@/models/outbound';
import { OutboundDomainStrategies } from '@/schemas/primitives';
import SettingListItem from '@/components/SettingListItem';
import type { XraySettingsValue, SetTemplate } from '@/hooks/useXraySetting';
import './BasicsTab.css';
@@ -217,7 +217,7 @@ export default function BasicsTab({
<Select
value={freedomStrategy}
style={{ width: '100%' }}
options={(OutboundDomainStrategies as string[]).map((s) => ({ value: s, label: s }))}
options={OutboundDomainStrategies.map((s) => ({ value: s, label: s }))}
onChange={(next) => mutate((tt) => {
if (!tt.outbounds) tt.outbounds = [];
const idx = tt.outbounds.findIndex((o) => o?.protocol === 'freedom' && o?.tag === 'direct');

View File

@@ -34,7 +34,7 @@ import {
import type { ColumnsType } from 'antd/es/table';
import { SizeFormatter } from '@/utils';
import { Protocols } from '@/models/outbound';
import { OutboundProtocols as Protocols } from '@/schemas/primitives';
import OutboundFormModal from './OutboundFormModal';
import type { XraySettingsValue, SetTemplate, OutboundTestState, OutboundTrafficRow } from '@/hooks/useXraySetting';
import './OutboundsTab.css';

View File

@@ -1,4 +1,5 @@
export * from './port';
export * from './protocol';
export * from './outbound-protocol';
export * from './sniffing';
export * from './flow';

View File

@@ -0,0 +1,30 @@
export const OutboundProtocols = Object.freeze({
Freedom: 'freedom',
Blackhole: 'blackhole',
DNS: 'dns',
VMess: 'vmess',
VLESS: 'vless',
Trojan: 'trojan',
Shadowsocks: 'shadowsocks',
Wireguard: 'wireguard',
Hysteria: 'hysteria',
Socks: 'socks',
HTTP: 'http',
Loopback: 'loopback',
});
export const OutboundDomainStrategies = Object.freeze([
'AsIs',
'UseIP',
'UseIPv4',
'UseIPv6',
'UseIPv6v4',
'UseIPv4v6',
'ForceIP',
'ForceIPv6v4',
'ForceIPv6',
'ForceIPv4v6',
'ForceIPv4',
] as const);
export type OutboundDomainStrategy = (typeof OutboundDomainStrategies)[number];