deckhearth/api/v1/cards/index.ts
Randall Stillwell 6b81ed38b0 🚀 TCG Vault - Complete All-Vercel Setup
 Features:
- Camera OCR card scanning with Tesseract.js
- Beautiful glowing card effects and animations
- Intelligent card matching and recognition
- Mobile-responsive design with Tailwind CSS

🏗️ Architecture:
- Frontend: React TypeScript application
- Backend: Vercel Functions (replacing FastAPI)
- Database: JSON file with exported card data
- Deployment: Single Vercel project

📁 Structure:
- api/ - Vercel Functions backend endpoints
- src/ - React frontend components and logic
- src/data/cards.json - Card database (12 cards)
- vercel.json - Optimized Vercel configuration

💰 Cost: /bin/zsh additional (uses existing Vercel Pro)
🚀 Ready for immediate Vercel deployment
2025-07-21 13:53:06 -05:00

95 lines
2.4 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import cardsData from '../../../src/data/cards.json'
interface Card {
id: number
name: string
set_name?: string
set_code?: string
card_number?: string
rarity?: string
game: string
mana_cost?: string
cmc?: number
card_type?: string
colors?: string[]
oracle_text?: string
flavor_text?: string
power?: string
toughness?: string
artist?: string
image_url?: string
stock_image_url?: string
artwork_crop_coords?: any
current_price?: number
market_price?: number
verified: boolean
created_at?: string
updated_at?: string
}
export default async function handler(req: NextRequest) {
// Enable CORS
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
}
if (req.method === 'OPTIONS') {
return new NextResponse(null, { status: 200, headers })
}
try {
const url = new URL(req.url)
const searchParams = url.searchParams
// Get query parameters
const skip = parseInt(searchParams.get('skip') || '0')
const limit = parseInt(searchParams.get('limit') || '100')
const search = searchParams.get('search')
const game = searchParams.get('game')
const set_name = searchParams.get('set_name')
let cards: Card[] = cardsData as Card[]
// Apply filters
if (game) {
cards = cards.filter(card => card.game === game)
}
if (set_name) {
cards = cards.filter(card => card.set_name === set_name)
}
if (search) {
const searchLower = search.toLowerCase()
cards = cards.filter(card =>
card.name.toLowerCase().includes(searchLower) ||
(card.oracle_text && card.oracle_text.toLowerCase().includes(searchLower)) ||
(card.card_type && card.card_type.toLowerCase().includes(searchLower))
)
}
// Apply pagination
const paginatedCards = cards.slice(skip, skip + limit)
return new NextResponse(JSON.stringify(paginatedCards), {
status: 200,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
} catch (error) {
console.error('API Error:', error)
return new NextResponse(JSON.stringify({ error: 'Internal server error' }), {
status: 500,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
}
}