@@ -275,6 +275,12 @@ function toCachedModelPricing(
275275 } ;
276276}
277277
278+ async function cancelUnreadResponseBody ( response : Response | undefined ) : Promise < void > {
279+ if ( response ?. bodyUsed !== true ) {
280+ await response ?. body ?. cancel ( ) . catch ( ( ) => undefined ) ;
281+ }
282+ }
283+
278284async function readPricingJsonObject (
279285 response : Response ,
280286 source : string ,
@@ -299,6 +305,28 @@ async function readPricingJsonObject(
299305 return payload as Record < string , unknown > ;
300306}
301307
308+ async function fetchPricingJsonObject ( params : {
309+ fetchImpl : typeof fetch ;
310+ url : string ;
311+ source : string ;
312+ failureLabel : string ;
313+ signal ?: AbortSignal ;
314+ } ) : Promise < Record < string , unknown > > {
315+ let response : Response | undefined ;
316+ try {
317+ response = await params . fetchImpl ( params . url , {
318+ headers : { Accept : "application/json" } ,
319+ signal : createPricingFetchSignal ( params . signal ) ,
320+ } ) ;
321+ if ( ! response . ok ) {
322+ throw new Error ( `${ params . failureLabel } : HTTP ${ response . status } ` ) ;
323+ }
324+ return await readPricingJsonObject ( response , params . source ) ;
325+ } finally {
326+ await cancelUnreadResponseBody ( response ) ;
327+ }
328+ }
329+
302330// ---------------------------------------------------------------------------
303331// LiteLLM tiered-pricing parsing
304332// ---------------------------------------------------------------------------
@@ -383,14 +411,13 @@ async function fetchLiteLLMPricingCatalog(
383411 fetchImpl : typeof fetch ,
384412 signal ?: AbortSignal ,
385413) : Promise < LiteLLMPricingCatalog > {
386- const response = await fetchImpl ( LITELLM_PRICING_URL , {
387- headers : { Accept : "application/json" } ,
388- signal : createPricingFetchSignal ( signal ) ,
414+ const payload = await fetchPricingJsonObject ( {
415+ fetchImpl,
416+ url : LITELLM_PRICING_URL ,
417+ source : "LiteLLM" ,
418+ failureLabel : "LiteLLM pricing fetch failed" ,
419+ signal,
389420 } ) ;
390- if ( ! response . ok ) {
391- throw new Error ( `LiteLLM pricing fetch failed: HTTP ${ response . status } ` ) ;
392- }
393- const payload = await readPricingJsonObject ( response , "LiteLLM" ) ;
394421 const catalog : LiteLLMPricingCatalog = new Map ( ) ;
395422 for ( const [ key , value ] of Object . entries ( payload ) ) {
396423 if ( ! value || typeof value !== "object" ) {
@@ -1059,14 +1086,13 @@ async function fetchOpenRouterPricingCatalog(
10591086 fetchImpl : typeof fetch ,
10601087 signal ?: AbortSignal ,
10611088) : Promise < Map < string , OpenRouterPricingEntry > > {
1062- const response = await fetchImpl ( OPENROUTER_MODELS_URL , {
1063- headers : { Accept : "application/json" } ,
1064- signal : createPricingFetchSignal ( signal ) ,
1089+ const payload = await fetchPricingJsonObject ( {
1090+ fetchImpl,
1091+ url : OPENROUTER_MODELS_URL ,
1092+ source : "OpenRouter" ,
1093+ failureLabel : "OpenRouter /models failed" ,
1094+ signal,
10651095 } ) ;
1066- if ( ! response . ok ) {
1067- throw new Error ( `OpenRouter /models failed: HTTP ${ response . status } ` ) ;
1068- }
1069- const payload = await readPricingJsonObject ( response , "OpenRouter" ) ;
10701096 const entries = Array . isArray ( payload . data ) ? payload . data : [ ] ;
10711097 const catalog = new Map < string , OpenRouterPricingEntry > ( ) ;
10721098 for ( const entry of entries ) {
0 commit comments