140 lines
4.6 KiB
TypeScript
140 lines
4.6 KiB
TypeScript
import { fileRouter } from "../..";
|
|
import { requireSession } from "../../lib/RouteAuth";
|
|
import {
|
|
createAgent,
|
|
deleteAgent,
|
|
listAgents,
|
|
regenerateApiKey,
|
|
setAgentDisabled,
|
|
updateAgent,
|
|
} from "../../lib/AgentService";
|
|
import { recordAudit } from "../../lib/Audit";
|
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
function reply(ctr: any, result: { ok: boolean; status?: number; message?: string; data?: unknown }) {
|
|
if (!result.ok) {
|
|
return ctr.status(result.status ?? 400).print({ status: "FAILED", message: result.message });
|
|
}
|
|
return ctr.print({ status: "OK", data: (result as any).data });
|
|
}
|
|
|
|
export = new fileRouter.Path("/")
|
|
// List agents
|
|
.http("GET", "/api/agents", (http) =>
|
|
http.onRequest(async (ctr) => {
|
|
const session = requireSession(ctr);
|
|
if (!session) return;
|
|
const agents = await listAgents(session.user);
|
|
return ctr.print({ status: "OK", data: agents });
|
|
}),
|
|
)
|
|
// Create agent
|
|
.http("POST", "/api/agents", (http) =>
|
|
http
|
|
.ratelimit((limit) => limit.hits(10).window(60000).penalty(2000))
|
|
.onRequest(async (ctr) => {
|
|
const session = requireSession(ctr);
|
|
if (!session) return;
|
|
const [data, error] = await ctr.bindBody((z) =>
|
|
z.object({
|
|
name: z.string().min(1).max(128),
|
|
description: z.string().max(500).nullable().optional(),
|
|
website: z.string().max(300).nullable().optional(),
|
|
icon_url: z.string().max(1000).nullable().optional(),
|
|
max_pending_requests: z.number().int().min(1).max(10).optional(),
|
|
}),
|
|
);
|
|
if (!data) return ctr.status(ctr.$status.BAD_REQUEST).print(error.toString());
|
|
const result = await createAgent(session.user, data);
|
|
if (result.ok) {
|
|
await recordAudit({
|
|
actorId: session.user.id,
|
|
action: "agent_created",
|
|
targetType: "agent",
|
|
targetId: String((result.data as any).id),
|
|
});
|
|
}
|
|
return reply(ctr, result);
|
|
}),
|
|
)
|
|
// Update agent
|
|
.http("PATCH", "/api/agents/{id}", (http) =>
|
|
http.onRequest(async (ctr) => {
|
|
const session = requireSession(ctr);
|
|
if (!session) return;
|
|
const id = Number(ctr.params.get("id"));
|
|
if (Number.isNaN(id)) {
|
|
return ctr.status(ctr.$status.BAD_REQUEST).print({ status: "FAILED", message: "Invalid agent id" });
|
|
}
|
|
const [data, error] = await ctr.bindBody((z) =>
|
|
z.object({
|
|
name: z.string().min(1).max(128).optional(),
|
|
description: z.string().max(500).nullable().optional(),
|
|
website: z.string().max(300).nullable().optional(),
|
|
icon_url: z.string().max(1000).nullable().optional(),
|
|
max_pending_requests: z.number().int().min(1).max(10).optional(),
|
|
}),
|
|
);
|
|
if (!data) return ctr.status(ctr.$status.BAD_REQUEST).print(error.toString());
|
|
return reply(ctr, await updateAgent(session.user, id, data));
|
|
}),
|
|
)
|
|
// Regenerate API key
|
|
.http("POST", "/api/agents/{id}/regenerate-key", (http) =>
|
|
http
|
|
.ratelimit((limit) => limit.hits(10).window(60000).penalty(2000))
|
|
.onRequest(async (ctr) => {
|
|
const session = requireSession(ctr);
|
|
if (!session) return;
|
|
const id = Number(ctr.params.get("id"));
|
|
if (Number.isNaN(id)) {
|
|
return ctr.status(ctr.$status.BAD_REQUEST).print({ status: "FAILED", message: "Invalid agent id" });
|
|
}
|
|
const result = await regenerateApiKey(session.user, id);
|
|
if (result.ok) {
|
|
await recordAudit({
|
|
actorId: session.user.id,
|
|
action: "agent_key_regenerated",
|
|
targetType: "agent",
|
|
targetId: String(id),
|
|
});
|
|
}
|
|
return reply(ctr, result);
|
|
}),
|
|
)
|
|
// Enable / disable agent
|
|
.http("POST", "/api/agents/{id}/disabled", (http) =>
|
|
http.onRequest(async (ctr) => {
|
|
const session = requireSession(ctr);
|
|
if (!session) return;
|
|
const id = Number(ctr.params.get("id"));
|
|
if (Number.isNaN(id)) {
|
|
return ctr.status(ctr.$status.BAD_REQUEST).print({ status: "FAILED", message: "Invalid agent id" });
|
|
}
|
|
const [data, error] = await ctr.bindBody((z) => z.object({ disabled: z.boolean() }));
|
|
if (!data) return ctr.status(ctr.$status.BAD_REQUEST).print(error.toString());
|
|
return reply(ctr, await setAgentDisabled(session.user, id, data.disabled));
|
|
}),
|
|
)
|
|
// Delete agent
|
|
.http("DELETE", "/api/agents/{id}", (http) =>
|
|
http.onRequest(async (ctr) => {
|
|
const session = requireSession(ctr);
|
|
if (!session) return;
|
|
const id = Number(ctr.params.get("id"));
|
|
if (Number.isNaN(id)) {
|
|
return ctr.status(ctr.$status.BAD_REQUEST).print({ status: "FAILED", message: "Invalid agent id" });
|
|
}
|
|
const result = await deleteAgent(session.user, id);
|
|
if (result.ok) {
|
|
await recordAudit({
|
|
actorId: session.user.id,
|
|
action: "agent_deleted",
|
|
targetType: "agent",
|
|
targetId: String(id),
|
|
});
|
|
}
|
|
return reply(ctr, result);
|
|
}),
|
|
);
|