import { NextRequest, NextResponse } from "next/server"; import { asJson } from "@/lib/arma-bridge/json"; import { requireArmaServer } from "@/lib/arma-bridge/server"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; interface IncomingEvent { eventId: string; server: number; type: string; occurredAt: string; payload: ReturnType; } export async function POST(req: NextRequest) { const auth = await requireArmaServer(req); if (auth instanceof NextResponse) return auth; const { payload, server } = auth; const body = (await req.json().catch(() => null)) as { events?: unknown[] } | null; if (!body?.events || !Array.isArray(body.events) || body.events.length > 100) { return NextResponse.json( { error: "events must be an array containing at most 100 entries." }, { status: 400 }, ); } // Validate + normalize; entries missing a string id or type are rejected. const valid: IncomingEvent[] = []; let rejected = 0; for (const rawEvent of body.events) { const event = rawEvent as Record; if (!event || typeof event.id !== "string" || typeof event.type !== "string") { rejected++; continue; } valid.push({ eventId: `${server.serverId}:${event.id}`, server: server.id, type: event.type, occurredAt: typeof event.occurredAt === "string" ? event.occurredAt : new Date().toISOString(), payload: asJson(event.payload), }); } // One batched lookup for events that already exist (idempotency by eventId). const existing = valid.length ? await payload.find({ collection: "arma-sync-events", where: { eventId: { in: valid.map((event) => event.eventId) } }, limit: valid.length, overrideAccess: true, }) : { docs: [] }; const seen = new Set(existing.docs.map((doc) => doc.eventId)); let accepted = 0; let duplicates = 0; for (const event of valid) { // Also catches the same id repeated within this batch. if (seen.has(event.eventId)) { duplicates++; continue; } try { await payload.create({ collection: "arma-sync-events", data: event, overrideAccess: true }); seen.add(event.eventId); accepted++; } catch (error) { const message = error instanceof Error ? error.message : String(error); if (/duplicate key|unique constraint/i.test(message)) { // Unique-constraint race with a concurrent request — already stored. duplicates++; } else { throw error; } } } return NextResponse.json({ ok: true, accepted, duplicates, rejected }); }