diff --git a/src/api/wrenClient.ts b/src/api/wrenClient.ts index 16418d7..2d86f46 100644 --- a/src/api/wrenClient.ts +++ b/src/api/wrenClient.ts @@ -108,19 +108,39 @@ const logError = (error: unknown) => { }; export async function getPortfolios(): Promise { + const startTime = Date.now(); + console.log('🔵 [WREN API] ========================================'); + console.log('🔵 [WREN API] GET /portfolios - Request initiated'); + console.log('🔵 [WREN API] Timestamp:', new Date().toISOString()); + try { if (!config.wrenApiKey) { + console.warn('⚠️ [WREN API] No API token configured, using fallback portfolio'); logger.warn('[wrenClient] No Wren API token configured, using fallback portfolio'); return [DEFAULT_PORTFOLIO]; } + console.log('🔵 [WREN API] API Key:', config.wrenApiKey ? '********' + config.wrenApiKey.slice(-4) : 'MISSING'); logger.log('[wrenClient] Getting portfolios with token:', config.wrenApiKey ? '********' + config.wrenApiKey.slice(-4) : 'MISSING'); const api = createApiClient(); - // Removed the /api prefix to match the working example + console.log('🔵 [WREN API] Making request to: https://www.wren.co/api/portfolios'); + const response = await api.get('/portfolios'); + const duration = Date.now() - startTime; + + console.log('✅ [WREN API] GET /portfolios - Success'); + console.log('✅ [WREN API] Status:', response.status); + console.log('✅ [WREN API] Duration:', duration + 'ms'); + console.log('✅ [WREN API] Portfolios returned:', response.data?.portfolios?.length || 0); + + if (response.data?.portfolios?.length > 0) { + console.log('✅ [WREN API] Portfolio IDs:', response.data.portfolios.map((p: any) => `#${p.id} (${p.name})`).join(', ')); + } + console.log('🔵 [WREN API] ========================================'); if (!response.data?.portfolios?.length) { + console.warn('⚠️ [WREN API] No portfolios in response, using fallback'); logger.warn('[wrenClient] No portfolios returned from API, using fallback'); return [DEFAULT_PORTFOLIO]; } @@ -180,6 +200,20 @@ export async function getPortfolios(): Promise { }; }); } catch (error) { + const duration = Date.now() - startTime; + console.error('❌ [WREN API] GET /portfolios - Failed'); + console.error('❌ [WREN API] Duration:', duration + 'ms'); + + if (axios.isAxiosError(error)) { + console.error('❌ [WREN API] Status:', error.response?.status || 'No response'); + console.error('❌ [WREN API] Status Text:', error.response?.statusText || 'N/A'); + console.error('❌ [WREN API] Error Data:', JSON.stringify(error.response?.data, null, 2)); + console.error('❌ [WREN API] Request URL:', error.config?.url); + } else { + console.error('❌ [WREN API] Error:', error instanceof Error ? error.message : String(error)); + } + console.log('🔵 [WREN API] ========================================'); + logError(error); logger.warn('[wrenClient] Failed to fetch portfolios from API, using fallback'); return [DEFAULT_PORTFOLIO]; @@ -191,15 +225,26 @@ export async function createOffsetOrder( tons: number, dryRun: boolean = false ): Promise { + const startTime = Date.now(); + console.log('🔵 [WREN API] ========================================'); + console.log('🔵 [WREN API] POST /offset-orders - Request initiated'); + console.log('🔵 [WREN API] Timestamp:', new Date().toISOString()); + console.log('🔵 [WREN API] Parameters:', JSON.stringify({ portfolioId, tons, dryRun }, null, 2)); + try { if (!config.wrenApiKey) { + console.error('❌ [WREN API] Cannot create order - missing API token'); console.error('[wrenClient] Cannot create order - missing API token'); throw new Error('Carbon offset service is currently unavailable. Please contact support.'); } - + + console.log('🔵 [WREN API] API Key:', config.wrenApiKey ? '********' + config.wrenApiKey.slice(-4) : 'MISSING'); logger.log(`[wrenClient] Creating offset order: portfolio=${portfolioId}, tons=${tons}, dryRun=${dryRun}`); - + const api = createApiClient(); + console.log('🔵 [WREN API] Making request to: https://www.wren.co/api/offset-orders'); + console.log('🔵 [WREN API] Request payload:', JSON.stringify({ portfolioId, tons, dryRun }, null, 2)); + // Removed the /api prefix to match the working example const response = await api.post('/offset-orders', { // Using exactly the format shown in the API tutorial @@ -208,20 +253,36 @@ export async function createOffsetOrder( dryRun // Use the provided dryRun parameter }); + const duration = Date.now() - startTime; + + console.log('✅ [WREN API] POST /offset-orders - Success'); + console.log('✅ [WREN API] Status:', response.status); + console.log('✅ [WREN API] Duration:', duration + 'ms'); + // Add detailed response logging - logger.log('[wrenClient] Offset order response:', - response.status, + logger.log('[wrenClient] Offset order response:', + response.status, response.data ? 'has data' : 'no data'); - + if (response.status === 400) { + console.error('❌ [WREN API] Bad request - Status 400'); + console.error('❌ [WREN API] Bad request details:', response.data); console.error('[wrenClient] Bad request details:', response.data); throw new Error(`Failed to create offset order: ${JSON.stringify(response.data)}`); } const order = response.data; if (!order) { + console.error('❌ [WREN API] Empty response received'); throw new Error('Empty response received from offset order API'); } + + console.log('✅ [WREN API] Order ID:', order.id || 'N/A'); + console.log('✅ [WREN API] Amount Charged:', order.amountCharged ? `$${order.amountCharged}` : 'N/A'); + console.log('✅ [WREN API] Tons:', order.tons || 'N/A'); + console.log('✅ [WREN API] Status:', order.status || 'N/A'); + console.log('✅ [WREN API] Dry Run:', order.dryRun !== undefined ? order.dryRun : 'N/A'); + console.log('🔵 [WREN API] ========================================') // Log to help diagnose issues logger.log('[wrenClient] Order data keys:', Object.keys(order).join(', ')); @@ -267,11 +328,23 @@ export async function createOffsetOrder( dryRun: getSafeProp(order, 'dryRun', true) }; } catch (error: unknown) { + const duration = Date.now() - startTime; + console.error('❌ [WREN API] POST /offset-orders - Failed'); + console.error('❌ [WREN API] Duration:', duration + 'ms'); + logError(error); - + if (axios.isAxiosError(error)) { const axiosError = error as AxiosError; - + + console.error('❌ [WREN API] Status:', axiosError.response?.status || 'No response'); + console.error('❌ [WREN API] Status Text:', axiosError.response?.statusText || 'N/A'); + console.error('❌ [WREN API] Error Data:', JSON.stringify(axiosError.response?.data, null, 2)); + console.error('❌ [WREN API] Request URL:', axiosError.config?.url); + console.error('❌ [WREN API] Request Method:', axiosError.config?.method?.toUpperCase()); + console.error('❌ [WREN API] Request Data:', JSON.stringify(axiosError.config?.data, null, 2)); + console.log('🔵 [WREN API] ========================================'); + console.error('[wrenClient] Axios error details:', { status: axiosError.response?.status, statusText: axiosError.response?.statusText, @@ -284,14 +357,14 @@ export async function createOffsetOrder( data: axiosError.config?.data } }); - + if (axiosError.response?.status === 400) { // Provide more specific error for 400 Bad Request const responseData = axiosError.response.data as any; const errorMessage = responseData?.message || responseData?.error || 'Invalid request format'; throw new Error(`Bad request: ${errorMessage}`); } - + if (axiosError.code === 'ECONNABORTED') { throw new Error('Request timed out. Please try again.'); } @@ -301,8 +374,11 @@ export async function createOffsetOrder( if (axiosError.response.status === 401) { throw new Error('Carbon offset service authentication failed. Please check your API token.'); } + } else { + console.error('❌ [WREN API] Error:', error instanceof Error ? error.message : String(error)); + console.log('🔵 [WREN API] ========================================'); } - + throw new Error('Failed to create offset order. Please try again.'); } }