fexios
Version:
Fetch based HTTP client with similar API to axios for browser and Node.js
9 lines (8 loc) • 10.1 kB
JavaScript
;Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var b=(s=>(s.BODY_USED="BODY_USED",s.NO_BODY_READER="NO_BODY_READER",s.TIMEOUT="TIMEOUT",s.NETWORK_ERROR="NETWORK_ERROR",s.BODY_NOT_ALLOWED="BODY_NOT_ALLOWED",s.HOOK_CONTEXT_CHANGED="HOOK_CONTEXT_CHANGED",s.ABORTED_BY_HOOK="ABORTED_BY_HOOK",s.INVALID_HOOK_CALLBACK="INVALID_HOOK_CALLBACK",s.UNEXPECTED_HOOK_RETURN="UNEXPECTED_HOOK_RETURN",s))(b||{});class f extends Error{constructor(r,t,e,o){super(t,o),this.code=r,this.context=e,this.name="FexiosError"}}class A extends f{constructor(r,t,e){super(t.statusText,r,void 0,e),this.response=t,this.name="FexiosResponseError"}}const x=s=>!(s instanceof A)&&s instanceof f;function I(s,r=1024){if(!(s instanceof Uint8Array))throw new TypeError("Input must be a Uint8Array");const t=s.slice(0,r),e=new TextDecoder("utf-8",{fatal:!0});try{const o=e.decode(t),n=/[\x00-\x08\x0E-\x1F\x7F]/g,h=o.match(n);return!(h&&h.length/o.length>.1)}catch{return!1}}function R(s){if(typeof s!="object"||s===null||Object.prototype.toString.call(s)!=="[object Object]")return!1;const r=Object.getPrototypeOf(s);return r===Object.prototype||r===null}function U(s,r={}){const t={};return Object.entries(s).forEach(([e,o])=>{o!=null&&(r.dropEmptyString&&o===""||(t[e]=o))}),t}class g{constructor(r,t,e){this.rawResponse=r,this.data=t,this.ok=r.ok,this.status=r.status,this.statusText=r.statusText,this.headers=r.headers,Object.entries(e||{}).forEach(([o,n])=>{this[o]=n})}}async function P(s,r,t){var l;if(s.bodyUsed)throw new f(b.BODY_USED,"Response body has already been used or locked");const e=s.headers.get("content-type")||"",o=Number(s.headers.get("content-length"))||0,n=(i,c)=>c==="json"||i.startsWith("application/json"),h=(i,c,a)=>a==="blob"||i.startsWith("image/")||i.startsWith("video/")||i.startsWith("audio/")||!I(c);if((s.status===101||s.status===426||s.headers.get("upgrade"))&&typeof globalThis.WebSocket<"u"){const i=new WebSocket(s.url);return await new Promise((c,a)=>{i.onopen=c,i.onerror=a}),new g(s,i,{ok:!0,status:101,statusText:"Switching Protocols"})}else if(e.startsWith("text/event-stream")&&!["text","json"].includes(r||"")&&typeof globalThis.EventSource<"u"){const i=new EventSource(s.url);return await new Promise((c,a)=>{i.onopen=c,i.onerror=a}),new g(s,i)}else{if(r==="stream")return new g(s,s.body);{const c=(l=s.clone().body)==null?void 0:l.getReader();if(!c)throw new f(b.NO_BODY_READER,"Failed to get ReadableStream from response body");let a=new Uint8Array;for(;;){const{done:O,value:y}=await c.read();if(O)break;if(y&&(a=new Uint8Array([...a,...y]),t&&o>0)){const m=Math.min(a.length/o,1);t(m,a)}}const d=new g(s,void 0);if(h(e,a,r)?d.data=new Blob([a],{type:s.headers.get("content-type")||void 0}):d.data=new TextDecoder().decode(a),n(e,r))try{d.data=JSON.parse(d.data)}catch{}if(typeof d.data=="string"&&r!=="text"){const O=d.data.trim(),y=O[0],m=O[O.length-1];if(y==="{"&&m==="}"||y==="["&&m==="]")try{d.data=JSON.parse(d.data)}catch{}}if(typeof d.data>"u"&&(d.data=a.length>0?a:void 0),d.ok)return d;throw new A(`Request failed with status code ${s.status}`,d)}}}class H{static makeSearchParams(r){const t=new URLSearchParams;return Object.entries(r).forEach(([e,o])=>{Array.isArray(o)?o.forEach(n=>t.append(e,String(n))):t.set(e,String(o))}),t}static makeQueryString(r){return this.makeSearchParams(r).toString()}}function B(s){return s&&s.__esModule&&Object.prototype.hasOwnProperty.call(s,"default")?s.default:s}var k,j;function q(){if(j)return k;j=1;function s(r){var t=this.constructor.prototype[r],e=function(){return t.apply(e,arguments)};return Object.setPrototypeOf(e,this.constructor.prototype),Object.getOwnPropertyNames(t).forEach(function(o){Object.defineProperty(e,o,Object.getOwnPropertyDescriptor(t,o))}),e}return s.prototype=Object.create(Function.prototype),k=s,k}var W=q();const K=B(W);class p extends K{constructor(r={}){super("request"),this.baseConfigs=r,this.hooks=[],this.DEFAULT_CONFIGS={baseURL:"",timeout:60*1e3,credentials:"same-origin",headers:{},query:{},responseType:void 0},this.ALL_METHODS=["get","post","put","patch","delete","head","options","trace"],this.METHODS_WITHOUT_BODY=["get","head","options","trace"],this.interceptors={request:this.createInterceptor("beforeRequest"),response:this.createInterceptor("afterResponse")},this.create=p.create,this.dropUndefinedAndNull=U,this.checkIsPlainObject=R,this.ALL_METHODS.forEach(this.createMethodShortcut.bind(this))}async request(r,t){var m,S,L,N;let e=t=t||{};typeof r=="string"||r instanceof URL?e.url=r.toString():typeof r=="object"&&(e={...r,...e}),e=await this.emit("beforeInit",e);const o=t.baseURL||this.baseConfigs.baseURL||((m=globalThis.location)==null?void 0:m.href),n=o?new URL(o,(S=globalThis.location)==null?void 0:S.href):void 0,h=new URL(e.url.toString(),n);e.url=h.href,e.baseURL=n?n.href:h.origin,e.headers=this.mergeHeaders(this.baseConfigs.headers,t.headers);const l=n==null?void 0:n.searchParams,i=new URLSearchParams(h.searchParams);if(h.search="",e.url=h.href,e.query=this.mergeQuery(l,this.baseConfigs.query,i,t.query),h.search=H.makeQueryString(e.query),e.url=h.toString(),this.METHODS_WITHOUT_BODY.includes((L=e.method)==null?void 0:L.toLocaleLowerCase())&&e.body)throw new f(b.BODY_NOT_ALLOWED,`Request method "${e.method}" does not allow body`);e=await this.emit("beforeRequest",e);let c;typeof e.body<"u"&&e.body!==null&&(e.body instanceof Blob||e.body instanceof FormData||e.body instanceof URLSearchParams?c=e.body:typeof e.body=="object"&&e.body!==null?(c=JSON.stringify(e.body),e.headers["content-type"]="application/json"):c=e.body),!((N=t.headers)!=null&&N["content-type"])&&c&&(c instanceof FormData||c instanceof URLSearchParams?delete e.headers["content-type"]:typeof c=="string"&&typeof e.body=="object"?e.headers["content-type"]="application/json":c instanceof Blob&&(e.headers["content-type"]=c.type)),e.body=c,e=await this.emit("afterBodyTransformed",e);const a=e.abortController||globalThis.AbortController?new AbortController:void 0,d=new Request(e.url,{method:e.method||"GET",credentials:e.credentials,cache:e.cache,mode:e.mode,headers:e.headers,body:e.body,signal:a==null?void 0:a.signal});e.rawRequest=d,e=await this.emit("beforeActualFetch",e);const O=e.timeout||this.baseConfigs.timeout||60*1e3;if(e.url.startsWith("ws"))try{const u=new WebSocket(e.url);return await new Promise((E,T)=>{const w=setTimeout(()=>{T(new f(b.TIMEOUT,`WebSocket connection timed out after ${O}ms`,e))},O);u.onopen=()=>{clearTimeout(w),E()},u.onerror=D=>{clearTimeout(w),T(new f(b.NETWORK_ERROR,"WebSocket connection failed",e))},u.onclose=D=>{D.code!==1e3&&(clearTimeout(w),T(new f(b.NETWORK_ERROR,`WebSocket closed with code ${D.code}`,e)))}}),e.rawResponse=new Response,e.response=new g(e.rawResponse,u,{ok:!0,status:101,statusText:"Switching Protocols"}),e.data=u,e.headers=new Headers,this.emit("afterResponse",e)}catch(u){throw u instanceof f?u:new f(b.NETWORK_ERROR,`WebSocket creation failed: ${u}`,e)}let y;try{a&&(y=setTimeout(()=>{a.abort()},O));const u=await fetch(e.rawRequest).catch(E=>{throw y&&clearTimeout(y),a!=null&&a.signal.aborted?new f(b.TIMEOUT,`Request timed out after ${O}ms`,e):new f(b.NETWORK_ERROR,E.message,e)});return y&&clearTimeout(y),e.rawResponse=u,e.response=await P(u,e.responseType,(E,T)=>{var w;(w=t==null?void 0:t.onProgress)==null||w.call(t,E,T)}),e.data=e.response.data,e.headers=e.response.headers,this.emit("afterResponse",e)}catch(u){throw y&&clearTimeout(y),u}}mergeQuery(r,...t){const e={},o=n=>{n&&(R(n)?Object.entries(n).forEach(([h,l])=>{l==null?delete e[h]:Array.isArray(l)?(h.endsWith("[]"),e[h]=l.map(String)):e[h]=String(l)}):new URLSearchParams(n).forEach((l,i)=>{e[i]=l}))};return o(r),t.forEach(o),e}mergeHeaders(r,...t){const e={},o=new Headers(r);for(const n of t){if(n==null)continue;if(R(n)){const l=U(n);if(Object.keys(l).length===0)continue;new Headers(l).forEach((c,a)=>{o.set(a,c)})}else new Headers(n).forEach((i,c)=>{o.set(c,i)})}return o.forEach((n,h)=>{e[h]=n}),e}async emit(r,t){const e=this.hooks.filter(o=>o.event===r);try{let o=0;for(const n of e){const h=`${r}#${n.action.name||`anonymous#${o}`}`,l=Symbol("FexiosHookContext");t[l]=l;const i=await n.action.call(this,t);if(i===!1)throw new f(b.ABORTED_BY_HOOK,`Request aborted by hook "${h}"`,t);if(typeof i=="object"&&i[l]===l)t=i;else{const c=globalThis["".concat("console")];try{throw new f(b.HOOK_CONTEXT_CHANGED,`Hook "${h}" should return the original FexiosContext or return false to abort the request, but got "${i}".`)}catch(a){c.warn(a.stack||a)}}delete t[l],o++}}catch(o){return Promise.reject(o)}return t}on(r,t,e=!1){if(typeof t!="function")throw new f(b.INVALID_HOOK_CALLBACK,`Hook should be a function, but got "${typeof t}"`);return this.hooks[e?"unshift":"push"]({event:r,action:t}),this}off(r,t){return r==="*"||!r?this.hooks=this.hooks.filter(e=>e.action!==t):this.hooks=this.hooks.filter(e=>e.event!==r||e.action!==t),this}createInterceptor(r){return{handlers:()=>this.hooks.filter(t=>t.event===r).map(t=>t.action),use:(t,e=!1)=>this.on(r,t,e),clear:()=>{this.hooks=this.hooks.filter(t=>t.event!==r)}}}createMethodShortcut(r){return Object.defineProperty(this,r,{value:(t,e,o)=>(this.METHODS_WITHOUT_BODY.includes(r.toLocaleLowerCase())?o=e:(o=o||{},o.body=e),this.request(t,{...o,method:r}))}),this}extends(r){const t=new p({...this.baseConfigs,...r});return t.hooks=[...this.hooks],t}static create(r){return new p(r)}}/**
* Fexios
* @desc Fetch based HTTP client with similar API to axios for browser and Node.js
*
* @license MIT
* @author dragon-fish <dragon-fish@qq.com>
*/const C=p.create,_=C();typeof globalThis<"u"?globalThis.fexios=_:typeof window<"u"&&(window.fexios=_);exports.Fexios=p;exports.FexiosError=f;exports.FexiosErrorCodes=b;exports.FexiosQueryBuilder=H;exports.FexiosResponse=g;exports.FexiosResponseError=A;exports.checkIfTextData=I;exports.checkIsPlainObject=R;exports.createFexios=C;exports.default=_;exports.dropUndefinedAndNull=U;exports.fexios=_;exports.isFexiosError=x;exports.resolveResponseBody=P;
//# sourceMappingURL=index.cjs.map