// Packages
import fetch from'isomorphic-unfetch';import retry from'async-retry';import{parse as parseContentType}from'content-type';const fetchAPI=_async((path,token=null,opts={})=>{const headers=opts.headers||{};if(token){headers.Authorization=`bearer ${token}`;}// accept path to be a full url or a relative path
// accept path to be a full url or a relative path
const url=path[0]==='/'?API_URL+path:path;let agent;if(isServer){const{parse}=require('url');const{protocol}=parse(url);if(protocol){agent=getAgent(protocol);}}return retry(_async((bail,currentAttempt)=>{let _exit=false;let res,data,err;return _continue(_catch(()=>_await(fetch(url,{...opts,headers,agent}),_fetch=>{res=_fetch;return(()=>{if(opts.throwOnHTTPError&&(res.status<200||res.status>=300)){const{type}=parseContentType(res.headers.get('Content-Type')||'text/plain');return(()=>{if(type==='application/json'){return _await(res.json(),_res$json=>{data=_res$json;// some APIs don't wrap their errors in `error`
// (like api-www-user
if(opts.wrapErrorsLegacy&&data.code&&data.message){data.error=data;}err=new Error(data.error==null?`Unexpected Error (${opts.method} ${url})`:data.error.message);err.res=res;err.status=res.status;// TODO: remove this hack https://github.com/zeit/front/issues/553
if(data.error){err.code=data.error.code;for(const field of Object.keys(data.error)){if(field!=='message'){err[field]=data.error[field];}}}else{err.code=res.status;}});// some APIs don't wrap their errors in `error`
// (like api-www-user
}else{// handle it below as network error
let text='';return _continue(_catch(()=>_await(res.text(),_res$text=>{text=_res$text;}),berr=>{// eslint-disable-next-line no-console
console.error('error buffering text',berr);}),()=>{const cerr=Error(`Unexpected response content-type (${opts.method||'GET'} ${url}): `+type+`(${res.status}) ${text}`);cerr.res=res;cerr.status=res.status;throw cerr;});}})();}else return _invokeIgnored(()=>{if(res.status===204){// Since 204 means no content we return null
data=null;}else{return _await(res.json(),_res$json2=>{data=_res$json2;});}});})();}),e=>{err=isServer?e:new Error(NETWORK_ERR_MESSAGE);err.code=NETWORK_ERR_CODE;}),_result=>{if(_exit)return _result;if(!err)return data;if(err.status<500)return bail(err);err.message=`[Attempt: ${currentAttempt}] ${err.message}: [${opts.method||'GET'} ${url} ]`;err.stack=(err.stack?err.stack:'')+' ### Fetched URL: '+url;if(opts.body){err.stack=(err.stack?err.stack:'')+' ### Request Body: '+opts.body;}throw err;});}),{retries:3,maxTimeout:2500});});const API_URL=process.env.API_URL;const NETWORK_ERR_CODE='network_error';const NETWORK_ERR_MESSAGE='A network error has occurred. Please retry';const isServer=typeof window==='undefined';const agents=new Map();export default fetchAPI;const getAgent=protocol=>{if(!agents.has(protocol)){const http=require('http');const https=require('https');const module=protocol==='https:'?https:http;const opts={keepAlive:true,keepAliveMsecs:10000,maxSockets:100};const agent=new module.Agent(opts);agents.set(protocol,agent);}return agents.get(protocol);};