mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
* fix(i18n): code shared validation errors and translate speech model, setup source and project group copy * fix(i18n): keep detected label for unknown setup import providers --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
139 lines
3.9 KiB
TypeScript
139 lines
3.9 KiB
TypeScript
export type NetworkProxySettings = {
|
|
httpProxyUrl?: string | null
|
|
httpProxyBypassRules?: string | null
|
|
}
|
|
|
|
// One English table: `message` stays English; the settings UI translates by code.
|
|
export const PROXY_URL_FAILURE_COPY = {
|
|
tooLong: 'Proxy URL is too long.',
|
|
invalid: 'Enter a valid proxy URL.',
|
|
unsupportedProtocol: 'Use an http, https, socks, socks4, or socks5 proxy URL.',
|
|
missingHost: 'Proxy URL must include a host.'
|
|
} as const
|
|
|
|
export type ProxyUrlFailureCode = keyof typeof PROXY_URL_FAILURE_COPY
|
|
|
|
export type ProxyUrlValidationResult =
|
|
| { ok: true; value: string; message?: undefined }
|
|
| { ok: false; value: ''; message: string; code: ProxyUrlFailureCode }
|
|
|
|
function proxyUrlFailure(code: ProxyUrlFailureCode): ProxyUrlValidationResult {
|
|
return { ok: false, value: '', message: PROXY_URL_FAILURE_COPY[code], code }
|
|
}
|
|
|
|
const PROXY_URL_MAX_LENGTH = 2048
|
|
const PROXY_BYPASS_RULES_MAX_LENGTH = 4096
|
|
const PROXY_PROTOCOLS = new Set(['http:', 'https:', 'socks:', 'socks4:', 'socks5:'])
|
|
const PROXY_ENV_KEYS = [
|
|
'HTTPS_PROXY',
|
|
'https_proxy',
|
|
'ALL_PROXY',
|
|
'all_proxy',
|
|
'HTTP_PROXY',
|
|
'http_proxy'
|
|
] as const
|
|
const NO_PROXY_ENV_KEYS = ['NO_PROXY', 'no_proxy'] as const
|
|
|
|
function formatProxyUrl(url: URL): string {
|
|
const auth =
|
|
url.username || url.password ? `${url.username}${url.password ? `:${url.password}` : ''}@` : ''
|
|
return `${url.protocol}//${auth}${url.host}`
|
|
}
|
|
|
|
export function normalizeProxyUrl(value: unknown): ProxyUrlValidationResult {
|
|
if (typeof value !== 'string') {
|
|
return { ok: true, value: '' }
|
|
}
|
|
const trimmed = value.trim()
|
|
if (!trimmed) {
|
|
return { ok: true, value: '' }
|
|
}
|
|
if (trimmed.length > PROXY_URL_MAX_LENGTH) {
|
|
return proxyUrlFailure('tooLong')
|
|
}
|
|
|
|
let parsed: URL
|
|
try {
|
|
parsed = new URL(trimmed)
|
|
} catch {
|
|
return proxyUrlFailure('invalid')
|
|
}
|
|
if (!PROXY_PROTOCOLS.has(parsed.protocol)) {
|
|
return proxyUrlFailure('unsupportedProtocol')
|
|
}
|
|
if (!parsed.hostname) {
|
|
return proxyUrlFailure('missingHost')
|
|
}
|
|
return { ok: true, value: formatProxyUrl(parsed) }
|
|
}
|
|
|
|
export function normalizeProxyBypassRules(value: unknown): string {
|
|
if (typeof value !== 'string') {
|
|
return ''
|
|
}
|
|
return value
|
|
.slice(0, PROXY_BYPASS_RULES_MAX_LENGTH)
|
|
.split(/[;,\n]/)
|
|
.map((rule) => rule.trim())
|
|
.filter(Boolean)
|
|
.join(';')
|
|
}
|
|
|
|
export function getProxyUrlFromEnvironment(
|
|
env: Record<string, string | undefined>
|
|
): ProxyUrlValidationResult {
|
|
for (const key of PROXY_ENV_KEYS) {
|
|
if (env[key]) {
|
|
return normalizeProxyUrl(env[key])
|
|
}
|
|
}
|
|
return { ok: true, value: '' }
|
|
}
|
|
|
|
export function getProxyBypassRulesFromEnvironment(
|
|
env: Record<string, string | undefined>
|
|
): string {
|
|
for (const key of NO_PROXY_ENV_KEYS) {
|
|
if (env[key]) {
|
|
return normalizeProxyBypassRules(env[key])
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
export function buildConfiguredProxyEnv(
|
|
settings: NetworkProxySettings | null | undefined
|
|
): Record<string, string> {
|
|
const proxy = normalizeProxyUrl(settings?.httpProxyUrl)
|
|
if (!proxy.ok || !proxy.value) {
|
|
return {}
|
|
}
|
|
const env: Record<string, string> = {
|
|
HTTP_PROXY: proxy.value,
|
|
HTTPS_PROXY: proxy.value,
|
|
ALL_PROXY: proxy.value,
|
|
http_proxy: proxy.value,
|
|
https_proxy: proxy.value,
|
|
all_proxy: proxy.value
|
|
}
|
|
const bypassRules = normalizeProxyBypassRules(settings?.httpProxyBypassRules)
|
|
// Explicit proxy settings must not inherit shell NO_PROXY; only the configured bypass field controls child-process exclusions.
|
|
const noProxy = bypassRules ? bypassRules.replaceAll(';', ',') : ''
|
|
env.NO_PROXY = noProxy
|
|
env.no_proxy = noProxy
|
|
return env
|
|
}
|
|
|
|
export function redactProxyUrl(value: string): string {
|
|
const parsed = normalizeProxyUrl(value)
|
|
if (!parsed.ok || !parsed.value) {
|
|
return parsed.value
|
|
}
|
|
const url = new URL(parsed.value)
|
|
if (url.username || url.password) {
|
|
url.username = '***'
|
|
url.password = url.password ? '***' : ''
|
|
}
|
|
return formatProxyUrl(url)
|
|
}
|