@@ -4,7 +4,7 @@ import process from 'node:process'
44import { getVersions } from 'get-npm-meta'
55import { fetch as ofetch } from 'ofetch'
66
7- const TIMEOUT = 5000
7+ const DEFAULT_REQUEST_TIMEOUT = 5000
88const JSR_API_REGISTRY = 'https://jsr.io/'
99const USER_AGENT = `taze@npm node/${ process . version } `
1010
@@ -48,37 +48,54 @@ const fetchWithUserAgent: typeof fetch = (input, init) => {
4848 return ofetch ( input , { ...init , headers } )
4949}
5050
51- export async function fetchPackage ( spec : string , force : boolean = false , cwd ?: string ) : Promise < PackageData > {
52- const data = await Promise . race ( [
53- getVersions ( spec , {
54- cwd,
55- force,
56- fetch : fetchWithUserAgent ,
57- metadata : true ,
58- throw : false ,
59- } ) ,
60- new Promise < Packument > (
61- ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( `Timeout requesting "${ spec } "` ) ) , TIMEOUT ) ,
62- ) ,
63- ] ) as PackageVersionsInfoWithMetadata
51+ function createTimeoutError ( name : string ) {
52+ return new Error ( `Timeout requesting "${ name } "` )
53+ }
54+
55+ async function withRequestTimeout < T > ( name : string , timeout : number , run : ( signal : AbortSignal ) => Promise < T > ) {
56+ const controller = new AbortController ( )
57+ const timeoutError = createTimeoutError ( name )
58+ let timeoutId : ReturnType < typeof setTimeout > | undefined
59+ const timeoutPromise = new Promise < never > ( ( _ , reject ) => {
60+ timeoutId = setTimeout ( ( ) => {
61+ reject ( timeoutError )
62+ controller . abort ( timeoutError )
63+ } , timeout )
64+ } )
65+
66+ try {
67+ return await Promise . race ( [ run ( controller . signal ) , timeoutPromise ] )
68+ }
69+ finally {
70+ if ( timeoutId )
71+ clearTimeout ( timeoutId )
72+
73+ controller . abort ( timeoutError )
74+ }
75+ }
76+
77+ export async function fetchPackage ( spec : string , force : boolean = false , cwd ?: string , requestTimeout : number = DEFAULT_REQUEST_TIMEOUT ) : Promise < PackageData > {
78+ const data = await withRequestTimeout ( spec , requestTimeout , signal => getVersions ( spec , {
79+ cwd,
80+ force,
81+ fetch : ( input , init ) => fetchWithUserAgent ( input , { ...init , signal } ) ,
82+ metadata : true ,
83+ throw : false ,
84+ } ) ) as PackageVersionsInfoWithMetadata
6485
6586 if ( 'error' in data )
6687 throw new Error ( `Failed to fetch package "${ spec } ": ${ data . error } ` )
6788
6889 return toPackageData ( data )
6990}
7091
71- export async function fetchJsrPackageMeta ( name : string ) : Promise < PackageData > {
72- const meta = await Promise . race ( [
73- fetchWithUserAgent ( new URL ( `${ name } /meta.json` , JSR_API_REGISTRY ) , {
74- headers : {
75- accept : 'application/json' ,
76- } ,
77- } ) . then ( r => r . json ( ) ) ,
78- new Promise < JsrPackageMeta > (
79- ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( `Timeout requesting "${ name } "` ) ) , TIMEOUT ) ,
80- ) ,
81- ] ) as JsrPackageMeta
92+ export async function fetchJsrPackageMeta ( name : string , requestTimeout : number = DEFAULT_REQUEST_TIMEOUT ) : Promise < PackageData > {
93+ const meta = await withRequestTimeout ( name , requestTimeout , signal => fetchWithUserAgent ( new URL ( `${ name } /meta.json` , JSR_API_REGISTRY ) , {
94+ signal,
95+ headers : {
96+ accept : 'application/json' ,
97+ } ,
98+ } ) . then ( r => r . json ( ) ) ) as JsrPackageMeta
8299
83100 return {
84101 versions : Object . keys ( meta . versions ) ,
0 commit comments