import { NextRequest, NextResponse } from "next/server" import { computeEbayChallengeResponse, getEbayNotificationEndpoint, getEbayNotificationVerificationToken, verifyEbayNotificationSignature, } from "@/lib/ebay-notifications" export const runtime = "nodejs" type EbayNotificationPayload = { metadata?: { topic?: string schemaVersion?: string deprecated?: boolean } notification?: { notificationId?: string eventDate?: string publishDate?: string publishAttemptCount?: number data?: { username?: string userId?: string eiasToken?: string } } } function parseNotificationBody(rawBody: string) { if (!rawBody.trim()) { return null } try { return JSON.parse(rawBody) as EbayNotificationPayload } catch { return null } } function getChallengeCode(request: NextRequest) { return ( request.nextUrl.searchParams.get("challenge_code") || request.nextUrl.searchParams.get("challengeCode") || "" ).trim() } export async function GET(request: NextRequest) { const challengeCode = getChallengeCode(request) if (!challengeCode) { return NextResponse.json( { error: "Missing challenge_code query parameter." }, { status: 400 } ) } const verificationToken = getEbayNotificationVerificationToken() if (!verificationToken) { return NextResponse.json( { error: "EBAY_NOTIFICATION_VERIFICATION_TOKEN is not configured." }, { status: 500 } ) } const endpoint = getEbayNotificationEndpoint(request.url) if (!endpoint) { return NextResponse.json( { error: "EBAY_NOTIFICATION_ENDPOINT is not configured." }, { status: 500 } ) } const challengeResponse = computeEbayChallengeResponse({ challengeCode, endpoint, verificationToken, }) return NextResponse.json( { challengeResponse }, { headers: { "Cache-Control": "no-store", }, } ) } export async function POST(request: NextRequest) { const body = await request.text() const signatureHeader = request.headers.get("x-ebay-signature") try { const verification = await verifyEbayNotificationSignature({ body, signatureHeader, }) if (!verification.verified) { if ( verification.reason === "Notification verification credentials are not configured." ) { console.warn( "[ebay/notifications] accepted notification without signature verification", { reason: verification.reason, } ) const payload = parseNotificationBody(body) const notification = payload?.notification console.info( "[ebay/notifications] accepted notification without verification", { topic: payload?.metadata?.topic || "unknown", notificationId: notification?.notificationId || "unknown", publishAttemptCount: notification?.publishAttemptCount ?? null, } ) return new NextResponse(null, { status: 204 }) } console.warn("[ebay/notifications] signature rejected", { reason: verification.reason, }) return NextResponse.json({ error: verification.reason }, { status: 412 }) } const payload = parseNotificationBody(body) const notification = payload?.notification console.info("[ebay/notifications] accepted notification", { keyId: verification.keyId, topic: payload?.metadata?.topic || "unknown", notificationId: notification?.notificationId || "unknown", publishAttemptCount: notification?.publishAttemptCount ?? null, }) return new NextResponse(null, { status: 204 }) } catch (error) { console.error("[ebay/notifications] failed to process notification", { error: error instanceof Error ? error.message : String(error), }) return NextResponse.json( { error: error instanceof Error ? error.message : "Failed to verify eBay notification.", }, { status: 500 } ) } }