refactor(frontend): swap InboundsPage clone fallback off Inbound.Settings.getSettings

First Step 4 call-site swap. createDefaultInboundSettings(protocol) lands
in lib/xray/inbound-defaults — a protocol-aware dispatch over the 10
per-protocol settings factories already in this module. Returns a Zod-
parsable plain object instead of a class instance, so callers that just
need the wire-shape JSON can drop the class hierarchy without touching
the broader form modals.

InboundsPage's clone path used Inbound.Settings.getSettings(p).toString()
as the fallback when settings JSON parsing failed. That's now
createDefaultInboundSettings + JSON.stringify, with a final '{}' guard
for unknown protocols (legacy returned null and .toString() crashed —
we just emit empty settings instead). The Inbound import on this file
is now unused and removed.

The 2 remaining getSettings call sites in InboundFormModal aren't safe
to swap in isolation — the form mutates the returned class instance
through methods like .addClient() and .toJson() across ~2000 lines of
JSX. Those land with the full Pattern A rewrite of InboundFormModal,
which the plan budgets at multiple days on its own.

Suite: 89 tests across 8 files; typecheck + lint clean.
This commit is contained in:
MHSanaei 2026-05-26 00:37:18 +02:00
parent 5d07185438
commit bd03f1a117
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
2 changed files with 36 additions and 2 deletions

View file

@ -225,3 +225,36 @@ export function createDefaultWireguardInboundSettings(
noKernelTun: seed.noKernelTun ?? false,
};
}
// Protocol-aware dispatch over every inbound-settings factory. Mirrors
// the legacy `Inbound.Settings.getSettings(protocol)` dispatcher, but
// returns a plain Zod-parsable object instead of a class instance.
// Callers swapping off the class hierarchy use this in place of
// `getSettings(p)` + `.toJson()`.
export type AnyInboundSettings =
| VlessInboundSettings
| VmessInboundSettings
| TrojanInboundSettings
| ShadowsocksInboundSettings
| HysteriaInboundSettings
| Hysteria2InboundSettings
| HttpInboundSettings
| MixedInboundSettings
| TunnelInboundSettings
| WireguardInboundSettings;
export function createDefaultInboundSettings(protocol: string): AnyInboundSettings | null {
switch (protocol) {
case 'vless': return createDefaultVlessInboundSettings();
case 'vmess': return createDefaultVmessInboundSettings();
case 'trojan': return createDefaultTrojanInboundSettings();
case 'shadowsocks': return createDefaultShadowsocksInboundSettings();
case 'hysteria': return createDefaultHysteriaInboundSettings();
case 'hysteria2': return createDefaultHysteria2InboundSettings();
case 'http': return createDefaultHttpInboundSettings();
case 'mixed': return createDefaultMixedInboundSettings();
case 'tunnel': return createDefaultTunnelInboundSettings();
case 'wireguard': return createDefaultWireguardInboundSettings();
default: return null;
}
}

View file

@ -20,7 +20,7 @@ import {
} from '@ant-design/icons';
import { HttpUtil, SizeFormatter, RandomUtil } from '@/utils';
import { Inbound } from '@/models/inbound';
import { createDefaultInboundSettings } from '@/lib/xray/inbound-defaults';
import { coerceInboundJsonField, type DBInbound } from '@/models/dbinbound';
import { useTheme } from '@/hooks/useTheme';
import { useMediaQuery } from '@/hooks/useMediaQuery';
@ -354,7 +354,8 @@ export default function InboundsPage() {
raw.clients = [];
clonedSettings = JSON.stringify(raw);
} catch {
clonedSettings = Inbound.Settings.getSettings(baseInbound.protocol).toString();
const fallback = createDefaultInboundSettings(baseInbound.protocol);
clonedSettings = fallback ? JSON.stringify(fallback, null, 2) : '{}';
}
const data = {
up: 0,