Files
OmniRoute/src/app/api/pricing/route.ts
diegosouzapw ec6456ba73 chore(release): align migration compatibility and packaged CLI runtime
Skip the superseded 041 session_account_affinity migration when
the canonical 050 file is present, and remap legacy migration
markers so upgraded databases do not replay the duplicate slot.

Also include the CLI entrypoints in packaged artifacts and extend
management-auth coverage across admin memory, pricing, routing,
provider validation, and usage endpoints to keep release bundles
runnable and sensitive operations protected.
2026-05-10 18:27:41 -03:00

106 lines
3.0 KiB
TypeScript

import { NextResponse } from "next/server";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import {
getPricing,
getPricingWithSources,
updatePricing,
resetPricing,
resetAllPricing,
} from "@/lib/localDb";
import { updatePricingSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/pricing
* Get current pricing configuration (merged user + defaults)
*/
export async function GET(request: Request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const includeSources = new URL(request.url).searchParams.get("includeSources") === "1";
if (includeSources) {
return NextResponse.json(await getPricingWithSources());
}
const pricing = await getPricing();
return NextResponse.json(pricing);
} catch (error) {
console.error("Error fetching pricing:", error);
return NextResponse.json({ error: "Failed to fetch pricing" }, { status: 500 });
}
}
/**
* PATCH /api/pricing
* Update pricing configuration
* Body: { provider: { model: { input: number, output: number, cached: number, ... } } }
*/
export async function PATCH(request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
let rawBody;
try {
rawBody = await request.json();
} catch {
return NextResponse.json(
{
error: {
message: "Invalid request",
details: [{ field: "body", message: "Invalid JSON body" }],
},
},
{ status: 400 }
);
}
try {
const validation = validateBody(updatePricingSchema, rawBody);
if (isValidationFailure(validation)) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
const body = validation.data;
const updatedPricing = await updatePricing(body);
return NextResponse.json(updatedPricing);
} catch (error) {
console.error("Error updating pricing:", error);
return NextResponse.json({ error: "Failed to update pricing" }, { status: 500 });
}
}
/**
* DELETE /api/pricing
* Reset pricing to defaults
* Query params: ?provider=xxx&model=yyy (optional)
*/
export async function DELETE(request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const { searchParams } = new URL(request.url);
const provider = searchParams.get("provider");
const model = searchParams.get("model");
if (provider && model) {
// Reset specific model
await resetPricing(provider, model);
} else if (provider) {
// Reset entire provider
await resetPricing(provider);
} else {
// Reset all pricing
await resetAllPricing();
}
const pricing = await getPricing();
return NextResponse.json(pricing);
} catch (error) {
console.error("Error resetting pricing:", error);
return NextResponse.json({ error: "Failed to reset pricing" }, { status: 500 });
}
}