( apiKey: string, requestId: string )
| 82 | } |
| 83 | |
| 84 | async function fetchFalAIBillingEvent( |
| 85 | apiKey: string, |
| 86 | requestId: string |
| 87 | ): Promise<FalAIBillingEvent | undefined> { |
| 88 | const url = new URL('https://api.fal.ai/v1/models/billing-events') |
| 89 | url.searchParams.set('request_id', requestId) |
| 90 | url.searchParams.set('limit', '1') |
| 91 | |
| 92 | let response: Response |
| 93 | try { |
| 94 | response = await fetch(url, { |
| 95 | headers: { |
| 96 | Authorization: `Key ${apiKey}`, |
| 97 | }, |
| 98 | }) |
| 99 | } catch (error) { |
| 100 | logger.warn('Failed to fetch Fal.ai billing event', { |
| 101 | requestId, |
| 102 | error: getErrorMessage(error, 'Unknown error'), |
| 103 | }) |
| 104 | return undefined |
| 105 | } |
| 106 | |
| 107 | if (!response.ok) return undefined |
| 108 | |
| 109 | const data = await response.json().catch((error) => { |
| 110 | logger.warn('Failed to parse Fal.ai billing event response', { |
| 111 | requestId, |
| 112 | error: getErrorMessage(error, 'Unknown error'), |
| 113 | }) |
| 114 | return undefined |
| 115 | }) |
| 116 | if (!isRecordLike(data) || !Array.isArray(data.billing_events)) return undefined |
| 117 | |
| 118 | return data.billing_events.map(parseBillingEvent).find(Boolean) |
| 119 | } |
| 120 | |
| 121 | async function estimateFalAICallCost( |
| 122 | apiKey: string, |
no test coverage detected