mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-15 00:56:08 +00:00
feat(clients,inbound): Auto Renew in Bulk Add + cleaner inbound wire payload
Bulk Add now exposes the same Auto Renew (`reset`, days) input as the single-client form, applied to every client the batch produces. The field was already on ClientBulkAddFormSchema's siblings; just wire it into the schema, the empty-form defaults, the UI, and the bulkCreate payload. Also relabel "Subscription info" to "Subscription ID" by switching to the canonical pages.clients.subId key and modernise the SyncOutlined-in-label random affordance on the same row. On the inbound submit path, two payload-shape cleanups in dropLegacyOptionalEmpties: - streamSettings.hysteriaSettings.auth is a holdover slot whose real per-client value lives in settings.clients[*].auth; drop the field entirely when empty instead of shipping `"auth": ""`. - finalmask's `tcp` / `udp` arrays were already dropped together when both were empty, but a UDP-only setup still emitted a stray `"tcp": []`. Drop each sub-array on its own when empty so a Hysteria-style "salamander on udp only" config no longer carries the empty tcp sibling.
This commit is contained in:
@@ -227,15 +227,32 @@ export function dropLegacyOptionalEmpties(
|
||||
const fb = settings.fallbacks;
|
||||
if (Array.isArray(fb) && fb.length === 0) delete settings.fallbacks;
|
||||
|
||||
// StreamSettings emits `finalmask` only when at least one transport
|
||||
// mask exists (legacy `hasFinalMask`). Otherwise drop the whole block.
|
||||
if (stream) {
|
||||
// StreamSettings emits `finalmask` only when at least one transport
|
||||
// mask exists (legacy `hasFinalMask`). Drop the whole block when all
|
||||
// sub-fields are empty; otherwise drop only the empty sub-arrays so
|
||||
// the wire payload doesn't carry a stray `"tcp": []` next to a
|
||||
// populated UDP mask list (and vice versa).
|
||||
const fm = stream.finalmask as { tcp?: unknown[]; udp?: unknown[]; quicParams?: unknown } | undefined;
|
||||
if (fm && typeof fm === 'object') {
|
||||
const hasTcp = Array.isArray(fm.tcp) && fm.tcp.length > 0;
|
||||
const hasUdp = Array.isArray(fm.udp) && fm.udp.length > 0;
|
||||
const hasQuic = fm.quicParams != null;
|
||||
if (!hasTcp && !hasUdp && !hasQuic) delete stream.finalmask;
|
||||
if (!hasTcp && !hasUdp && !hasQuic) {
|
||||
delete stream.finalmask;
|
||||
} else {
|
||||
if (!hasTcp) delete fm.tcp;
|
||||
if (!hasUdp) delete fm.udp;
|
||||
}
|
||||
}
|
||||
|
||||
// Hysteria's per-client auth lives in settings.clients[*].auth; the
|
||||
// streamSettings.hysteriaSettings.auth slot is a holdover from older
|
||||
// hysteria builds and serves no purpose on the inbound side, so an
|
||||
// empty value shouldn't ride along in the JSON payload.
|
||||
const hs = stream.hysteriaSettings as { auth?: string } | undefined;
|
||||
if (hs && typeof hs === 'object' && (hs.auth === '' || hs.auth == null)) {
|
||||
delete hs.auth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user