refactor(frontend): narrow outbound.ts eslint-disable to no-explicit-any only

- Fix all 36 prefer-const violations: convert never-reassigned `let` to
  `const`; for mixed-mutability destructuring (fromParamLink,
  fromHysteriaLink) split into separate `const`/`let` declarations
  by index instead of destructuring.
- Fix both no-var violations: `var stream` / `var settings` → `let`.
- File still carries `/* eslint-disable @typescript-eslint/no-explicit-any */`
  because tightening 223 `any` uses requires removing CommonClass's
  `[key: string]: any` escape hatch and reshaping ~30 dynamically-attached
  subclass patterns into named classes — multi-hour architectural work
  tracked as Phase 7's twin for outbound.
This commit is contained in:
MHSanaei 2026-05-25 02:27:07 +02:00
parent 004ebe60a6
commit cc1eee0a70
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A

View file

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any, no-var, prefer-const */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { ObjectUtil, Base64, Wireguard } from '@/utils'; import { ObjectUtil, Base64, Wireguard } from '@/utils';
export const Protocols = { export const Protocols = {
@ -262,7 +262,7 @@ export class TcpStreamSettings extends CommonClass {
} }
static fromJson(json: any = {}): any { static fromJson(json: any = {}): any {
let header = json.header; const header = json.header;
if (!header) return new TcpStreamSettings(); if (!header) return new TcpStreamSettings();
if (header.type == 'http' && header.request) { if (header.type == 'http' && header.request) {
return new TcpStreamSettings( return new TcpStreamSettings(
@ -1349,14 +1349,14 @@ export class Outbound extends CommonClass {
} }
toJson() { toJson() {
var stream; let stream;
if (this.canEnableStream()) { if (this.canEnableStream()) {
stream = this.stream.toJson(); stream = this.stream.toJson();
} else { } else {
if (this.stream?.sockopt) if (this.stream?.sockopt)
stream = { sockopt: this.stream.sockopt.toJson() }; stream = { sockopt: this.stream.sockopt.toJson() };
} }
let settingsOut = this.settings instanceof CommonClass ? this.settings.toJson() : this.settings; const settingsOut = this.settings instanceof CommonClass ? this.settings.toJson() : this.settings;
return { return {
protocol: this.protocol, protocol: this.protocol,
settings: settingsOut, settings: settingsOut,
@ -1387,9 +1387,9 @@ export class Outbound extends CommonClass {
} }
static fromVmessLink(json: any = {}) { static fromVmessLink(json: any = {}) {
let stream = new StreamSettings(json.net, json.tls); const stream = new StreamSettings(json.net, json.tls);
let network = json.net; const network = json.net;
if (network === 'tcp') { if (network === 'tcp') {
stream.tcp = new TcpStreamSettings( stream.tcp = new TcpStreamSettings(
json.type, json.type,
@ -1470,15 +1470,15 @@ export class Outbound extends CommonClass {
static fromParamLink(link: any) { static fromParamLink(link: any) {
const url = new URL(link); const url = new URL(link);
let type = url.searchParams.get('type') ?? 'tcp'; const type = url.searchParams.get('type') ?? 'tcp';
let security = url.searchParams.get('security') ?? 'none'; const security = url.searchParams.get('security') ?? 'none';
let stream = new StreamSettings(type, security); const stream = new StreamSettings(type, security);
let headerType = url.searchParams.get('headerType') ?? undefined; const headerType = url.searchParams.get('headerType') ?? undefined;
let host = url.searchParams.get('host') ?? undefined; const host = url.searchParams.get('host') ?? undefined;
let path = url.searchParams.get('path') ?? undefined; const path = url.searchParams.get('path') ?? undefined;
let seed = url.searchParams.get('seed') ?? path ?? undefined; const seed = url.searchParams.get('seed') ?? path ?? undefined;
let mode = url.searchParams.get('mode') ?? undefined; const mode = url.searchParams.get('mode') ?? undefined;
if (type === 'tcp' || type === 'none') { if (type === 'tcp' || type === 'none') {
stream.tcp = new TcpStreamSettings(headerType ?? 'none', host, path); stream.tcp = new TcpStreamSettings(headerType ?? 'none', host, path);
@ -1546,20 +1546,20 @@ export class Outbound extends CommonClass {
} }
if (security == 'tls') { if (security == 'tls') {
let fp = url.searchParams.get('fp') ?? 'none'; const fp = url.searchParams.get('fp') ?? 'none';
let alpn = url.searchParams.get('alpn'); const alpn = url.searchParams.get('alpn');
let sni = url.searchParams.get('sni') ?? ''; const sni = url.searchParams.get('sni') ?? '';
let ech = url.searchParams.get('ech') ?? ''; const ech = url.searchParams.get('ech') ?? '';
stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, ech); stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, ech);
} }
if (security == 'reality') { if (security == 'reality') {
let pbk = url.searchParams.get('pbk'); const pbk = url.searchParams.get('pbk');
let fp = url.searchParams.get('fp'); const fp = url.searchParams.get('fp');
let sni = url.searchParams.get('sni') ?? ''; const sni = url.searchParams.get('sni') ?? '';
let sid = url.searchParams.get('sid') ?? ''; const sid = url.searchParams.get('sid') ?? '';
let spx = url.searchParams.get('spx') ?? ''; const spx = url.searchParams.get('spx') ?? '';
let pqv = url.searchParams.get('pqv') ?? ''; const pqv = url.searchParams.get('pqv') ?? '';
stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx, pqv); stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx, pqv);
} }
@ -1567,13 +1567,16 @@ export class Outbound extends CommonClass {
const match = link.match(regex); const match = link.match(regex);
if (!match) return null; if (!match) return null;
let [, protocol, userData, address, port,] = match; const address = match[3];
let protocol = match[1];
let userData: any = match[2];
let port: any = match[4];
port *= 1; port *= 1;
if (protocol == 'ss') { if (protocol == 'ss') {
protocol = 'shadowsocks'; protocol = 'shadowsocks';
userData = atob(userData).split(':'); userData = atob(userData).split(':');
} }
var settings; let settings;
switch (protocol) { switch (protocol) {
case Protocols.VLESS: case Protocols.VLESS:
settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? '', url.searchParams.get('encryption') ?? 'none'); settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? '', url.searchParams.get('encryption') ?? 'none');
@ -1610,22 +1613,23 @@ export class Outbound extends CommonClass {
if (!match) return null; if (!match) return null;
let [, password, address, port, params, hash] = match; const password = match[1];
const address = match[2];
let port: any = match[3];
const params = match[4];
const hash = match[5];
port = parseInt(port); port = parseInt(port);
// Parse URL parameters if present const urlParams = new URLSearchParams(params);
let urlParams = new URLSearchParams(params);
// Create stream settings with hysteria network const security = urlParams.get('security') ?? 'none';
let security = urlParams.get('security') ?? 'none'; const stream = new StreamSettings('hysteria', security);
let stream = new StreamSettings('hysteria', security);
// Parse TLS settings when security=tls
if (security === 'tls') { if (security === 'tls') {
let fp = urlParams.get('fp') ?? 'none'; const fp = urlParams.get('fp') ?? 'none';
let alpn = urlParams.get('alpn'); const alpn = urlParams.get('alpn');
let sni = urlParams.get('sni') ?? ''; const sni = urlParams.get('sni') ?? '';
let ech = urlParams.get('ech') ?? ''; const ech = urlParams.get('ech') ?? '';
stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, ech); stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, ech);
} }
@ -1700,11 +1704,9 @@ export class Outbound extends CommonClass {
} catch (_) { /* ignore malformed fm */ } } catch (_) { /* ignore malformed fm */ }
} }
// Create settings const settings = new Outbound.HysteriaSettings(address, port, 2);
let settings = new Outbound.HysteriaSettings(address, port, 2);
// Extract remark from hash const remark = hash ? decodeURIComponent(hash.substring(1)) : `out-hysteria-${port}`;
let remark = hash ? decodeURIComponent(hash.substring(1)) : `out-hysteria-${port}`;
return new Outbound(remark, Protocols.Hysteria, settings, stream); return new Outbound(remark, Protocols.Hysteria, settings, stream);
} }