feat(api): Agent-API mit Enrollment, Report und Ping (#004)

Gehashte Tokens mit Praefix, Rate-Limit je IP und Token, zod-Validierung mit
durchgaengig optionalen Feldern, idempotente Reports ueber reportId, Key- und
Server-ID-Historie sowie automatischer Laufzeit-Vorschlag. 32 Tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-17 20:39:33 +02:00
co-authored by Claude Opus 5
parent 51c8aafa69
commit bef51eb863
19 changed files with 1209 additions and 30 deletions
+15 -7
View File
@@ -2,8 +2,10 @@ import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "@/generated/prisma/client";
/**
* Prisma-Client als Singleton. Im Entwicklungsmodus lädt Next.js Module neu,
* ohne den Prozess zu beenden – ohne Singleton entstünden dabei immer neue Verbindungspools.
* Prisma-Client als Singleton, der erst beim ersten Zugriff verbindet.
* Das ist wichtig, weil Next.js beim Bauen Module lädt, ohne dass `DATABASE_URL` gesetzt sein muss.
* Im Entwicklungsmodus verhindert der globale Zwischenspeicher, dass jeder Hot-Reload
* einen neuen Verbindungspool öffnet.
*/
declare global {
var proxledgerPrisma: PrismaClient | undefined;
@@ -14,11 +16,17 @@ function erzeugeClient(): PrismaClient {
if (!connectionString) {
throw new Error("DATABASE_URL ist nicht gesetzt. Beispielwerte stehen in .env.example.");
}
return new PrismaClient({ adapter: new PrismaPg({ connectionString }) });
const client = new PrismaClient({ adapter: new PrismaPg({ connectionString }) });
if (process.env.NODE_ENV !== "production") globalThis.proxledgerPrisma = client;
return client;
}
export const prisma: PrismaClient = globalThis.proxledgerPrisma ?? erzeugeClient();
if (process.env.NODE_ENV !== "production") {
globalThis.proxledgerPrisma = prisma;
export function getPrisma(): PrismaClient {
return globalThis.proxledgerPrisma ?? erzeugeClient();
}
export const prisma: PrismaClient = new Proxy({} as PrismaClient, {
get(_ziel, eigenschaft, empfaenger) {
return Reflect.get(getPrisma(), eigenschaft, empfaenger);
},
});