Fix API connection and Lorcana API issues - update API base URL to Vercel deployment and improve Lorcana API resilience

This commit is contained in:
Randall Stillwell 2025-07-22 21:48:45 -05:00
parent 40928bbbda
commit 29e935b680
2 changed files with 146 additions and 88 deletions

View file

@ -286,41 +286,62 @@ export const lorcanaService = {
await lorcastLimiter.waitForSlot(); await lorcastLimiter.waitForSlot();
try { try {
const response = await fetch( // Try different search endpoints
`${LORCAST_API_BASE_URL}/cards?q=${encodeURIComponent(query)}` 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)}`
];
if (!response.ok) { for (const endpoint of searchEndpoints) {
throw new Error(`Lorcast API error: ${response.status}`); 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) {
console.log(`✅ Found ${cards.length} Lorcana cards from ${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 ${endpoint}:`, e);
continue;
}
} }
const data = await response.json(); console.log('⚠️ No Lorcana cards found from any search endpoint');
return [];
return data.cards.map((card: any) => ({
id: card.id,
name: card.name,
set_name: card.set?.name || '',
set_code: card.set?.code || '',
card_number: card.number,
rarity: card.rarity,
game: 'LORCANA',
mana_cost: card.cost?.toString(),
cmc: card.cost,
card_type: card.type,
colors: card.colors || [],
oracle_text: card.text || '',
power: card.strength?.toString(),
toughness: card.willpower?.toString(),
image_url: card.image_url,
stock_image_url: card.image_url,
current_price: card.price?.market || undefined,
market_price: card.price?.low || undefined,
verified: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}));
} catch (error) { } catch (error) {
console.error('Error fetching Lorcana cards:', error); console.error('Error searching Lorcana cards:', error);
return []; return [];
} }
}, },
@ -329,45 +350,61 @@ export const lorcanaService = {
await lorcastLimiter.waitForSlot(); await lorcastLimiter.waitForSlot();
try { try {
const response = await fetch( // Try different search endpoints for exact name match
`${LORCAST_API_BASE_URL}/cards?q=name:${encodeURIComponent(name)}` 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)}`
];
if (!response.ok) { for (const endpoint of searchEndpoints) {
return null; 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 ${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 ${endpoint}:`, e);
continue;
}
} }
const data = await response.json(); console.log(`⚠️ Lorcana card "${name}" not found from any endpoint`);
return null;
if (data.cards.length === 0) {
return null;
}
const card = data.cards[0];
return {
id: card.id,
name: card.name,
set_name: card.set?.name || '',
set_code: card.set?.code || '',
card_number: card.number,
rarity: card.rarity,
game: 'LORCANA',
mana_cost: card.cost?.toString(),
cmc: card.cost,
card_type: card.type,
colors: card.colors || [],
oracle_text: card.text || '',
power: card.strength?.toString(),
toughness: card.willpower?.toString(),
image_url: card.image_url,
stock_image_url: card.image_url,
current_price: card.price?.market || undefined,
market_price: card.price?.low || undefined,
verified: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
} catch (error) { } catch (error) {
console.error('Error fetching Lorcana card:', error); console.error('Error fetching Lorcana card:', error);
return null; return null;
@ -378,39 +415,60 @@ export const lorcanaService = {
await lorcastLimiter.waitForSlot(); await lorcastLimiter.waitForSlot();
try { try {
// Get all cards and randomly select // Try different endpoints for Lorcana cards
const response = await fetch(`${LORCAST_API_BASE_URL}/cards`); const endpoints = [
'/cards',
'/api/cards',
'/v0/cards',
'/api/v0/cards'
];
if (!response.ok) { let allCards: any[] = [];
throw new Error(`Lorcast API error: ${response.status}`);
for (const endpoint of endpoints) {
try {
const response = await fetch(`${LORCAST_API_BASE_URL}${endpoint}`);
if (response.ok) {
const data = await response.json();
allCards = data.cards || data.data || data || [];
console.log(`✅ Found ${allCards.length} cards from ${endpoint}`);
break;
}
} catch (e) {
console.log(`❌ Failed to fetch from ${endpoint}:`, e);
continue;
}
} }
const data = await response.json(); if (allCards.length === 0) {
const allCards = data.cards || []; console.log('⚠️ No cards found from any endpoint, returning empty array');
return [];
}
// Randomly select cards // Randomly select cards
const shuffled = allCards.sort(() => 0.5 - Math.random()); const shuffled = allCards.sort(() => 0.5 - Math.random());
const selectedCards = shuffled.slice(0, count); const selectedCards = shuffled.slice(0, count);
return selectedCards.map((card: any) => ({ return selectedCards.map((card: any) => ({
id: card.id, id: card.id || card.uuid || `lorcana-${Math.random()}`,
name: card.name, name: card.name,
set_name: card.set?.name || '', set_name: card.set?.name || card.set_name || '',
set_code: card.set?.code || '', set_code: card.set?.code || card.set_code || '',
card_number: card.number, card_number: card.number || card.card_number || '',
rarity: card.rarity, rarity: card.rarity,
game: 'LORCANA', game: 'LORCANA',
mana_cost: card.cost?.toString(), mana_cost: card.cost?.toString() || card.mana_cost,
cmc: card.cost, cmc: card.cost || card.cmc,
card_type: card.type, card_type: card.type || card.card_type,
colors: card.colors || [], colors: card.colors || [],
oracle_text: card.text || '', oracle_text: card.text || card.oracle_text || '',
power: card.strength?.toString(), power: card.strength?.toString() || card.power,
toughness: card.willpower?.toString(), toughness: card.willpower?.toString() || card.toughness,
image_url: card.image_url, image_url: card.image_url || card.images?.small || card.images?.png,
stock_image_url: card.image_url, stock_image_url: card.image_url || card.images?.small || card.images?.png,
current_price: card.price?.market || undefined, current_price: card.price?.market || card.current_price || undefined,
market_price: card.price?.low || undefined, market_price: card.price?.low || card.market_price || undefined,
verified: true, verified: true,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),

View file

@ -15,7 +15,7 @@ import type {
UserStats, UserStats,
} from '../types'; } from '../types';
const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000'; const API_BASE_URL = process.env.REACT_APP_API_URL || 'https://tcg-vault.vercel.app';
// Create axios instance with default config // Create axios instance with default config
const api = axios.create({ const api = axios.create({