UNPKG

jcall

Version:

Ajax library that ease sending asynchronous calls to your backend server

1 lines 7.71 kB
function isObjectLiteral(e){return"object"==typeof e&&null!==e&&"[object Object]"===Object.prototype.toString.call(e)}const METHODS=["put","delete","post","get","patch"],local_noop=()=>{},FETCH_SUPPORT="function"==typeof fetch;class FetchError extends Error{constructor(e,t,r,n){super(e),this.name=this.constructor.name,this.status=t||null,this.statusText=r||null,this.stack=(new Error).stack,this.response=n}}function getHeaders(e){const t={};if("string"==typeof e)e.trim().split(/[\r\n]+/).forEach((e=>{const r=e.split(": "),n=r.shift(),o=r.join(": ");t[n.toLowerCase()]=o}));else if(e.entries)for(let[r,n]of e.entries())t[r]=n;return t}function jcall(e,t){if(!e)throw new Error("An api/url must be defined to send an jcall request!");let r=e,n="post",o=(t=t||{}).timeout||null,a=t.credentials||!1,s=t.csrf||jcall.csrf,c=t.useXHR||!1;if(e.indexOf(":")&&([n,r]=e.split(":")),s&&(a=!0),!0===jcall.preventer){let e=document.createElement("div");e.style.backgroundColor="rgba(0,0,0,.2)",e.style.position="fixed",e.style.zIndex="10000",e.style.left=e.style.top=0,e.style.width=e.style.height="100%",e.style.display="none",e.open=function(){this.style.display="inline"},e.close=function(){this.style.display="none"},jcall.preventer=e}let l=new AbortController,i={api:e,url:r,method:n&&-1!=METHODS.indexOf(n)?n:"post",credentials:"boolean"==typeof a&&a,timeout:o?o<10?1e3*o:o<100?100*o:o<1e3?10*o:o:0,headers:{signal:l.signal},csrf:s};function u(e,t,r,n,o){switch(e){case 400:n(new FetchError("400 - Bad Request: The server couldn't understand the request.",400,t,r));break;case 401:n(new FetchError("401 - Unauthorized: Authentication is required, or the provided credentials are incorrect.",401,t,r));break;case 403:n(new FetchError("403 - Forbidden: The server understood the request, but the user doesn't have permission to perform the action.",403,t,r));break;case 404:n(new FetchError("404 - Not Found: The requested resource could not be found on the server.",404,t,r));break;case 500:n(new FetchError("500 - Internal Server Error: The server encountered an unexpected condition.",500,t,r));break;case 502:n(new FetchError("502 - Bad Gateway: The server, while acting as a gateway or proxy, received an invalid response from the upstream server.",502,t,r));break;case 503:n(new FetchError("503 - Service Unavailable: The server is currently unavailable, often due to maintenance or overloading.",503,t,r))}}jcall.authorization&&(i.headers.authorize=jcall.authorization);let h={type:!0===c?"XHR":!0===FETCH_SUPPORT?"FETCH":"XHR",progress:function(){},setHeaders:function(e){let t={};return e.accept&&-1!=["application/json","application/xml","text/html","text/plain","*/*"].indexOf(e.accept)&&(t.accept=e.accept),e.cache&&("boolean"==typeof e.cache?"XHR"==this.type?t.cache=1==e.cache?"public":"no-cache":t.cache=1==e.cache?"force-cache":"no-cache":"string"==typeof e.cache&&("XHR"!=this.type||-1==["no-cache","no-store","public","private"].indexOf(e.cache)&&0!=e.cache.indexOf("max-age=")?"FETCH"==this.type&&-1!=["default","no-store","no-cache","reload","force-cache","only-if-cached"].indexOf(e.cache)?t.cache=e.cache:console.warn("You are using inproperiate values for ``cache`` attribute!"):t.cache=e.cache)),e.cookie&&(t.cookie=e.cookie),e.referer&&(t.referer=e.referer),e.origin&&(t.origin=e.origin),e.lang&&(t.lang=e.lang),e.authorize&&(t.authorize=e.authorize),"boolean"==typeof e.frame&&(t.frame=!0===e.frame?"SAMEORIGIN":"DENY"),!0===e.nosniff&&(t.nosniff=e.nosniff),e.contentType&&(t.contentType=e.contentType),i.headers=t,this},launch:function(e,t){const{headers:r}=i;let n=i.headers.contentType,o={result:null,response:null,headers:null,contentType:null};return!0!==t&&jcall.preventer&&jcall.preventer.open(),new Promise(((t,a)=>{let s=this;if(e instanceof FormData||("string"==typeof e?n="text/plain":!0===isObjectLiteral(e)&&(n="application/json",e=JSON.stringify(e))),"XHR"===this.type){let c=!0;"function"==typeof jcall.before&&(c=!1!==jcall.before(i,e)),!1===c&&t(!1);let l=new XMLHttpRequest;this.xhr=l,l.open(i.method||"post",i.url),l.setRequestHeader("X-Requested-With","XMLHttpRequest"),l.upload.onprogress=function(e){e.percent=e.loaded/e.total*100,"function"==typeof s.progress&&s.progress(e)},"boolean"==typeof i.credentials&&(l.withCredentials=i.credentials),l.timeout=i.timeout,l.responseType="json",i.csrf&&l.setRequestHeader("X-CSRF-TOKEN",i.csrf),n&&l.setRequestHeader("Content-Type",n),r.accept&&l.setRequestHeader("Accept",r.accept),r.cache&&l.setRequestHeader("Cache-Control",r.cache),r.cookie&&l.setRequestHeader("Cookie",r.cookie),r.referer&&l.setRequestHeader("Referer",r.referer),r.origin&&l.setRequestHeader("Origin",r.origin),r.lang&&l.setRequestHeader("Accept-Language",r.lang),r.authorize&&l.setRequestHeader("Authorization",r.authorize),r.frame&&l.setRequestHeader("X-Frame-Options",r.frame),!0===r.nosniff&&l.setRequestHeader("X-Content-Type-Options","nosniff"),l.onreadystatechange=function(e){if(4==this.readyState)if(o.headers=getHeaders(this.getAllResponseHeaders()),jcall.preventer&&jcall.preventer.close(),200==this.status)try{o.result=JSON.parse(this.response),o.response=this.response,t(o)}catch(e){a("ServerSide Error",this.responseText,this,e)}else u(this.status,this.statusText,this.response,a)},l.onerror=function(e){jcall.preventer&&jcall.preventer.close(),a("error",e,this)},l.ontimeout=function(e){jcall.preventer&&jcall.preventer.close(),a("timeout",e,this)},l.onabort=function(e){jcall.preventer&&jcall.preventer.close(),a("abort",e,this)},l.onprogress=function(e){e.percent=e.loaded/e.total*100,"function"==typeof s.progress&&s.progress(e)},l.send(e)}else{let r;0!=i.timeout&&0!=i.timeout&&(r=setTimeout((function(){jcall.preventer&&jcall.preventer.close(),s.abort()}),i.timeout)),i.body=e,i.signal=l.signal,i.credentials=!0===i.credentials?"include":"omit",n&&(i.headers["Content-Type"]=n),i.headers.authorize&&(i.headers.Authorization=i.headers.authorize),i.csrf&&(i.headers["X-CSRF-TOKEN"]=i.csrf);let c=!0;"function"==typeof jcall.before&&(c=!1!==jcall.before(i,e)),!1===c&&t(!1),i.cache=fetch(i.url,i).then((async e=>{const{ok:n,status:s,statusText:c,type:l,headers:i}=e;if(clearTimeout(r),jcall.preventer&&jcall.preventer.close(),!n)return void u(s,c,await e.json(),a);let h=i.get("Content-Type").split(";")[0];return o.headers=getHeaders(i),o.contentType=h,o.response=e,h.includes("application/json")?(o.result=await e.json(),t(o)):h.includes("text/html")||h.includes("text/plain")?(o.result=await e.text(),t(o)):h.includes("image")||h.includes("application/pdf")?e.blob():e.arrayBuffer()})).then((async e=>{if(e instanceof Blob){const e=new FileReader;e.readAsDataURL(blob),e.onloadend=()=>{t(e.result)}}})).catch((e=>{if(jcall.preventer&&jcall.preventer.close(),clearTimeout(r),"AbortError"===e.name)return a("timeout");a("error",e)}))}})).finally((e=>{jcall.after&&jcall.after(e)}))},abort:function(e){"XHR"==this.request.type?this.xhr.abort():l.abort(e)}};return h=Object.seal(h),h}jcall.csrf=null,jcall.authorization=null,jcall.after=local_noop,jcall.before=local_noop,jcall.preventer=null,jcall.jcallify=function(e,t){let r=null,n=null,o=local_noop,a=local_noop,s={api:function(e){return r=e,this},data:function(e){return n=e,this},success:function(e){return a=e,this},error:function(e){return o=e,this}};return e instanceof HTMLFormElement&&e.addEventListener("submit",(function(t){t.preventDefault();let s=e.getAttribute("method")||"post",c=this.getAttribute("action");if(null!=r&&(c=r(this,c)),!c)throw new Error("Bad setup!\nplease include the action attribute in the form");let l=new FormData(this);null!=n&&(l=n(this,l)),jcall(c,{method:s}).launch(l).then((e=>{a(e)})).catch((e=>o(e)))})),s},window.jcall=jcall;export default jcall;