Ctrl K
ComunidadGuías…

lib/dashboard-control-plane.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import "server-only";

import { getDashboardSessionUser } from "@/lib/dashboard-session";
import { localDemoLogs, localDemoServers } from "@/lib/local-demo";
import { hasServerNeonEnv } from "@/lib/neon/env";
import { createUserDataClient } from "@/lib/neon/server";
import type { McpServer, RuntimeLog } from "@/lib/types";
import { resolveMcpEndpoint } from "@/lib/urls";

export type CredentialSummary = {
  id: string;
  server_id: string | null;
  name: string;
  provider: string | null;
  security_scheme?: string | null;
  auth_scheme: string;
  injection_name: string | null;
  scopes: string[] | null;
  key_preview: string;
  expires_at?: string | null;
  connect_status?: string | null;
  revocation_url?: string | null;
  revocation_status?: string | null;
  revocation_error?: string | null;
  revocation_attempted_at?: string | null;
  end_user_id?: string | null;
  health_status?: string | null;
  health_checked_at?: string | null;
  expected_scopes?: string[] | null;
  consecutive_refresh_failures?: number | null;
  last_refresh_status?: string | null;
  last_refresh_at?: string | null;
  last_refresh_error?: string | null;
  reconnect_reason?: string | null;
  created_at: string;
  updated_at: string;
};

export type ApprovalSummary = {
  id: string;
  server_id: string;
  tool_name: string;
  status: string;
  expires_at: string;
  created_at: string;
};

export type DashboardControlPlane = {
  servers: McpServer[];
  credentials: CredentialSummary[];
  logs: RuntimeLog[];
  approvals: ApprovalSummary[];
  warnings: string[];
  preview: boolean;
};

export async function loadDashboardControlPlane(): Promise<DashboardControlPlane> {
  if (!hasServerNeonEnv()) {
    return {
      servers: localDemoServers(),
      credentials: [],
      logs: localDemoLogs(),
      approvals: [],
      warnings: ["Credential and approval rows appear after workspace storage is connected."],
      preview: true,
    };
  }

  const user = await getDashboardSessionUser();
  // These are user-owned dashboard reads. Use the signed-in user's JWT so
  // Postgres RLS is the authorization boundary; never sign in as the runtime
  // service identity merely to render a page.
  const admin = createUserDataClient();
  const [serversResult, initialCredentialsResult, logsResult, approvalsResult] = await Promise.all([
    admin.from("mcp_servers").select("*").eq("user_id", user.id).order("created_at", { ascending: false }),
    admin.from("api_credentials")
      .select("id,server_id,name,provider,security_scheme,auth_scheme,injection_name,scopes,expected_scopes,key_preview,expires_at,connect_status,end_user_id,revocation_url,revocation_status,revocation_error,revocation_attempted_at,health_status,health_checked_at,consecutive_refresh_failures,last_refresh_status,last_refresh_at,last_refresh_error,reconnect_reason,created_at,updated_at")
      .eq("user_id", user.id).order("created_at", { ascending: false }),
    admin.from("tool_call_logs")
      .select("id,server_id,user_id,tool_name,status,method,path,execution_mode,upstream_status,trace_id,attempt_count,error_code,error,latency_ms,end_user_id,actor_role,api_key_id,api_key_name,api_key_preview,client_name,credential_refs,bundle_id,arguments_redacted,summary,created_at")
      .eq("user_id", user.id).order("created_at", { ascending: false }).order("id", { ascending: false }).limit(100),
    admin.from("tool_approval_requests")
      .select("id,server_id,tool_name,status,expires_at,created_at")
      .eq("user_id", user.id).order("created_at", { ascending: false }).limit(100),
  ]);
  let credentialsResult: { data: unknown[] | null; error: { message: string } | null } = initialCredentialsResult;
  if (credentialsResult.error?.message.includes("column")) {
    credentialsResult = await admin.from("api_credentials")
      .select("id,server_id,name,provider,security_scheme,auth_scheme,injection_name,scopes,key_preview,expires_at,connect_status,end_user_id,created_at,updated_at")
      .eq("user_id", user.id).order("created_at", { ascending: false });
  }
  if (credentialsResult.error?.message.includes("column")) {
    credentialsResult = await admin.from("api_credentials")
      .select("id,server_id,name,provider,auth_scheme,injection_name,scopes,key_preview,created_at,updated_at")
      .eq("user_id", user.id).order("created_at", { ascending: false });
  }
  let completeLogsResult: { data: unknown[] | null; error: { message: string } | null } = logsResult;
  if (completeLogsResult.error?.message.includes("column")) {
    completeLogsResult = await admin.from("tool_call_logs")
      .select("id,server_id,user_id,tool_name,status,method,path,execution_mode,upstream_status,trace_id,attempt_count,error_code,error,latency_ms,end_user_id,actor_role,arguments_redacted,summary,created_at")
      .eq("user_id", user.id).order("created_at", { ascending: false }).order("id", { ascending: false }).limit(100);
  }
  if (completeLogsResult.error?.message.includes("column")) {
    completeLogsResult = await admin.from("tool_call_logs")
      .select("id,server_id,user_id,tool_name,status,method,path,execution_mode,upstream_status,trace_id,attempt_count,error_code,error,latency_ms,created_at")
      .eq("user_id", user.id).order("created_at", { ascending: false }).order("id", { ascending: false }).limit(100);
  }

  const warnings = [
    serversResult.error ? `Integrations: ${serversResult.error.message}` : null,
    credentialsResult.error ? `Connections: ${credentialsResult.error.message}` : null,
    completeLogsResult.error ? `Activity: ${completeLogsResult.error.message}` : null,
    approvalsResult.error ? `Approvals: ${approvalsResult.error.message}` : null,
  ].filter((value): value is string => Boolean(value));

  return {
    servers: ((serversResult.data ?? []) as McpServer[]).map((server) => ({
      ...server,
      hosted_endpoint: resolveMcpEndpoint(server.id, server.hosted_endpoint),
    })),
    credentials: (credentialsResult.data ?? []) as CredentialSummary[],
    logs: (completeLogsResult.data ?? []) as RuntimeLog[],
    approvals: (approvalsResult.data ?? []) as ApprovalSummary[],
    warnings,
    preview: false,
  };
}

export function controlPlaneStats(data: DashboardControlPlane) {
  const tools = data.servers.flatMap((server) => server.tools_json ?? []);
  return {
    integrations: data.servers.length,
    liveIntegrations: data.servers.filter((server) => server.status === "live" || server.status === "preset").length,
    connections: data.credentials.length,
    tools: tools.length,
    allow: tools.filter((tool) => (tool.policy ?? "allow") === "allow").length,
    approval: tools.filter((tool) => tool.policy === "approval").length,
    block: tools.filter((tool) => tool.policy === "block").length,
    pendingApprovals: data.approvals.filter((approval) => approval.status === "pending").length,
  };
}