import { eq } from "drizzle-orm"; import { db } from "./db"; import { credentials as credentialsTable } from "@homelab/db"; export type Provider = | "github" | "gitlab" | "gitea" | "anthropic" | "openai" | "openrouter" | "google" | "opencode-zen" | "opencode-go"; export const GIT_PROVIDERS: Provider[] = ["github", "gitlab", "gitea"]; export const AI_PROVIDERS: Provider[] = ["anthropic", "openai", "openrouter", "google", "opencode-zen", "opencode-go"]; export interface Credential { id: string; provider: Provider; label: string; token: string; baseUrl?: string; } function maskToken(token: string): string { if (token.length <= 8) return "••••••••"; return token.slice(0, 4) + "••••" + token.slice(-4); } function rowToCredential(row: typeof credentialsTable.$inferSelect): Credential { return { id: row.id, provider: row.provider as Provider, label: row.label, token: row.token, baseUrl: row.baseUrl ?? undefined, }; } export async function getAllCredentials(): Promise { const rows = await db.select().from(credentialsTable); return rows.map(r => ({ ...rowToCredential(r), token: maskToken(r.token) })); } export async function getCredentialsByKind(kind: "git" | "ai"): Promise { const providers = kind === "git" ? GIT_PROVIDERS : AI_PROVIDERS; const rows = await db.select().from(credentialsTable); return rows .filter(r => providers.includes(r.provider as Provider)) .map(r => ({ ...rowToCredential(r), token: maskToken(r.token) })); } export async function getCredential(id: string): Promise { const [row] = await db.select().from(credentialsTable).where(eq(credentialsTable.id, id)); return row ? rowToCredential(row) : undefined; } export async function getCredentialsByProvider(provider: Provider): Promise { const rows = await db.select().from(credentialsTable).where(eq(credentialsTable.provider, provider)); return rows.map(r => ({ ...rowToCredential(r), token: maskToken(r.token) })); } export async function getRawCredentialsByProvider(provider: Provider): Promise { const rows = await db.select().from(credentialsTable).where(eq(credentialsTable.provider, provider)); return rows.map(rowToCredential); } export async function upsertCredential(cred: Credential): Promise { await db.insert(credentialsTable).values({ id: cred.id, provider: cred.provider, label: cred.label, token: cred.token, baseUrl: cred.baseUrl, }).onConflictDoUpdate({ target: credentialsTable.id, set: { provider: cred.provider, label: cred.label, token: cred.token, baseUrl: cred.baseUrl, updatedAt: new Date(), }, }); return { ...cred, token: maskToken(cred.token) }; } export async function deleteCredential(id: string): Promise { const result = await db.delete(credentialsTable).where(eq(credentialsTable.id, id)); return (result as unknown as { rowCount: number }).rowCount > 0; }