Files
agent-park/src/app/api/discovery/check-duplicates/route.ts
T

190 lines
4.2 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { CheckTaskDuplicatesSchema } from "@/lib/validations";
import { isValidApiKey } from "@/lib/auth";
type DuplicateCheckResult = {
url: string;
shouldCreate: boolean;
reason: string;
existingTask?: {
id: string;
status: string;
sourceUrl: string;
createdAt: Date;
projectId?: string | null;
};
existingProject?: {
id: string;
name: string;
slug: string;
};
};
async function checkUrlDuplicate(url: string): Promise<DuplicateCheckResult> {
const activeTask = await prisma.projectDiscoveryTask.findFirst({
where: {
sourceUrl: url,
status: {
in: ["PENDING", "IN_PROGRESS"],
},
},
select: {
id: true,
status: true,
sourceUrl: true,
createdAt: true,
projectId: true,
},
});
if (activeTask) {
return {
url,
shouldCreate: false,
reason: `Task already exists with status ${activeTask.status}`,
existingTask: activeTask,
};
}
const finishedTask = await prisma.projectDiscoveryTask.findFirst({
where: {
sourceUrl: url,
status: {
in: ["COMPLETED", "FAILED"],
},
},
select: {
id: true,
status: true,
sourceUrl: true,
createdAt: true,
projectId: true,
},
orderBy: {
createdAt: "desc",
},
});
if (finishedTask) {
let projectInfo;
if (finishedTask.status === "COMPLETED" && finishedTask.projectId) {
const project = await prisma.project.findUnique({
where: { id: finishedTask.projectId },
select: {
id: true,
name: true,
slug: true,
},
});
if (project) {
projectInfo = project;
}
}
return {
url,
shouldCreate: false,
reason:
finishedTask.status === "COMPLETED" ? "Task already completed" : "Task already failed",
existingTask: finishedTask,
existingProject: projectInfo,
};
}
const existingLink = await prisma.externalLink.findFirst({
where: {
url,
},
select: {
project: {
select: {
id: true,
name: true,
slug: true,
},
},
},
});
if (existingLink) {
return {
url,
shouldCreate: false,
reason: "Project already exists with this URL",
existingProject: existingLink.project,
};
}
return {
url,
shouldCreate: true,
reason: "No existing task or project found",
};
}
export async function POST(request: NextRequest) {
const startTime = Date.now();
try {
const body = await request.json();
const validationResult = CheckTaskDuplicatesSchema.safeParse(body);
if (!validationResult.success) {
return NextResponse.json(
{
success: false,
error: "Validation error",
details: validationResult.error.errors.map((error) => error.message),
},
{ status: 400 }
);
}
const { apiKey, urls } = validationResult.data;
if (!isValidApiKey(apiKey)) {
return NextResponse.json(
{
success: false,
error: "Unauthorized",
details: ["Invalid or missing API Key"],
},
{ status: 401 }
);
}
const results = await Promise.all(urls.map((url) => checkUrlDuplicate(url)));
const stats = {
total: results.length,
shouldCreate: results.filter((result) => result.shouldCreate).length,
duplicate: results.filter((result) => !result.shouldCreate).length,
};
const duration = Date.now() - startTime;
console.warn(
`[CheckTaskDuplicates] Checked ${stats.total} URLs in ${duration}ms: ${stats.shouldCreate} should create, ${stats.duplicate} duplicate`
);
return NextResponse.json({
success: true,
results,
stats,
});
} catch (error) {
console.error("[CheckTaskDuplicates] Error:", error);
return NextResponse.json(
{
success: false,
error: "Internal server error",
details: [error instanceof Error ? error.message : "Unknown error"],
},
{ status: 500 }
);
}
}