mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-13 16:16:06 +00:00
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:
@@ -420,6 +420,54 @@ describe('outbound-form-adapter: round-trip', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('outbound-form-adapter: targetStrategy', () => {
|
||||
it('round-trips a top-level targetStrategy', () => {
|
||||
const back = formValuesToWirePayload(rawOutboundToFormValues({
|
||||
protocol: 'vless',
|
||||
settings: { address: 's', port: 443, id: '11111111-2222-4333-8444-555555555555', flow: '', encryption: 'none' },
|
||||
targetStrategy: 'ForceIPv6v4',
|
||||
}));
|
||||
expect(back.targetStrategy).toBe('ForceIPv6v4');
|
||||
});
|
||||
|
||||
it('normalizes wire case to the canonical spelling (core matches case-insensitively)', () => {
|
||||
const form = rawOutboundToFormValues({
|
||||
protocol: 'freedom',
|
||||
settings: {},
|
||||
targetStrategy: 'useipv4v6',
|
||||
});
|
||||
expect(form.targetStrategy).toBe('UseIPv4v6');
|
||||
});
|
||||
|
||||
it('omits targetStrategy when unset and drops unknown values', () => {
|
||||
const unset = formValuesToWirePayload(rawOutboundToFormValues({
|
||||
protocol: 'freedom',
|
||||
settings: {},
|
||||
}));
|
||||
expect(unset).not.toHaveProperty('targetStrategy');
|
||||
|
||||
const invalid = formValuesToWirePayload(rawOutboundToFormValues({
|
||||
protocol: 'freedom',
|
||||
settings: {},
|
||||
targetStrategy: 'UseIPv5',
|
||||
}));
|
||||
expect(invalid).not.toHaveProperty('targetStrategy');
|
||||
});
|
||||
|
||||
it('freedom prefers settings.targetStrategy over domainStrategy and emits the legacy key', () => {
|
||||
const form = rawOutboundToFormValues({
|
||||
protocol: 'freedom',
|
||||
settings: { targetStrategy: 'UseIPv6', domainStrategy: 'UseIPv4' },
|
||||
});
|
||||
if (form.protocol === 'freedom') {
|
||||
expect(form.settings.domainStrategy).toBe('UseIPv6');
|
||||
}
|
||||
const back = formValuesToWirePayload(form);
|
||||
expect(back.settings).toMatchObject({ domainStrategy: 'UseIPv6' });
|
||||
expect(back.settings).not.toHaveProperty('targetStrategy');
|
||||
});
|
||||
});
|
||||
|
||||
describe('outbound-form-adapter: xhttp xmux toggle', () => {
|
||||
const xmuxWire = {
|
||||
protocol: 'vless',
|
||||
|
||||
Reference in New Issue
Block a user