Add initial project skeleton
This commit is contained in:
82
server.js
Normal file
82
server.js
Normal file
@@ -0,0 +1,82 @@
|
||||
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}`);
|
||||
});
|
||||
Reference in New Issue
Block a user