UNPKG

fexios

Version:

Fetch based HTTP client with similar API to axios for browser and Node.js

9 lines (8 loc) 11.4 kB
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var b=(t=>(t.BODY_USED="BODY_USED",t.NO_BODY_READER="NO_BODY_READER",t.TIMEOUT="TIMEOUT",t.NETWORK_ERROR="NETWORK_ERROR",t.BODY_NOT_ALLOWED="BODY_NOT_ALLOWED",t.HOOK_CONTEXT_CHANGED="HOOK_CONTEXT_CHANGED",t.ABORTED_BY_HOOK="ABORTED_BY_HOOK",t.INVALID_HOOK_CALLBACK="INVALID_HOOK_CALLBACK",t.UNEXPECTED_HOOK_RETURN="UNEXPECTED_HOOK_RETURN",t))(b||{});class u extends Error{constructor(s,r,e,o){super(r,o),this.code=s,this.context=e,this.name="FexiosError"}}class U extends u{constructor(s,r,e){super(r.statusText,s,void 0,e),this.response=r,this.name="FexiosResponseError"}}const P=t=>!(t instanceof U)&&t instanceof u;function N(t,s=2048){if(!(t instanceof Uint8Array))throw new TypeError("Input must be a Uint8Array");if(t.length===0)return!0;const r=Math.min(Math.max(t.length,256),s),e=t.slice(0,r);if(x(e))return!1;const o=W(e);if(o.nullByteRatio>.05||o.highByteRatio>.95)return!1;const i=["utf-8","utf-16le","utf-16be","iso-8859-1"];let n=-1,l=!1;for(const c of i)try{const a=new TextDecoder(c,{fatal:!0}).decode(e),f=q(a);f>n&&(n=f,l=f>.7)}catch{continue}return l}function x(t){if(t.length<4)return!1;const s=[[137,80,78,71],[255,216,255],[71,73,70],[37,80,68,70],[80,75,3,4],[80,75,5,6],[80,75,7,8],[127,69,76,70],[77,90],[202,254,186,190],[0,0,1,0],[82,73,70,70]];for(const r of s)if(t.length>=r.length){let e=!0;for(let o=0;o<r.length;o++)if(t[o]!==r[o]){e=!1;break}if(e)return!0}return!1}function W(t){let s=0,r=0,e=0;for(const o of t)o===0&&s++,o>127&&r++,(o<32&&o!==9&&o!==10&&o!==13||o===127)&&e++;return{nullByteRatio:s/t.length,highByteRatio:r/t.length,controlCharRatio:e/t.length}}function q(t){if(t.length===0)return 1;let s=1,r=0;for(let o=0;o<t.length;o++){const n=t[o].charCodeAt(0);n>=32&&n<=126||n===9||n===10||n===13||n===32?r++:n>127&&n<65534?!K(n)&&!M(n)&&r++:s-=.1}const e=r/t.length;return s*=e,v(t)&&(s*=1.1),Math.max(0,Math.min(1,s))}function K(t){return t>=0&&t<=31||t>=127&&t<=159}function M(t){return t>=57344&&t<=63743||t>=983040&&t<=1048573||t>=1048576&&t<=1114109}function v(t){return[/\b\w+\b/,/[.!?]+\s/,/\s+/,/[a-zA-Z]{3,}/,/[\u4e00-\u9fa5]+/,/\d+/].some(r=>r.test(t))}function R(t){if(typeof t!="object"||t===null||Object.prototype.toString.call(t)!=="[object Object]")return!1;const s=Object.getPrototypeOf(t);return s===Object.prototype||s===null}function B(t,s={}){const r={};return Object.entries(t).forEach(([e,o])=>{o!=null&&(s.dropEmptyString&&o===""||(r[e]=o))}),r}class w{constructor(s,r,e){this.rawResponse=s,this.data=r,this.ok=s.ok,this.status=s.status,this.statusText=s.statusText,this.headers=s.headers,Object.entries(e||{}).forEach(([o,i])=>{this[o]=i})}}async function j(t,s,r){var l;if(t.bodyUsed)throw new u(b.BODY_USED,"Response body has already been used or locked");const e=t.headers.get("content-type")||"",o=Number(t.headers.get("content-length"))||0,i=(c,h)=>h==="json"||c.startsWith("application/json"),n=(c,h,a)=>a==="blob"||c.startsWith("image/")&&!c.startsWith("image/svg")||c.startsWith("video/")||c.startsWith("audio/")||!N(h);if((t.status===101||t.status===426||t.headers.get("upgrade"))&&typeof globalThis.WebSocket<"u"){const c=new WebSocket(t.url);return await new Promise((h,a)=>{c.onopen=h,c.onerror=a}),new w(t,c,{ok:!0,status:101,statusText:"Switching Protocols"})}else if(e.startsWith("text/event-stream")&&!["text","json"].includes(s||"")&&typeof globalThis.EventSource<"u"){const c=new EventSource(t.url);return await new Promise((h,a)=>{c.onopen=h,c.onerror=a}),new w(t,c)}else{if(s==="stream")return new w(t,t.body);{const h=(l=t.clone().body)==null?void 0:l.getReader();if(!h)throw new u(b.NO_BODY_READER,"Failed to get ReadableStream from response body");let a=new Uint8Array;for(;;){const{done:y,value:O}=await h.read();if(y)break;if(O&&(a=new Uint8Array([...a,...O]),r&&o>0)){const g=Math.min(a.length/o,1);r(g,a)}}const f=new w(t,void 0);if(s==="arrayBuffer")return f.data=a.buffer,f;if(i(e,s))try{const y=new TextDecoder().decode(a);f.data=JSON.parse(y)}catch{}if(typeof f.data!="string"&&n(e,a,s)?f.data=new Blob([a],{type:t.headers.get("content-type")||void 0}):f.data=new TextDecoder().decode(a),typeof f.data=="string"&&s!=="text"){const y=f.data.trim(),O=y[0],g=y[y.length-1];if(O==="{"&&g==="}"||O==="["&&g==="]")try{f.data=JSON.parse(f.data)}catch{}}if(typeof f.data>"u"&&(f.data=a.length>0?a:void 0),f.ok)return f;throw new U(`Request failed with status code ${t.status}`,f)}}}class H{static makeSearchParams(s){const r=new URLSearchParams;return Object.entries(s).forEach(([e,o])=>{Array.isArray(o)?o.forEach(i=>r.append(e,String(i))):r.set(e,String(o))}),r}static makeQueryString(s){return this.makeSearchParams(s).toString()}}function F(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var k,A;function Y(){if(A)return k;A=1;function t(s){var r=this.constructor.prototype[s],e=function(){return r.apply(e,arguments)};return Object.setPrototypeOf(e,this.constructor.prototype),Object.getOwnPropertyNames(r).forEach(function(o){Object.defineProperty(e,o,Object.getOwnPropertyDescriptor(r,o))}),e}return t.prototype=Object.create(Function.prototype),k=t,k}var $=Y();const Q=F($);class p extends Q{constructor(s={}){super("request"),this.baseConfigs=s,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=B,this.checkIsPlainObject=R,this.ALL_METHODS.forEach(this.createMethodShortcut.bind(this))}async request(s,r){var g,_,C,L;let e=r=r||{};typeof s=="string"||s instanceof URL?e.url=s.toString():typeof s=="object"&&(e={...s,...e}),e=await this.emit("beforeInit",e);const o=r.baseURL||this.baseConfigs.baseURL||((g=globalThis.location)==null?void 0:g.href),i=o?new URL(o,(_=globalThis.location)==null?void 0:_.href):void 0,n=new URL(e.url.toString(),i);e.url=n.href,e.baseURL=i?i.href:n.origin,e.headers=this.mergeHeaders(this.baseConfigs.headers,r.headers);const l=i==null?void 0:i.searchParams,c=new URLSearchParams(n.searchParams);if(n.search="",e.url=n.href,e.query=this.mergeQuery(l,this.baseConfigs.query,c,r.query),n.search=H.makeQueryString(e.query),e.url=n.toString(),this.METHODS_WITHOUT_BODY.includes((C=e.method)==null?void 0:C.toLocaleLowerCase())&&e.body)throw new u(b.BODY_NOT_ALLOWED,`Request method "${e.method}" does not allow body`);e=await this.emit("beforeRequest",e);let h;typeof e.body<"u"&&e.body!==null&&(e.body instanceof Blob||e.body instanceof FormData||e.body instanceof URLSearchParams?h=e.body:typeof e.body=="object"&&e.body!==null?(h=JSON.stringify(e.body),e.headers["content-type"]="application/json"):h=e.body),!((L=r.headers)!=null&&L["content-type"])&&h&&(h instanceof FormData||h instanceof URLSearchParams?delete e.headers["content-type"]:typeof h=="string"&&typeof e.body=="object"?e.headers["content-type"]="application/json":h instanceof Blob&&(e.headers["content-type"]=h.type)),e.body=h,e=await this.emit("afterBodyTransformed",e);const a=e.abortController||globalThis.AbortController?new AbortController:void 0,f=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=f,e=await this.emit("beforeActualFetch",e);const y=e.timeout||this.baseConfigs.timeout||60*1e3;if(e.url.startsWith("ws"))try{const d=new WebSocket(e.url);return await new Promise((T,E)=>{const m=setTimeout(()=>{E(new u(b.TIMEOUT,`WebSocket connection timed out after ${y}ms`,e))},y);d.onopen=()=>{clearTimeout(m),T()},d.onerror=D=>{clearTimeout(m),E(new u(b.NETWORK_ERROR,"WebSocket connection failed",e))},d.onclose=D=>{D.code!==1e3&&(clearTimeout(m),E(new u(b.NETWORK_ERROR,`WebSocket closed with code ${D.code}`,e)))}}),e.rawResponse=new Response,e.response=new w(e.rawResponse,d,{ok:!0,status:101,statusText:"Switching Protocols"}),e.data=d,e.headers=new Headers,this.emit("afterResponse",e)}catch(d){throw d instanceof u?d:new u(b.NETWORK_ERROR,`WebSocket creation failed: ${d}`,e)}let O;try{a&&(O=setTimeout(()=>{a.abort()},y));const d=await fetch(e.rawRequest).catch(T=>{throw O&&clearTimeout(O),a!=null&&a.signal.aborted?new u(b.TIMEOUT,`Request timed out after ${y}ms`,e):new u(b.NETWORK_ERROR,T.message,e)});return O&&clearTimeout(O),e.rawResponse=d,e.response=await j(d,e.responseType,(T,E)=>{var m;(m=r==null?void 0:r.onProgress)==null||m.call(r,T,E)}),e.data=e.response.data,e.headers=e.response.headers,this.emit("afterResponse",e)}catch(d){throw O&&clearTimeout(O),d}}mergeQuery(s,...r){const e={},o=i=>{i&&(R(i)?Object.entries(i).forEach(([n,l])=>{l==null?delete e[n]:Array.isArray(l)?(n.endsWith("[]"),e[n]=l.map(String)):e[n]=String(l)}):new URLSearchParams(i).forEach((l,c)=>{e[c]=l}))};return o(s),r.forEach(o),e}mergeHeaders(s,...r){const e={},o=new Headers(s);for(const i of r){if(i==null)continue;if(R(i)){const l=B(i);if(Object.keys(l).length===0)continue;new Headers(l).forEach((h,a)=>{o.set(a,h)})}else new Headers(i).forEach((c,h)=>{o.set(h,c)})}return o.forEach((i,n)=>{e[n]=i}),e}async emit(s,r){const e=this.hooks.filter(o=>o.event===s);try{let o=0;for(const i of e){const n=`${s}#${i.action.name||`anonymous#${o}`}`,l=Symbol("FexiosHookContext");r[l]=l;const c=await i.action.call(this,r);if(c===!1)throw new u(b.ABORTED_BY_HOOK,`Request aborted by hook "${n}"`,r);if(typeof c=="object"&&c[l]===l)r=c;else{const h=globalThis["".concat("console")];try{throw new u(b.HOOK_CONTEXT_CHANGED,`Hook "${n}" should return the original FexiosContext or return false to abort the request, but got "${c}".`)}catch(a){h.warn(a.stack||a)}}delete r[l],o++}}catch(o){return Promise.reject(o)}return r}on(s,r,e=!1){if(typeof r!="function")throw new u(b.INVALID_HOOK_CALLBACK,`Hook should be a function, but got "${typeof r}"`);return this.hooks[e?"unshift":"push"]({event:s,action:r}),this}off(s,r){return s==="*"||!s?this.hooks=this.hooks.filter(e=>e.action!==r):this.hooks=this.hooks.filter(e=>e.event!==s||e.action!==r),this}createInterceptor(s){return{handlers:()=>this.hooks.filter(r=>r.event===s).map(r=>r.action),use:(r,e=!1)=>this.on(s,r,e),clear:()=>{this.hooks=this.hooks.filter(r=>r.event!==s)}}}createMethodShortcut(s){return Object.defineProperty(this,s,{value:(r,e,o)=>(this.METHODS_WITHOUT_BODY.includes(s.toLocaleLowerCase())?o=e:(o=o||{},o.body=e),this.request(r,{...o,method:s}))}),this}extends(s){const r=new p({...this.baseConfigs,...s});return r.hooks=[...this.hooks],r}static create(s){return new p(s)}}/** * 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 I=p.create,S=I();typeof globalThis<"u"?globalThis.fexios=S:typeof window<"u"&&(window.fexios=S);exports.Fexios=p;exports.FexiosError=u;exports.FexiosErrorCodes=b;exports.FexiosQueryBuilder=H;exports.FexiosResponse=w;exports.FexiosResponseError=U;exports.checkIfTextData=N;exports.checkIsPlainObject=R;exports.createFexios=I;exports.default=S;exports.dropUndefinedAndNull=B;exports.fexios=S;exports.isFexiosError=P;exports.resolveResponseBody=j; //# sourceMappingURL=index.cjs.map