api9nin / src /app /api /providers /client /route.js
github-actions[bot]
deploy from github actions 2026-06-18
c8ae75d
Raw
History Blame Contribute Delete
4.67 kB
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 });
}
}