Spaces:
Paused
Paused
| /** Upstream proxy config persistence for upstream_proxy_config table. */ | |
| import { getDbInstance } from "./core"; | |
| interface UpstreamProxyConfig { | |
| id: number; | |
| providerId: string; | |
| mode: string; | |
| cliproxyapiModelMapping: Record<string, unknown> | null; | |
| nativePriority: number; | |
| cliproxyapiPriority: number; | |
| enabled: boolean; | |
| createdAt: string; | |
| updatedAt: string; | |
| } | |
| interface UpstreamProxyRow { | |
| id: unknown; | |
| provider_id: unknown; | |
| mode: unknown; | |
| cliproxyapi_model_mapping: unknown; | |
| native_priority: unknown; | |
| cliproxyapi_priority: unknown; | |
| enabled: unknown; | |
| created_at: unknown; | |
| updated_at: unknown; | |
| } | |
| function toRecord(value: unknown): Record<string, unknown> { | |
| return value && typeof value === "object" ? (value as Record<string, unknown>) : {}; | |
| } | |
| const BLOCKED_HOSTNAMES = ["metadata.google.internal", "169.254.169.254", "metadata.aws.internal"]; | |
| function isPrivateHost(hostname: string): boolean { | |
| // CLIProxyAPI runs on localhost:8317 — allow loopback explicitly | |
| if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") return false; | |
| if (BLOCKED_HOSTNAMES.includes(hostname)) return true; | |
| if ( | |
| /^10\./.test(hostname) || | |
| /^172\.(1[6-9]|2\d|3[01])\./.test(hostname) || | |
| /^192\.168\./.test(hostname) | |
| ) | |
| return true; | |
| if ( | |
| /^0\./.test(hostname) || | |
| /^127\./.test(hostname) || | |
| /^224\./.test(hostname) || | |
| /^169\.254\./.test(hostname) | |
| ) | |
| return true; | |
| return false; | |
| } | |
| export function validateProxyUrl( | |
| url: string | |
| ): { valid: true; url: string } | { valid: false; error: string } { | |
| try { | |
| const parsed = new URL(url); | |
| if (!["http:", "https:"].includes(parsed.protocol)) { | |
| return { | |
| valid: false, | |
| error: `Unsupported protocol "${parsed.protocol}" — use http or https`, | |
| }; | |
| } | |
| if (isPrivateHost(parsed.hostname)) { | |
| return { | |
| valid: false, | |
| error: `Proxy URL cannot point to private/internal address "${parsed.hostname}"`, | |
| }; | |
| } | |
| return { valid: true, url }; | |
| } catch { | |
| return { valid: false, error: `Invalid URL: "${url}"` }; | |
| } | |
| } | |
| function rowToConfig(record: Record<string, unknown>): UpstreamProxyConfig { | |
| let mapping: Record<string, unknown> | null = null; | |
| if (record.cliproxyapi_model_mapping && typeof record.cliproxyapi_model_mapping === "string") { | |
| try { | |
| mapping = JSON.parse(record.cliproxyapi_model_mapping); | |
| } catch { | |
| mapping = null; | |
| } | |
| } | |
| return { | |
| id: record.id as number, | |
| providerId: record.provider_id as string, | |
| mode: record.mode as string, | |
| cliproxyapiModelMapping: mapping, | |
| nativePriority: record.native_priority as number, | |
| cliproxyapiPriority: record.cliproxyapi_priority as number, | |
| enabled: record.enabled === 1 || record.enabled === true, | |
| createdAt: record.created_at as string, | |
| updatedAt: record.updated_at as string, | |
| }; | |
| } | |
| export async function getUpstreamProxyConfigs() { | |
| const db = getDbInstance(); | |
| const rows = db | |
| .prepare("SELECT * FROM upstream_proxy_config ORDER BY provider_id") | |
| .all() as UpstreamProxyRow[]; | |
| return rows.map((row) => rowToConfig(toRecord(row))); | |
| } | |
| export async function getUpstreamProxyConfig(providerId: string) { | |
| const db = getDbInstance(); | |
| const row = db | |
| .prepare("SELECT * FROM upstream_proxy_config WHERE provider_id = ?") | |
| .get(providerId) as UpstreamProxyRow | undefined; | |
| if (!row) return null; | |
| return rowToConfig(toRecord(row)); | |
| } | |
| export async function upsertUpstreamProxyConfig(data: { | |
| providerId: string; | |
| mode?: string; | |
| cliproxyapiModelMapping?: Record<string, unknown> | null; | |
| nativePriority?: number; | |
| cliproxyapiPriority?: number; | |
| enabled?: boolean; | |
| }) { | |
| const db = getDbInstance(); | |
| const mode = data.mode ?? "native"; | |
| const cliproxyapiModelMapping = | |
| data.cliproxyapiModelMapping !== undefined | |
| ? JSON.stringify(data.cliproxyapiModelMapping) | |
| : null; | |
| const nativePriority = data.nativePriority ?? 1; | |
| const cliproxyapiPriority = data.cliproxyapiPriority ?? 2; | |
| const enabled = data.enabled !== false ? 1 : 0; | |
| db.prepare( | |
| `INSERT INTO upstream_proxy_config | |
| (provider_id, mode, cliproxyapi_model_mapping, native_priority, cliproxyapi_priority, enabled, created_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, datetime('now'), datetime('now')) | |
| ON CONFLICT(provider_id) DO UPDATE SET | |
| mode = excluded.mode, | |
| cliproxyapi_model_mapping = excluded.cliproxyapi_model_mapping, | |
| native_priority = excluded.native_priority, | |
| cliproxyapi_priority = excluded.cliproxyapi_priority, | |
| enabled = excluded.enabled, | |
| updated_at = datetime('now')` | |
| ).run( | |
| data.providerId, | |
| mode, | |
| cliproxyapiModelMapping, | |
| nativePriority, | |
| cliproxyapiPriority, | |
| enabled | |
| ); | |
| return getUpstreamProxyConfig(data.providerId); | |
| } | |
| export async function updateUpstreamProxyConfig( | |
| providerId: string, | |
| updates: Record<string, unknown> | |
| ) { | |
| const db = getDbInstance(); | |
| const current = await getUpstreamProxyConfig(providerId); | |
| if (!current) { | |
| throw new Error(`Provider ${providerId} not found`); | |
| } | |
| const sets: string[] = ["updated_at = datetime('now')"]; | |
| const params: unknown[] = []; | |
| if (updates.mode !== undefined) { | |
| sets.push("mode = ?"); | |
| params.push(updates.mode); | |
| } | |
| if (updates.cliproxyapiModelMapping !== undefined) { | |
| sets.push("cliproxyapi_model_mapping = ?"); | |
| params.push( | |
| updates.cliproxyapiModelMapping === null | |
| ? null | |
| : JSON.stringify(updates.cliproxyapiModelMapping) | |
| ); | |
| } | |
| if (updates.nativePriority !== undefined) { | |
| sets.push("native_priority = ?"); | |
| params.push(updates.nativePriority); | |
| } | |
| if (updates.cliproxyapiPriority !== undefined) { | |
| sets.push("cliproxyapi_priority = ?"); | |
| params.push(updates.cliproxyapiPriority); | |
| } | |
| if (updates.enabled !== undefined) { | |
| sets.push("enabled = ?"); | |
| params.push(updates.enabled === true ? 1 : 0); | |
| } | |
| params.push(providerId); | |
| db.prepare(`UPDATE upstream_proxy_config SET ${sets.join(", ")} WHERE provider_id = ?`).run( | |
| ...params | |
| ); | |
| return getUpstreamProxyConfig(providerId); | |
| } | |
| export async function deleteUpstreamProxyConfig(providerId: string) { | |
| const db = getDbInstance(); | |
| const result = db | |
| .prepare("DELETE FROM upstream_proxy_config WHERE provider_id = ?") | |
| .run(providerId); | |
| return result.changes > 0; | |
| } | |
| export async function getProvidersByMode(mode: string) { | |
| const db = getDbInstance(); | |
| const rows = db | |
| .prepare( | |
| "SELECT * FROM upstream_proxy_config WHERE mode = ? AND enabled = 1 ORDER BY provider_id" | |
| ) | |
| .all(mode) as UpstreamProxyRow[]; | |
| return rows.map((row) => rowToConfig(toRecord(row))); | |
| } | |
| export async function getFallbackChainForProvider(providerId: string) { | |
| const config = await getUpstreamProxyConfig(providerId); | |
| if (!config) return []; | |
| const chain: { executor: "native" | "cliproxyapi"; priority: number }[] = []; | |
| if (config.enabled) { | |
| chain.push({ executor: "native", priority: config.nativePriority }); | |
| if (config.mode === "cliproxyapi" || config.mode === "fallback") { | |
| chain.push({ executor: "cliproxyapi", priority: config.cliproxyapiPriority }); | |
| } | |
| } | |
| chain.sort((a, b) => a.priority - b.priority); | |
| return chain; | |
| } | |