feat(evidence): add protected AUD0 outbox dispatch endpoint
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
import { verifyInternalServiceToken } from "@/src/auth/internal-token";
|
||||
import { createAud0Client } from "@/src/clients/aud0-client";
|
||||
import {
|
||||
Aud0OutboxDispatcher,
|
||||
createAud0OutboxRepositoryFromEnv,
|
||||
} from "@/src/evidence/aud0-outbox";
|
||||
import { siaxErrorResponse } from "@/src/http/siax-error-response";
|
||||
import { SiaxError } from "@/src/platform/errors";
|
||||
|
||||
function assertInternal(request: NextRequest): NextResponse | undefined {
|
||||
if (verifyInternalServiceToken(request.headers)) return undefined;
|
||||
return NextResponse.json(
|
||||
{ error: "UNAUTHENTICATED", message: "valid X-Internal-Token is required" },
|
||||
{ status: 401 },
|
||||
);
|
||||
}
|
||||
|
||||
function repository() {
|
||||
const repo = createAud0OutboxRepositoryFromEnv();
|
||||
if (!repo) {
|
||||
throw new SiaxError(
|
||||
"DEPENDENCY_UNAVAILABLE",
|
||||
"0pt.aud0_outbox",
|
||||
"DATABASE_URL is required for durable evidence dispatch",
|
||||
);
|
||||
}
|
||||
return repo;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const denied = assertInternal(request);
|
||||
if (denied) return denied;
|
||||
|
||||
try {
|
||||
const raw = await request.json().catch(() => ({})) as { limit?: unknown };
|
||||
const limit = raw.limit === undefined ? 100 : Number(raw.limit);
|
||||
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 500) {
|
||||
return NextResponse.json(
|
||||
{ error: "INVALID_REQUEST", message: "limit must be an integer between 1 and 500" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const repo = repository();
|
||||
const dispatcher = new Aud0OutboxDispatcher(repo, createAud0Client());
|
||||
const result = await dispatcher.sweep(limit);
|
||||
const stats = await repo.stats();
|
||||
return NextResponse.json({ result, stats });
|
||||
} catch (error: unknown) {
|
||||
return siaxErrorResponse(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const denied = assertInternal(request);
|
||||
if (denied) return denied;
|
||||
|
||||
try {
|
||||
return NextResponse.json(await repository().stats());
|
||||
} catch (error: unknown) {
|
||||
return siaxErrorResponse(error);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user