feat(frontend): add targetStrategy field to the outbound editor

Xray-core added a top-level targetStrategy to OutboundObject that
controls how the destination domain is resolved before dialing
(AsIs/UseIP*/ForceIP*, any protocol). The panel neither offered a
control for it nor preserved the key across the modal's JSON round
trip, so hand-written values were silently dropped on save.

The form now carries targetStrategy next to sendThrough as a select
of the 11 canonical values; the adapter normalizes wire values to
canonical case (the core matches case-insensitively) and omits the
key when unset. Freedom settings additionally read the new
settings-level targetStrategy with domainStrategy as fallback,
mirroring the core, while still emitting the legacy domainStrategy
key so configs keep working on older cores.
This commit is contained in:
MHSanaei
2026-07-02 23:03:43 +02:00
parent 9f760cf0fa
commit 258d8b7344
18 changed files with 113 additions and 10 deletions
@@ -39,6 +39,7 @@ import {
NETWORK_OPTIONS,
PROTOCOL_OPTIONS,
SERVER_PROTOCOLS,
TARGET_STRATEGY_OPTIONS,
} from './outbound-form-constants';
import {
applyNetworkChange,
@@ -394,6 +395,14 @@ export default function OutboundFormModal({
<Input placeholder={t('pages.xray.outboundForm.localIpPlaceholder')} />
</Form.Item>
<Form.Item
label={t('pages.xray.outbound.targetStrategy')}
name="targetStrategy"
tooltip={t('pages.xray.outboundForm.targetStrategyHint')}
>
<Select allowClear placeholder="AsIs" options={TARGET_STRATEGY_OPTIONS} />
</Form.Item>
{SERVER_PROTOCOLS.has(protocol) && <ServerTarget />}
{protocol === 'vmess' && <VmessFields />}
{protocol === 'vless' && <VlessFields />}
@@ -7,6 +7,7 @@ import {
USERS_SECURITY,
UTLS_FINGERPRINT,
} from '@/schemas/primitives';
import { OutboundDomainStrategySchema } from '@/schemas/protocols/outbound';
import { SSMethodSchema } from '@/schemas/protocols/shared/shadowsocks';
export const PROTOCOL_OPTIONS = Object.values(Protocols).map((p) => ({ value: p, label: p }));
@@ -20,6 +21,10 @@ export const ADDRESS_PORT_STRATEGY_OPTIONS = Object.values(Address_Port_Strategy
value: v,
label: v,
}));
export const TARGET_STRATEGY_OPTIONS = OutboundDomainStrategySchema.options.map((v) => ({
value: v,
label: v,
}));
// canEnableMux mirrors the adapter's helper but lives here so the modal
// can show/hide the Mux section without going through the adapter.