120 lines
3 KiB
TypeScript
120 lines
3 KiB
TypeScript
import { NextResponse } from "next/server"
|
|
import { fetchQuery } from "convex/nextjs"
|
|
import { api } from "@/convex/_generated/api"
|
|
import { hasConvexUrl } from "@/lib/convex-config"
|
|
import {
|
|
filterTrustedEbayListings,
|
|
rankListingsForQuery,
|
|
type CachedEbayListing,
|
|
type EbayCacheState,
|
|
} from "@/lib/ebay-parts-match"
|
|
|
|
type CacheSource = "convex" | "fallback"
|
|
|
|
function getDisabledCacheState(message: string): EbayCacheState {
|
|
return {
|
|
key: "manual-parts",
|
|
status: "disabled",
|
|
lastSuccessfulAt: null,
|
|
lastAttemptAt: null,
|
|
nextEligibleAt: null,
|
|
lastError: message,
|
|
consecutiveFailures: 0,
|
|
queryCount: 0,
|
|
itemCount: 0,
|
|
sourceQueries: [],
|
|
freshnessMs: null,
|
|
isStale: true,
|
|
listingCount: 0,
|
|
activeListingCount: 0,
|
|
message,
|
|
}
|
|
}
|
|
|
|
function getErrorCacheState(message: string): EbayCacheState {
|
|
const now = Date.now()
|
|
return {
|
|
key: "manual-parts",
|
|
status: "error",
|
|
lastSuccessfulAt: null,
|
|
lastAttemptAt: now,
|
|
nextEligibleAt: null,
|
|
lastError: message,
|
|
consecutiveFailures: 1,
|
|
queryCount: 0,
|
|
itemCount: 0,
|
|
sourceQueries: [],
|
|
freshnessMs: null,
|
|
isStale: true,
|
|
listingCount: 0,
|
|
activeListingCount: 0,
|
|
message,
|
|
}
|
|
}
|
|
|
|
export async function GET(request: Request) {
|
|
const { searchParams } = new URL(request.url)
|
|
const keywords = searchParams.get("keywords")?.trim() || ""
|
|
const maxResults = Math.min(
|
|
Math.max(Number.parseInt(searchParams.get("maxResults") || "6", 10) || 6, 1),
|
|
20
|
|
)
|
|
|
|
if (!keywords) {
|
|
return NextResponse.json(
|
|
{ error: "Keywords parameter is required" },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
if (!hasConvexUrl()) {
|
|
const message =
|
|
"Cached eBay backend is disabled because NEXT_PUBLIC_CONVEX_URL is not configured."
|
|
return NextResponse.json({
|
|
query: keywords,
|
|
results: [],
|
|
cache: getDisabledCacheState(message),
|
|
cacheSource: "fallback" satisfies CacheSource,
|
|
error: message,
|
|
})
|
|
}
|
|
|
|
try {
|
|
const [overview, listings] = await Promise.all([
|
|
fetchQuery(api.ebay.getCacheOverview, {}),
|
|
fetchQuery(api.ebay.listCachedListings, { limit: 200 }),
|
|
])
|
|
|
|
const trustedListings = filterTrustedEbayListings(
|
|
listings as CachedEbayListing[]
|
|
)
|
|
const ranked = rankListingsForQuery(
|
|
keywords,
|
|
trustedListings,
|
|
maxResults
|
|
)
|
|
|
|
return NextResponse.json({
|
|
query: keywords,
|
|
results: ranked,
|
|
cache: overview,
|
|
cacheSource: "convex" satisfies CacheSource,
|
|
})
|
|
} catch (error) {
|
|
console.error("Failed to load cached eBay listings:", error)
|
|
const message =
|
|
error instanceof Error
|
|
? `Cached eBay listings are unavailable: ${error.message}`
|
|
: "Cached eBay listings are unavailable."
|
|
return NextResponse.json(
|
|
{
|
|
query: keywords,
|
|
results: [],
|
|
cache: getErrorCacheState(message),
|
|
cacheSource: "fallback" satisfies CacheSource,
|
|
error: message,
|
|
},
|
|
{ status: 200 }
|
|
)
|
|
}
|
|
}
|