import { NextRequest, NextResponse } from "next/server"; import { nanoid } from "nanoid"; import { db } from "@/lib/db"; import { claws } from "@/lib/db/schema"; import { setClawOnline, updateActiveClaws, incrementGlobalStat, incrementRegionCount, publishEvent, } from "@/lib/redis"; import { generateApiKey } from "@/lib/auth/api-key"; import { getGeoLocation } from "@/lib/geo/ip-location"; import { registerSchema } from "@/lib/validators/schemas"; function getClientIp(req: NextRequest): string { const forwarded = req.headers.get("x-forwarded-for"); if (forwarded) return forwarded.split(",")[0].trim(); const realIp = req.headers.get("x-real-ip"); if (realIp) return realIp.trim(); return "127.0.0.1"; } export async function POST(req: NextRequest) { try { const body = await req.json(); const parsed = registerSchema.safeParse(body); if (!parsed.success) { return NextResponse.json( { error: "Validation failed", details: parsed.error.flatten() }, { status: 400 } ); } const { name, model, platform } = parsed.data; const clawId = nanoid(21); const apiKey = generateApiKey(); const clientIp = getClientIp(req); const geo = await getGeoLocation(clientIp); const now = new Date(); await db.insert(claws).values({ id: clawId, apiKey, name, model: model ?? null, platform: platform ?? null, ip: clientIp, latitude: geo ? String(geo.latitude) : null, longitude: geo ? String(geo.longitude) : null, city: geo?.city ?? null, country: geo?.country ?? null, countryCode: geo?.countryCode ?? null, region: geo?.region ?? null, lastHeartbeat: now, totalTasks: 0, createdAt: now, updatedAt: now, }); await setClawOnline(clawId, clientIp); await updateActiveClaws(clawId); await incrementGlobalStat("total_claws"); if (geo?.region) { await incrementRegionCount(geo.region); } await publishEvent({ type: "online", clawId, clawName: name, city: geo?.city ?? null, country: geo?.country ?? null, }); return NextResponse.json({ clawId, apiKey, endpoint: `${process.env.NEXT_PUBLIC_APP_URL}/api/v1`, }); } catch (error) { console.error("Register error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } }