Fix Lorcana API integration and user-cards 500 error - add dual API support and database table checks

This commit is contained in:
Randall Stillwell 2025-07-22 21:54:42 -05:00
parent 29e935b680
commit d27a04e460
2 changed files with 167 additions and 11 deletions

View file

@ -12,6 +12,38 @@ export async function GET(request) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
} }
// Check if tables exist first
try {
const tableCheck = await sql.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'user_cards'
) as user_cards_exists,
EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'cards'
) as cards_exists
`);
const { user_cards_exists, cards_exists } = tableCheck.rows[0];
if (!user_cards_exists || !cards_exists) {
console.log('Tables do not exist, returning empty array');
return NextResponse.json({
success: true,
data: [],
message: 'No cards found (tables not initialized)'
});
}
} catch (error) {
console.error('Error checking table existence:', error);
return NextResponse.json({
success: true,
data: [],
message: 'Database not initialized'
});
}
const { searchParams } = new URL(request.url); const { searchParams } = new URL(request.url);
const game = searchParams.get('game'); const game = searchParams.get('game');
const rarity = searchParams.get('rarity'); const rarity = searchParams.get('rarity');

View file

@ -5,6 +5,7 @@ const SCRYFALL_BASE_URL = 'https://api.scryfall.com';
const POKEMON_API_BASE_URL = 'https://api.pokemontcg.io/v2'; const POKEMON_API_BASE_URL = 'https://api.pokemontcg.io/v2';
const YUGIOH_API_BASE_URL = 'https://db.ygoprodeck.com/api/v7'; const YUGIOH_API_BASE_URL = 'https://db.ygoprodeck.com/api/v7';
const LORCAST_API_BASE_URL = 'https://api.lorcast.com/v0'; const LORCAST_API_BASE_URL = 'https://api.lorcast.com/v0';
const LORCANA_API_BASE_URL = 'https://lorcana-api.com/api/v1';
// Rate limiting utilities // Rate limiting utilities
@ -286,7 +287,46 @@ export const lorcanaService = {
await lorcastLimiter.waitForSlot(); await lorcastLimiter.waitForSlot();
try { try {
// Try different search endpoints // Try Lorcana API first (more reliable)
try {
const response = await fetch(`${LORCANA_API_BASE_URL}/cards?search=${encodeURIComponent(query)}`);
if (response.ok) {
const data = await response.json();
const cards = data.cards || data.data || data || [];
if (cards.length > 0) {
console.log(`✅ Found ${cards.length} Lorcana cards from Lorcana API`);
return cards.map((card: any) => ({
id: card.id || card.uuid || `lorcana-${Math.random()}`,
name: card.name,
set_name: card.set?.name || card.set_name || '',
set_code: card.set?.code || card.set_code || '',
card_number: card.number || card.card_number || '',
rarity: card.rarity,
game: 'LORCANA',
mana_cost: card.cost?.toString() || card.mana_cost,
cmc: card.cost || card.cmc,
card_type: card.type || card.card_type,
colors: card.colors || [],
oracle_text: card.text || card.oracle_text || '',
power: card.strength?.toString() || card.power,
toughness: card.willpower?.toString() || card.toughness,
image_url: card.image_url || card.images?.small || card.images?.png,
stock_image_url: card.image_url || card.images?.small || card.images?.png,
current_price: card.price?.market || card.current_price || undefined,
market_price: card.price?.low || card.market_price || undefined,
verified: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}));
}
}
} catch (e) {
console.log('❌ Lorcana API failed, trying Lorcast API');
}
// Fallback to Lorcast API with multiple endpoints
const searchEndpoints = [ const searchEndpoints = [
`/cards?q=${encodeURIComponent(query)}`, `/cards?q=${encodeURIComponent(query)}`,
`/cards?search=${encodeURIComponent(query)}`, `/cards?search=${encodeURIComponent(query)}`,
@ -306,7 +346,7 @@ export const lorcanaService = {
const cards = data.cards || data.data || data || []; const cards = data.cards || data.data || data || [];
if (cards.length > 0) { if (cards.length > 0) {
console.log(`✅ Found ${cards.length} Lorcana cards from ${endpoint}`); console.log(`✅ Found ${cards.length} Lorcana cards from Lorcast ${endpoint}`);
return cards.map((card: any) => ({ return cards.map((card: any) => ({
id: card.id || card.uuid || `lorcana-${Math.random()}`, id: card.id || card.uuid || `lorcana-${Math.random()}`,
name: card.name, name: card.name,
@ -333,12 +373,12 @@ export const lorcanaService = {
} }
} }
} catch (e) { } catch (e) {
console.log(`❌ Failed to search from ${endpoint}:`, e); console.log(`❌ Failed to search from Lorcast ${endpoint}:`, e);
continue; continue;
} }
} }
console.log('⚠️ No Lorcana cards found from any search endpoint'); console.log('⚠️ No Lorcana cards found from any API');
return []; return [];
} catch (error) { } catch (error) {
console.error('Error searching Lorcana cards:', error); console.error('Error searching Lorcana cards:', error);
@ -350,7 +390,47 @@ export const lorcanaService = {
await lorcastLimiter.waitForSlot(); await lorcastLimiter.waitForSlot();
try { try {
// Try different search endpoints for exact name match // Try Lorcana API first
try {
const response = await fetch(`${LORCANA_API_BASE_URL}/cards?search=${encodeURIComponent(name)}`);
if (response.ok) {
const data = await response.json();
const cards = data.cards || data.data || data || [];
if (cards.length > 0) {
const card = cards[0];
console.log(`✅ Found Lorcana card "${name}" from Lorcana API`);
return {
id: card.id || card.uuid || `lorcana-${Math.random()}`,
name: card.name,
set_name: card.set?.name || card.set_name || '',
set_code: card.set?.code || card.set_code || '',
card_number: card.number || card.card_number || '',
rarity: card.rarity,
game: 'LORCANA',
mana_cost: card.cost?.toString() || card.mana_cost,
cmc: card.cost || card.cmc,
card_type: card.type || card.card_type,
colors: card.colors || [],
oracle_text: card.text || card.oracle_text || '',
power: card.strength?.toString() || card.power,
toughness: card.willpower?.toString() || card.toughness,
image_url: card.image_url || card.images?.small || card.images?.png,
stock_image_url: card.image_url || card.images?.small || card.images?.png,
current_price: card.price?.market || card.current_price || undefined,
market_price: card.price?.low || card.market_price || undefined,
verified: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
}
}
} catch (e) {
console.log('❌ Lorcana API failed for card lookup, trying Lorcast API');
}
// Fallback to Lorcast API
const searchEndpoints = [ const searchEndpoints = [
`/cards?q=name:${encodeURIComponent(name)}`, `/cards?q=name:${encodeURIComponent(name)}`,
`/cards?search=${encodeURIComponent(name)}`, `/cards?search=${encodeURIComponent(name)}`,
@ -371,7 +451,7 @@ export const lorcanaService = {
if (cards.length > 0) { if (cards.length > 0) {
const card = cards[0]; const card = cards[0];
console.log(`✅ Found Lorcana card "${name}" from ${endpoint}`); console.log(`✅ Found Lorcana card "${name}" from Lorcast ${endpoint}`);
return { return {
id: card.id || card.uuid || `lorcana-${Math.random()}`, id: card.id || card.uuid || `lorcana-${Math.random()}`,
name: card.name, name: card.name,
@ -398,12 +478,12 @@ export const lorcanaService = {
} }
} }
} catch (e) { } catch (e) {
console.log(`❌ Failed to fetch card from ${endpoint}:`, e); console.log(`❌ Failed to fetch card from Lorcast ${endpoint}:`, e);
continue; continue;
} }
} }
console.log(`⚠️ Lorcana card "${name}" not found from any endpoint`); console.log(`⚠️ Lorcana card "${name}" not found from any API`);
return null; return null;
} catch (error) { } catch (error) {
console.error('Error fetching Lorcana card:', error); console.error('Error fetching Lorcana card:', error);
@ -415,7 +495,51 @@ export const lorcanaService = {
await lorcastLimiter.waitForSlot(); await lorcastLimiter.waitForSlot();
try { try {
// Try different endpoints for Lorcana cards // Try Lorcana API first
try {
const response = await fetch(`${LORCANA_API_BASE_URL}/cards?limit=${count}`);
if (response.ok) {
const data = await response.json();
const allCards = data.cards || data.data || data || [];
if (allCards.length > 0) {
console.log(`✅ Found ${allCards.length} cards from Lorcana API`);
// Randomly select cards
const shuffled = allCards.sort(() => 0.5 - Math.random());
const selectedCards = shuffled.slice(0, count);
return selectedCards.map((card: any) => ({
id: card.id || card.uuid || `lorcana-${Math.random()}`,
name: card.name,
set_name: card.set?.name || card.set_name || '',
set_code: card.set?.code || card.set_code || '',
card_number: card.number || card.card_number || '',
rarity: card.rarity,
game: 'LORCANA',
mana_cost: card.cost?.toString() || card.mana_cost,
cmc: card.cost || card.cmc,
card_type: card.type || card.card_type,
colors: card.colors || [],
oracle_text: card.text || card.oracle_text || '',
power: card.strength?.toString() || card.power,
toughness: card.willpower?.toString() || card.toughness,
image_url: card.image_url || card.images?.small || card.images?.png,
stock_image_url: card.image_url || card.images?.small || card.images?.png,
current_price: card.price?.market || card.current_price || undefined,
market_price: card.price?.low || card.market_price || undefined,
verified: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}));
}
}
} catch (e) {
console.log('❌ Lorcana API failed for random cards, trying Lorcast API');
}
// Fallback to Lorcast API
const endpoints = [ const endpoints = [
'/cards', '/cards',
'/api/cards', '/api/cards',
@ -432,11 +556,11 @@ export const lorcanaService = {
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
allCards = data.cards || data.data || data || []; allCards = data.cards || data.data || data || [];
console.log(`✅ Found ${allCards.length} cards from ${endpoint}`); console.log(`✅ Found ${allCards.length} cards from Lorcast ${endpoint}`);
break; break;
} }
} catch (e) { } catch (e) {
console.log(`❌ Failed to fetch from ${endpoint}:`, e); console.log(`❌ Failed to fetch from Lorcast ${endpoint}:`, e);
continue; continue;
} }
} }