mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-16 08:10:58 +00:00
feat: add inbound share address strategy (#5162)
* feat: add inbound share address strategy Allow node-managed inbounds to choose whether exported share links use the node address, routable listen address, or a custom endpoint. Preserve locally configured share address fields during remote node traffic sync. Refs #5161 Refs #4891 * fix: preserve inbound share address settings Forward share address fields to remote nodes, keep existing values when older update payloads omit them, align localhost handling between frontend and subscriptions, and preserve share address settings when cloning inbounds. * fix: keep share address strategy out of subscriptions Limit the new share address strategy to direct exported share links and QR codes. Restore subscription address resolution to the existing panel-owned behavior and update the UI help text accordingly. * fix: address share address review feedback * fix: validate custom share address * fix --------- Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { InboundFormValues, TrafficReset } from '@/schemas/forms/inbound-form';
|
||||
import type { InboundFormValues, ShareAddrStrategy, TrafficReset } from '@/schemas/forms/inbound-form';
|
||||
import type { InboundSettings } from '@/schemas/protocols/inbound';
|
||||
import {
|
||||
HysteriaClientSchema,
|
||||
@@ -37,6 +37,8 @@ export interface RawInboundRow {
|
||||
trafficReset?: string;
|
||||
lastTrafficResetTime?: number;
|
||||
nodeId?: number | null;
|
||||
shareAddrStrategy?: string;
|
||||
shareAddr?: string;
|
||||
clientStats?: unknown;
|
||||
}
|
||||
|
||||
@@ -61,6 +63,8 @@ export interface WireInboundPayload {
|
||||
tag: string;
|
||||
clientStats?: unknown;
|
||||
nodeId?: number;
|
||||
shareAddrStrategy: ShareAddrStrategy;
|
||||
shareAddr: string;
|
||||
}
|
||||
|
||||
function coerceJsonObject(value: unknown): Record<string, unknown> {
|
||||
@@ -82,6 +86,7 @@ function coerceJsonObject(value: unknown): Record<string, unknown> {
|
||||
}
|
||||
|
||||
const TRAFFIC_RESETS: TrafficReset[] = ['never', 'hourly', 'daily', 'weekly', 'monthly'];
|
||||
const SHARE_ADDR_STRATEGIES: ShareAddrStrategy[] = ['node', 'listen', 'custom'];
|
||||
|
||||
function coerceTrafficReset(v: unknown): TrafficReset {
|
||||
return typeof v === 'string' && (TRAFFIC_RESETS as string[]).includes(v)
|
||||
@@ -89,6 +94,12 @@ function coerceTrafficReset(v: unknown): TrafficReset {
|
||||
: 'never';
|
||||
}
|
||||
|
||||
function coerceShareAddrStrategy(v: unknown): ShareAddrStrategy {
|
||||
return typeof v === 'string' && (SHARE_ADDR_STRATEGIES as string[]).includes(v)
|
||||
? (v as ShareAddrStrategy)
|
||||
: 'node';
|
||||
}
|
||||
|
||||
// Network values that map to a required `${network}Settings` key in
|
||||
// NetworkSettingsSchema. Older saved inbounds may be missing the per-
|
||||
// network sub-object (the legacy panel sometimes emitted streamSettings
|
||||
@@ -162,6 +173,8 @@ export function rawInboundToFormValues(row: RawInboundRow): InboundFormValues {
|
||||
trafficReset: coerceTrafficReset(row.trafficReset),
|
||||
lastTrafficResetTime: row.lastTrafficResetTime ?? 0,
|
||||
nodeId: row.nodeId ?? null,
|
||||
shareAddrStrategy: coerceShareAddrStrategy(row.shareAddrStrategy),
|
||||
shareAddr: row.shareAddr ?? '',
|
||||
protocol,
|
||||
settings,
|
||||
} as InboundFormValues;
|
||||
@@ -307,6 +320,8 @@ export function formValuesToWirePayload(values: InboundFormValues): WireInboundP
|
||||
// rather than the default { enabled: false } so the row carries no sniffing.
|
||||
sniffing: canEnableSniffing({ protocol: values.protocol }) ? JSON.stringify(normalizeSniffing(values.sniffing)) : '',
|
||||
tag: values.tag,
|
||||
shareAddrStrategy: values.shareAddrStrategy,
|
||||
shareAddr: values.shareAddr,
|
||||
};
|
||||
if (values.nodeId != null) payload.nodeId = values.nodeId;
|
||||
return payload;
|
||||
|
||||
Reference in New Issue
Block a user