51 lines · 2.0 KB
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { limitWrite } from "~/server/limits";
import { createAgent, deleteAgent, listAgents, MAX_AGENT_TOKEN_DAYS, mintAgentToken } from "~/server/mcp/agents";
import { TOKEN_AREAS } from "~/server/token-scope";

const areaAccess = z.enum(["read", "write"]).optional();

export const listAgentIdentities = createServerFn({ method: "GET" })
  .middleware([viewerMiddleware])
  .handler(async ({ context }) => listAgents(requireViewer(context.viewer).id));

export const createAgentIdentity = createServerFn({ method: "POST" })
  .middleware([viewerMiddleware])
  .validator(z.object({ name: z.string().trim().min(1).max(64), description: z.string().trim().max(500) }))
  .handler(async ({ data, context }) => {
    const viewer = requireViewer(context.viewer);
    await limitWrite(viewer);
    return createAgent(viewer, data.name, data.description || null);
  });

export const deleteAgentIdentity = createServerFn({ method: "POST" })
  .middleware([viewerMiddleware])
  .validator(z.object({ id: z.string() }))
  .handler(async ({ data, context }) => {
    const viewer = requireViewer(context.viewer);
    await limitWrite(viewer);
    await deleteAgent(viewer, data.id);
    return { ok: true };
  });

export const createAgentToken = createServerFn({ method: "POST" })
  .middleware([viewerMiddleware])
  .validator(
    z.object({
      id: z.string(),
      repos: z.array(z.string()).max(50),
      allRepos: z.boolean(),
      permissions: z.object(Object.fromEntries(TOKEN_AREAS.map((area) => [area, areaAccess]))),