57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { sql } from "drizzle-orm";
|
|
import { db } from "@/lib/db";
|
|
import { invalidateTokenLeaderboardCache } from "@/lib/redis";
|
|
import { authenticateRequest } from "@/lib/auth/request";
|
|
import { getTodayDateString } from "@/lib/utils";
|
|
import { tokenSchema } from "@/lib/validators/schemas";
|
|
|
|
export async function POST(req: NextRequest) {
|
|
try {
|
|
const auth = await authenticateRequest(req);
|
|
if (auth instanceof NextResponse) {
|
|
return auth;
|
|
}
|
|
const { claw } = auth;
|
|
|
|
const body = await req.json();
|
|
const parsed = tokenSchema.safeParse(body);
|
|
if (!parsed.success) {
|
|
return NextResponse.json(
|
|
{ error: "Validation failed", details: parsed.error.flatten() },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const { inputTokens, outputTokens, date } = parsed.data;
|
|
const targetDate = date || getTodayDateString();
|
|
|
|
// Use UPSERT (INSERT ... ON DUPLICATE KEY UPDATE) for atomic operation
|
|
await db.execute(sql`
|
|
INSERT INTO token_usage (claw_id, date, input_tokens, output_tokens)
|
|
VALUES (${claw.id}, ${targetDate}, ${inputTokens}, ${outputTokens})
|
|
ON DUPLICATE KEY UPDATE
|
|
input_tokens = ${inputTokens},
|
|
output_tokens = ${outputTokens},
|
|
updated_at = NOW()
|
|
`);
|
|
|
|
// Invalidate leaderboard cache
|
|
await invalidateTokenLeaderboardCache();
|
|
|
|
return NextResponse.json({
|
|
ok: true,
|
|
date: targetDate,
|
|
inputTokens,
|
|
outputTokens,
|
|
totalTokens: inputTokens + outputTokens,
|
|
});
|
|
} catch (error) {
|
|
console.error("Token report error:", error);
|
|
return NextResponse.json(
|
|
{ error: "Internal server error" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|