import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import path from 'path'; import { fileURLToPath } from 'url'; import fetch from 'node-fetch'; const app = express(); app.use(cors()); app.use(express.json()); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Serve static frontend app.use(express.static(path.join(__dirname, 'public'))); // (Mock data routes removed) // eBay completed (sold) listings search app.get('/api/ebay/search', async (req, res) => { try { const { player, team, manufacturer, page = 1 } = req.query; const appId = process.env.EBAY_APP_ID; if (!appId) { return res.status(500).json({ error: 'Server missing EBAY_APP_ID environment variable' }); } const name = String(player || '').trim(); if (!name) return res.status(400).json({ error: 'Missing required "player" query param' }); const keywords = [name, team, manufacturer].filter(Boolean).join(' '); const params = new URLSearchParams({ 'OPERATION-NAME': 'findCompletedItems', 'SERVICE-VERSION': '1.13.0', 'SECURITY-APPNAME': appId, 'RESPONSE-DATA-FORMAT': 'JSON', keywords, 'paginationInput.entriesPerPage': '24', 'paginationInput.pageNumber': String(page), 'sortOrder': 'EndTimeSoonest', 'outputSelector': 'PictureURLLarge' }); // item filters params.append('itemFilter(0).name', 'SoldItemsOnly'); params.append('itemFilter(0).value', 'true'); params.append('GLOBAL-ID', 'EBAY-US'); const url = `https://svcs.ebay.com/services/search/FindingService/v1?${params.toString()}`; const resp = await fetch(url); if (!resp.ok) { const text = await resp.text(); return res.status(502).json({ error: 'eBay API error', detail: text }); } const data = await resp.json(); const root = (data && data.findCompletedItemsResponse && data.findCompletedItemsResponse[0]) || {}; const items = ((root.searchResult && root.searchResult[0] && root.searchResult[0].item) || []).map((it) => { const title = it.title?.[0] || ''; const url = it.viewItemURL?.[0] || ''; const image = (it.pictureURLLarge?.[0] || it.galleryURL?.[0] || ''); const price = it.sellingStatus?.[0]?.currentPrice?.[0]?.__value__ || null; const currency = it.sellingStatus?.[0]?.currentPrice?.[0]?.['@currencyId'] || null; const ended = it.listingInfo?.[0]?.endTime?.[0] || null; return { title, url, image, price, currency, ended }; }); res.json({ results: items }); } catch (err) { console.error('eBay search error', err); res.status(500).json({ error: 'Internal server error' }); } }); // Fallback to index.html for root app.get('/', (_req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Baseball Cards Search running on http://localhost:${PORT}`); });