import { userAgent } from '@frogpond/constants' ; import delay from 'delay' ; import queryString from 'query-string' ; export { insertForUrl } from './cached' ; const USER_AGENT = userAgent ( ) ; class HTTPError extends Error { response : Response ; constructor ( response ) { super ( response . statusText ) ; this . name = 'HTTPError' ; this . response = response ; } } export interface ExpandedFetchArgs extends RequestInit { searchParams ? : { [ key ] : string | number ; } ; throwHttpErrors ? : boolean ; delay ? : number ; } class Fetch { private readonly startMs : number ; private readonly request : Request ; private response ? : Response ; private readonly options : ExpandedFetchArgs ; constructor ( input , init = { } ) { this . startMs = Date . now ( ) ; this . options = { throwHttpErrors : true , delay : 0 , ... init , } ; let url = input instanceof Request ? input . url : input ; if ( init . searchParams ) { url = url . split ( '?' ) [ 0 ] ; url = `${ url }?${ queryString . stringify ( init . searchParams ) }` ; } let request ; if ( typeof input === 'string' ) { request = new Request ( url , init ) ; } else { request = new Request ( { ... input , url : url } , init ) ; } if ( ! request . headers . has ( 'User-Agent' ) ) { request . headers . set ( 'User-Agent' , USER_AGENT ) ; } this . request = request ; } async json < T > ( ) { if ( ! this . response ) { this . response = await this . doFetch ( ) ; } return this . response . clone ( ) . json ( ) ; } async text ( ) { if ( ! this . response ) { this . response = await this . doFetch ( ) ; } return this . response . clone ( ) . text ( ) ; } async doFetch ( ) { let response = await fetch ( this . request ) ; if ( this . options . throwHttpErrors && ! response . ok ) { throw new HTTPError ( response ) ; } let elapsed = Date . now ( ) - this . startMs ; if ( this . options . delay && elapsed < this . options . delay ) { await delay ( this . options . delay - elapsed ) ; } return response ; } } const buildFetch = ( input , init ? ) : Fetch => new Fetch ( input , init ) ; export { buildFetch as fetch } ;