import { NextResponse } from "next/server"; import { getProviderConnections } from "@/lib/localDb"; import { backfillCodexEmails } from "@/lib/oauth/providers"; import { USAGE_APIKEY_PROVIDERS, USAGE_SUPPORTED_PROVIDERS } from "@/shared/constants/providers"; const SAFE_FIELDS = [ "id", "provider", "authType", "name", "email", "displayName", "priority", "globalPriority", "isActive", "defaultModel", "testStatus", "lastError", "lastErrorAt", "errorCode", "expiresAt", "lastUsedAt", "consecutiveUseCount", "createdAt", "updatedAt", ]; const SAFE_PSD_FIELDS = [ "baseUrl", "azureEndpoint", "deployment", "apiVersion", "accountId", "region", "projectId", "resourceUrl", "proxyPoolId", "connectionProxyEnabled", "connectionProxyUrl", "connectionNoProxy", "githubLogin", "githubName", "githubEmail", "githubUserId", "username", "firstName", "lastName", "authMethod", "authKind", "profileArn", ]; const DEFAULT_PAGE_SIZE = 20; const MAX_PAGE_SIZE = 500; function maskName(name) { if (typeof name !== "string" || name.length <= 16) return name; if (/[a-zA-Z0-9_-]{32,}/.test(name)) return `${name.slice(0, 8)}***`; return name; } function sanitize(c) { const safe = {}; for (const f of SAFE_FIELDS) if (c[f] !== undefined) safe[f] = c[f]; if (safe.name) safe.name = maskName(safe.name); if (c.providerSpecificData) { const psd = {}; for (const f of SAFE_PSD_FIELDS) { if (c.providerSpecificData[f] !== undefined) psd[f] = c.providerSpecificData[f]; } safe.providerSpecificData = psd; } return safe; } function isUsageEligible(connection) { return USAGE_SUPPORTED_PROVIDERS.includes(connection.provider) && ( connection.authType === "oauth" || USAGE_APIKEY_PROVIDERS.includes(connection.provider) ); } function parsePositiveInt(value, fallback) { const parsed = Number.parseInt(value, 10); return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback; } function sortConnections(connections, sort) { const list = [...connections]; if (sort === "provider") { return list.sort((a, b) => { const orderA = USAGE_SUPPORTED_PROVIDERS.indexOf(a.provider); const orderB = USAGE_SUPPORTED_PROVIDERS.indexOf(b.provider); if (orderA !== orderB) return orderA - orderB; return a.provider.localeCompare(b.provider); }); } return list.sort((a, b) => { const priorityA = a.priority ?? Number.MAX_SAFE_INTEGER; const priorityB = b.priority ?? Number.MAX_SAFE_INTEGER; if (priorityA !== priorityB) return priorityA - priorityB; return (a.provider || "").localeCompare(b.provider || ""); }); } export async function GET(request) { try { await backfillCodexEmails(); const { searchParams } = new URL(request.url); const provider = searchParams.get("provider") || "all"; const accountStatus = searchParams.get("accountStatus") || "all"; const sort = searchParams.get("sort") || "priority"; const page = parsePositiveInt(searchParams.get("page"), 1); const pageSize = Math.min(parsePositiveInt(searchParams.get("pageSize"), DEFAULT_PAGE_SIZE), MAX_PAGE_SIZE); const allConnections = await getProviderConnections(); const eligibleConnections = allConnections.filter(isUsageEligible); const providerOptions = Array.from(new Set(eligibleConnections.map((conn) => conn.provider))).sort(); const providerFilteredConnections = eligibleConnections.filter((conn) => ( provider === "all" || conn.provider === provider )); const accountFilteredConnections = providerFilteredConnections.filter((conn) => { if (accountStatus === "active") return conn.isActive ?? true; if (accountStatus === "inactive") return !(conn.isActive ?? true); return true; }); const sortedConnections = sortConnections(accountFilteredConnections, sort); const total = sortedConnections.length; const totalPages = Math.max(1, Math.ceil(total / pageSize)); const currentPage = Math.min(page, totalPages); const offset = (currentPage - 1) * pageSize; const pageConnections = sortedConnections.slice(offset, offset + pageSize).map(sanitize); return NextResponse.json({ connections: pageConnections, providerOptions, pagination: { page: currentPage, pageSize, total, totalPages, }, totals: { eligibleConnections: eligibleConnections.length, providerFilteredConnections: providerFilteredConnections.length, }, }); } catch (error) { console.log("Error fetching providers for client:", error); return NextResponse.json({ error: "Failed to fetch providers" }, { status: 500 }); } }