Refactor VPN proxy client implementation
Build and Deploy Gateway / build-and-push (push) Failing after 2s
Build and Deploy Gateway / deploy (push) Has been skipped

This commit is contained in:
2026-08-09 00:41:52 +03:00
parent 32be4380a3
commit 34d8b681ad
190 changed files with 20064 additions and 9761 deletions
+105
View File
@@ -0,0 +1,105 @@
export interface ServerIdentityInput extends Record<string, unknown> {
id?: unknown;
label?: unknown;
tag?: unknown;
host?: unknown;
server?: unknown;
port?: unknown;
server_port?: unknown;
protocol?: unknown;
type?: unknown;
country?: unknown;
city?: unknown;
provider?: unknown;
}
export interface NormalizedServer extends Record<string, unknown> {
id: string;
label: string;
host: string;
port: number;
protocol: string;
tag: string;
server: string;
server_port: number;
type: string;
}
const text = (value: unknown) => String(value || '').trim();
function record(value: unknown): ServerIdentityInput {
return value && typeof value === 'object' && !Array.isArray(value)
? value as ServerIdentityInput
: {};
}
function hash64(value: string) {
let hash = 0xcbf29ce484222325n;
for (let index = 0; index < value.length; index += 1) {
hash ^= BigInt(value.charCodeAt(index));
hash = BigInt.asUintN(64, hash * 0x100000001b3n);
}
return hash.toString(16).padStart(16, '0');
}
export function serverIdentityKey(value: unknown) {
const server = record(value);
const protocol = text(server.protocol || server.type).toLowerCase();
const host = text(server.host || server.server).toLowerCase();
const port = Number(server.port || server.server_port) || 0;
return `${protocol}\u0000${host}\u0000${port}`;
}
export function createServerId(server: unknown) {
return `srv_${hash64(`endpoint\u0000${serverIdentityKey(server)}`)}`;
}
export function normalizeServer(server: unknown): NormalizedServer {
const source = record(server);
const protocol = text(source.protocol || source.type).toLowerCase();
const host = text(source.host || source.server);
const port = Number(source.port || source.server_port) || 0;
const id = text(source.id) || createServerId(source);
const label = text(source.label || source.tag) || host;
const metadata = Object.fromEntries([
['country', text(source.country)],
['city', text(source.city)],
['provider', text(source.provider)],
].filter(([, value]) => value));
return {
id,
label,
host,
port,
protocol,
...metadata,
// v0 aliases remain until old clients no longer consume this API.
tag: label,
server: host,
server_port: port,
type: protocol,
};
}
export function normalizeServers(servers: unknown): NormalizedServer[] {
const seen = new Set<string>();
return (Array.isArray(servers) ? servers : []).flatMap((server) => {
const normalized = normalizeServer(server);
if (!normalized.id || seen.has(normalized.id)) return [];
seen.add(normalized.id);
return [normalized];
});
}
export function resolveServerId(
servers: readonly Pick<NormalizedServer, 'id' | 'label'>[],
serverId: unknown,
legacyTag: unknown = '',
) {
const id = text(serverId);
if (id) return servers.some((server) => server.id === id) ? id : '';
const tag = text(legacyTag);
const matches = tag ? servers.filter((server) => server.label === tag) : [];
return matches.length === 1 ? matches[0].id : '';
}