2021-11-26 20:57:51 +08:00
import { isPlainObject } from "is-plain-object" ;
import nodeFetch from "node-fetch" ;
import { RequestError } from "@octokit/request-error" ;
import getBuffer from "./get-buffer-response" ;
export default function fetchWrapper ( requestOptions ) {
2022-04-04 21:27:01 +08:00
const log = requestOptions . request && requestOptions . request . log
? requestOptions . request . log
: console ;
2021-11-26 20:57:51 +08:00
if ( isPlainObject ( requestOptions . body ) ||
Array . isArray ( requestOptions . body ) ) {
requestOptions . body = JSON . stringify ( requestOptions . body ) ;
}
let headers = { } ;
let status ;
let url ;
const fetch = ( requestOptions . request && requestOptions . request . fetch ) || nodeFetch ;
return fetch ( requestOptions . url , Object . assign ( {
method : requestOptions . method ,
body : requestOptions . body ,
headers : requestOptions . headers ,
redirect : requestOptions . redirect ,
} ,
// `requestOptions.request.agent` type is incompatible
// see https://github.com/octokit/types.ts/pull/264
requestOptions . request ) )
2022-04-04 21:27:01 +08:00
. then ( async ( response ) => {
2021-11-26 20:57:51 +08:00
url = response . url ;
status = response . status ;
for ( const keyAndValue of response . headers ) {
headers [ keyAndValue [ 0 ] ] = keyAndValue [ 1 ] ;
}
2022-04-04 21:27:01 +08:00
if ( "deprecation" in headers ) {
const matches = headers . link && headers . link . match ( /<([^>]+)>; rel="deprecation"/ ) ;
const deprecationLink = matches && matches . pop ( ) ;
log . warn ( ` [@octokit/request] " ${ requestOptions . method } ${ requestOptions . url } " is deprecated. It is scheduled to be removed on ${ headers . sunset } ${ deprecationLink ? ` . See ${ deprecationLink } ` : "" } ` ) ;
}
2021-11-26 20:57:51 +08:00
if ( status === 204 || status === 205 ) {
return ;
}
// GitHub API returns 200 for HEAD requests
if ( requestOptions . method === "HEAD" ) {
if ( status < 400 ) {
return ;
}
throw new RequestError ( response . statusText , status , {
2022-04-04 21:27:01 +08:00
response : {
url ,
status ,
headers ,
data : undefined ,
} ,
2021-11-26 20:57:51 +08:00
request : requestOptions ,
} ) ;
}
if ( status === 304 ) {
throw new RequestError ( "Not modified" , status , {
2022-04-04 21:27:01 +08:00
response : {
url ,
status ,
headers ,
data : await getResponseData ( response ) ,
} ,
2021-11-26 20:57:51 +08:00
request : requestOptions ,
} ) ;
}
if ( status >= 400 ) {
2022-04-04 21:27:01 +08:00
const data = await getResponseData ( response ) ;
const error = new RequestError ( toErrorMessage ( data ) , status , {
response : {
url ,
status ,
2021-11-26 20:57:51 +08:00
headers ,
2022-04-04 21:27:01 +08:00
data ,
} ,
request : requestOptions ,
2021-11-26 20:57:51 +08:00
} ) ;
2022-04-04 21:27:01 +08:00
throw error ;
2021-11-26 20:57:51 +08:00
}
2022-04-04 21:27:01 +08:00
return getResponseData ( response ) ;
2021-11-26 20:57:51 +08:00
} )
. then ( ( data ) => {
return {
status ,
url ,
headers ,
data ,
} ;
} )
. catch ( ( error ) => {
2022-04-04 21:27:01 +08:00
if ( error instanceof RequestError )
2021-11-26 20:57:51 +08:00
throw error ;
throw new RequestError ( error . message , 500 , {
request : requestOptions ,
} ) ;
} ) ;
}
2022-04-04 21:27:01 +08:00
async function getResponseData ( response ) {
const contentType = response . headers . get ( "content-type" ) ;
if ( /application\/json/ . test ( contentType ) ) {
return response . json ( ) ;
}
if ( ! contentType || /^text\/|charset=utf-8$/ . test ( contentType ) ) {
return response . text ( ) ;
}
return getBuffer ( response ) ;
}
function toErrorMessage ( data ) {
if ( typeof data === "string" )
return data ;
// istanbul ignore else - just in case
if ( "message" in data ) {
if ( Array . isArray ( data . errors ) ) {
return ` ${ data . message } : ${ data . errors . map ( JSON . stringify ) . join ( ", " ) } ` ;
}
return data . message ;
}
// istanbul ignore next - just in case
return ` Unknown error: ${ JSON . stringify ( data ) } ` ;
}