Download src/app/api/tools/route.ts from T2T-AI-X/copilot_work_3: direct link, hf CLI and curl.
- Browser
- Download file 3.03 kB
-
https://huggingface.co/T2T-AI-X/copilot_work_3/resolve/refs%2Fpr%2F4/src/app/api/tools/route.ts
- Command line
-
hf download hf://T2T-AI-X/copilot_work_3@refs/pr/4/src/app/api/tools/route.ts
-
curl -L -o route.ts https://huggingface.co/T2T-AI-X/copilot_work_3/resolve/refs%2Fpr%2F4/src/app/api/tools/route.ts
3.03 kB
| import { NextResponse } from "next/server"; | |
| import { z } from "zod"; | |
| import { categories } from "@/lib/tool-types"; | |
| import { parseGithubRepoUrl, verifyRepo } from "@/lib/github"; | |
| import { checkRateLimit, getClientIp, rateLimitResponse } from "@/lib/rate-limit"; | |
| import { DuplicateRepoError, submitTool } from "@/lib/tools"; | |
| const SUBMISSIONS_PER_HOUR = 3; | |
| const githubRepoUrl = z | |
| .string() | |
| .url() | |
| .refine((value) => parseGithubRepoUrl(value) !== undefined, "Enter a public GitHub repository URL."); | |
| const optionalWebsiteUrl = z | |
| .union([z.literal(""), z.string().url()]) | |
| .refine((value) => { | |
| if (!value) return true; | |
| const url = new URL(value); | |
| return url.protocol === "https:" && !url.username && !url.password; | |
| }, "Website must be a public HTTPS URL."); | |
| const submissionSchema = z.object({ | |
| name: z.string().trim().min(2).max(80), | |
| summary: z.string().trim().min(20).max(300), | |
| category: z.enum(categories), | |
| repoUrl: githubRepoUrl, | |
| websiteUrl: optionalWebsiteUrl, | |
| submittedBy: z.string().trim().min(2).max(60), | |
| }); | |
| export async function POST(request: Request) { | |
| const limit = checkRateLimit(`tools:${getClientIp(request)}`, SUBMISSIONS_PER_HOUR, 60 * 60 * 1000); | |
| if (!limit.allowed) return rateLimitResponse(limit); | |
| let body: unknown; | |
| try { | |
| body = await request.json(); | |
| } catch { | |
| return NextResponse.json({ error: "Request body must be valid JSON." }, { status: 400 }); | |
| } | |
| const parsed = submissionSchema.safeParse(body); | |
| if (!parsed.success) { | |
| return NextResponse.json( | |
| { error: "Please review the submission fields and try again.", fields: parsed.error.flatten().fieldErrors }, | |
| { status: 400 }, | |
| ); | |
| } | |
| const repo = parseGithubRepoUrl(parsed.data.repoUrl); | |
| if (!repo) { | |
| return NextResponse.json({ error: "Enter a public GitHub repository URL." }, { status: 400 }); | |
| } | |
| // A failed lookup (rate limit, timeout) must not block the submission: it stays | |
| // pending and a moderator checks it. Only a definite "not found" is rejected. | |
| const verification = await verifyRepo(repo); | |
| if (verification.status === "not_found") { | |
| return NextResponse.json( | |
| { | |
| error: "That GitHub repository could not be found. Make sure it exists and is public.", | |
| fields: { repoUrl: ["That GitHub repository could not be found. Make sure it exists and is public."] }, | |
| }, | |
| { status: 422 }, | |
| ); | |
| } | |
| try { | |
| await submitTool(parsed.data); | |
| return NextResponse.json( | |
| { status: "pending", message: "Thanks! Your submission is awaiting review." }, | |
| { status: 201 }, | |
| ); | |
| } catch (error) { | |
| if (error instanceof DuplicateRepoError) { | |
| return NextResponse.json( | |
| { | |
| error: error.message, | |
| fields: { repoUrl: [error.message] }, | |
| }, | |
| { status: 409 }, | |
| ); | |
| } | |
| console.error("Tool submission failed", error); | |
| return NextResponse.json( | |
| { error: "The tool could not be saved. Please try again later." }, | |
| { status: 500 }, | |
| ); | |
| } | |
| } | |