← back to Govarbitrage
src/app/api/listings/route.ts
53 lines
import { NextRequest, NextResponse } from "next/server";
import { queryListings, type ListingRow, type QueryParams } from "@/lib/listings";
import { getCurrentTier } from "@/lib/current-user";
import { tierDef } from "@/lib/tiers";
export const dynamic = "force-dynamic";
// Money-math fields the FREE tier does NOT see — the arbitrage intelligence a
// reseller pays for (recommended max bid, ROI, valuations, opportunity scores).
const PAID_FIELDS: (keyof ListingRow)[] = [
"recommendedMaxBid", "retailLow", "retailAverage", "retailHigh",
"usedLow", "usedAverage", "usedHigh", "wholesale", "liquidation", "sellNow",
"value7Day", "value30Day", "value90Day", "expectedSale", "netProfit", "roi",
"opportunityScore", "arbitrageScore", "demandScore", "velocityScore",
"logisticsScore", "conditionScore", "competitionScore", "buyerScore",
];
export async function GET(req: NextRequest) {
const sp = req.nextUrl.searchParams;
const params: QueryParams = {
search: sp.get("search") || undefined,
source: sp.get("source") || undefined,
category: sp.get("category") || undefined,
condition: sp.get("condition") || undefined,
risk: sp.get("risk") || undefined,
closingWithinHours: sp.get("closingWithinHours")
? Number(sp.get("closingWithinHours"))
: undefined,
sort: (sp.get("sort") as keyof ListingRow) || undefined,
dir: (sp.get("dir") as "asc" | "desc") || undefined,
page: sp.get("page") ? Number(sp.get("page")) : undefined,
pageSize: sp.get("pageSize") ? Number(sp.get("pageSize")) : undefined,
profile: sp.get("profile") || undefined,
};
const tier = await getCurrentTier();
const limits = tierDef(tier).limits;
// Enforce the tier's listing cap.
const capped = { ...params, pageSize: Math.min(params.pageSize ?? 50, limits.maxListings) };
const result = await queryListings(capped);
// FREE tier: redact the money-math (they see the catalog, not the intelligence).
if (!limits.showMoneyMath) {
result.rows = result.rows.map((r) => {
const row: Record<string, unknown> = { ...r };
for (const f of PAID_FIELDS) row[f] = null;
return row as unknown as ListingRow;
});
}
return NextResponse.json({ ...result, tier, gated: !limits.showMoneyMath });
}