Fix Lorcana API integration and user-cards 500 error - add dual API support and database table checks
This commit is contained in:
parent
29e935b680
commit
d27a04e460
2 changed files with 167 additions and 11 deletions
|
|
@ -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');
|
||||||
|
|
|
||||||
|
|
@ -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,27 +287,16 @@ export const lorcanaService = {
|
||||||
await lorcastLimiter.waitForSlot();
|
await lorcastLimiter.waitForSlot();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try different search endpoints
|
// Try Lorcana API first (more reliable)
|
||||||
const searchEndpoints = [
|
|
||||||
`/cards?q=${encodeURIComponent(query)}`,
|
|
||||||
`/cards?search=${encodeURIComponent(query)}`,
|
|
||||||
`/cards?query=${encodeURIComponent(query)}`,
|
|
||||||
`/api/cards?q=${encodeURIComponent(query)}`,
|
|
||||||
`/api/cards?search=${encodeURIComponent(query)}`,
|
|
||||||
`/v0/cards?q=${encodeURIComponent(query)}`,
|
|
||||||
`/v0/cards?search=${encodeURIComponent(query)}`
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const endpoint of searchEndpoints) {
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${LORCAST_API_BASE_URL}${endpoint}`);
|
const response = await fetch(`${LORCANA_API_BASE_URL}/cards?search=${encodeURIComponent(query)}`);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
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 Lorcana API`);
|
||||||
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,45 +323,84 @@ export const lorcanaService = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`❌ Failed to search from ${endpoint}:`, e);
|
console.log('❌ Lorcana API failed, trying Lorcast API');
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('⚠️ No Lorcana cards found from any search endpoint');
|
// Fallback to Lorcast API with multiple endpoints
|
||||||
return [];
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error searching Lorcana cards:', error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getCardByName(name: string): Promise<Card | null> {
|
|
||||||
await lorcastLimiter.waitForSlot();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Try different search endpoints for exact name match
|
|
||||||
const searchEndpoints = [
|
const searchEndpoints = [
|
||||||
`/cards?q=name:${encodeURIComponent(name)}`,
|
`/cards?q=${encodeURIComponent(query)}`,
|
||||||
`/cards?search=${encodeURIComponent(name)}`,
|
`/cards?search=${encodeURIComponent(query)}`,
|
||||||
`/cards?query=${encodeURIComponent(name)}`,
|
`/cards?query=${encodeURIComponent(query)}`,
|
||||||
`/api/cards?q=name:${encodeURIComponent(name)}`,
|
`/api/cards?q=${encodeURIComponent(query)}`,
|
||||||
`/api/cards?search=${encodeURIComponent(name)}`,
|
`/api/cards?search=${encodeURIComponent(query)}`,
|
||||||
`/v0/cards?q=name:${encodeURIComponent(name)}`,
|
`/v0/cards?q=${encodeURIComponent(query)}`,
|
||||||
`/v0/cards?search=${encodeURIComponent(name)}`
|
`/v0/cards?search=${encodeURIComponent(query)}`
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const endpoint of searchEndpoints) {
|
for (const endpoint of searchEndpoints) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${LORCAST_API_BASE_URL}${endpoint}`);
|
const response = await fetch(`${LORCAST_API_BASE_URL}${endpoint}`);
|
||||||
|
|
||||||
|
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 Lorcast ${endpoint}`);
|
||||||
|
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(`❌ Failed to search from Lorcast ${endpoint}:`, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('⚠️ No Lorcana cards found from any API');
|
||||||
|
return [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error searching Lorcana cards:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getCardByName(name: string): Promise<Card | null> {
|
||||||
|
await lorcastLimiter.waitForSlot();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try Lorcana API first
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${LORCANA_API_BASE_URL}/cards?search=${encodeURIComponent(name)}`);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const cards = data.cards || data.data || data || [];
|
const cards = data.cards || data.data || data || [];
|
||||||
|
|
||||||
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 Lorcana API`);
|
||||||
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 +427,63 @@ export const lorcanaService = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`❌ Failed to fetch card from ${endpoint}:`, e);
|
console.log('❌ Lorcana API failed for card lookup, trying Lorcast API');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to Lorcast API
|
||||||
|
const searchEndpoints = [
|
||||||
|
`/cards?q=name:${encodeURIComponent(name)}`,
|
||||||
|
`/cards?search=${encodeURIComponent(name)}`,
|
||||||
|
`/cards?query=${encodeURIComponent(name)}`,
|
||||||
|
`/api/cards?q=name:${encodeURIComponent(name)}`,
|
||||||
|
`/api/cards?search=${encodeURIComponent(name)}`,
|
||||||
|
`/v0/cards?q=name:${encodeURIComponent(name)}`,
|
||||||
|
`/v0/cards?search=${encodeURIComponent(name)}`
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const endpoint of searchEndpoints) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${LORCAST_API_BASE_URL}${endpoint}`);
|
||||||
|
|
||||||
|
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 Lorcast ${endpoint}`);
|
||||||
|
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(`❌ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue