@ecosy/core 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/http.d.ts CHANGED
@@ -58,6 +58,15 @@ export interface HttpOptions {
58
58
  * response body is returned.
59
59
  */
60
60
  allowedOrigins?: ReadonlyArray<string>;
61
+ /**
62
+ * Default `configs` merged into every request sent through this
63
+ * instance. Same shape and allowlist as {@link HttpRequest.configs}:
64
+ * `credentials`, `cache`, `mode`, `redirect`, `referrer`,
65
+ * `referrerPolicy`, `integrity`, `keepalive`, `priority`, `duplex`,
66
+ * plus framework extensions (`next`, `cf`, `dispatcher`). Per-call
67
+ * `configs` override these.
68
+ */
69
+ configs?: Record<string, unknown>;
61
70
  }
62
71
  /** Storage adapter interface for reading/writing auth tokens (e.g. `localStorage`). */
63
72
  export interface HttpStorage {
@@ -165,6 +174,7 @@ export declare class Http {
165
174
  private interceptors;
166
175
  private readonly baseURL;
167
176
  private readonly allowedOrigins;
177
+ private readonly defaultConfigs;
168
178
  /**
169
179
  * @param init - Either a base URL string (backwards-compatible form)
170
180
  * or an {@link HttpOptions} object. Using the object form lets
package/dist/http.js CHANGED
@@ -1 +1 @@
1
- "use strict";var t=require("./utilities/filelist.js"),e=require("./utilities/flatten.js"),r=require("./utilities/formdata.js"),s=require("./utilities/get.js"),o=require("./utilities/sanitize-mime.js"),n=require("./serialize.js"),i=require("./env.js");function a(t){try{return new URL(t).origin}catch(t){return null}}const c=new Set(["__proto__","constructor","prototype"]),d=new Set(["credentials","cache","mode","redirect","referrer","referrerPolicy","integrity","keepalive","priority","duplex","window","next","cf","dispatcher"]);function l(t){const e=Object.create(null);for(const r of Object.keys(t))c.has(r)||(e[r]=t[r]);return e}const p=i.getEnv("API_URL","/"),u=i.getEnv("API_AUTH_TOKEN_KEY"),h=i.getEnv("API_AUTH_HEADER_KEY"),g=i.getEnv("API_AUTH_HEADER_TYPE");var f,y;exports.HttpMethod=void 0,(f=exports.HttpMethod||(exports.HttpMethod={})).GET="GET",f.POST="POST",f.PUT="PUT",f.DELETE="DELETE",f.PATCH="PATCH",f.HEAD="HEAD",f.OPTIONS="OPTIONS",exports.HttpUpload=void 0,(y=exports.HttpUpload||(exports.HttpUpload={})).UPLOAD="UPLOAD",y.RELATED="RELATED";class T{static register(t,e){return this.registered[t]=Object.assign({},e),this}static all(){return Object.assign({},this.registered)}}T.registered={};class E{constructor(t){var e,r,s,o;this.defaultHeaders={"Content-Type":"application/json"},this.method=E.method,this.storage=E.storage,this.interceptors={request:[],response:[],transform:[],error:[]};const n="string"==typeof t||void 0===t?{baseURL:null!=t?t:p}:{baseURL:null!==(e=t.baseURL)&&void 0!==e?e:p,allowedOrigins:t.allowedOrigins};this.baseURL=null!==(s=null!==(r=n.baseURL)&&void 0!==r?r:p)&&void 0!==s?s:"/";const i=new Set;for(const t of null!==(o=n.allowedOrigins)&&void 0!==o?o:[]){const e=a(t);if(!e)throw new Error(`Http: invalid allowedOrigins entry: ${t}`);i.add(e)}const c=a(this.baseURL);c&&i.add(c),this.allowedOrigins=i}isAllowedOrigin(t){return 0===this.allowedOrigins.size||this.allowedOrigins.has(t)}assertSameOriginResponse(t,e,r){const s=Object.keys(r).some(t=>"authorization"===t.toLowerCase()&&!!r[t]),o=Object.keys(r).some(t=>"cookie"===t.toLowerCase()&&!!r[t]);if(!s&&!o)return;const n=a(t);if(!n)return;const i=e.url?a(e.url):null;if(i&&i!==n&&!this.isAllowedOrigin(i))throw new Error(`Http: credentialed request was redirected from ${n} to untrusted origin ${i}`)}static on(...t){const[e,r]=t,s=E.interceptors[e];s.includes(r)||s.push(r),E.interceptors[e]=s}static off(...t){const[e,r]=t,s=E.interceptors[e];E.interceptors[e]=s.filter(t=>t!==r)}setStorage(t){this.storage=t}isValidQuery(t){return"string"==typeof t||t instanceof URLSearchParams||(Array.isArray(t)?t.every(t=>Array.isArray(t)&&2===t.length&&"string"==typeof t[0]&&n.Serialize.Primitive.isPrimitive(t[1])):"object"==typeof t&&null!==t&&Object.values(t).every(t=>n.Serialize.Primitive.isPrimitive(t)))}getQuery(t){const{method:e,body:r,query:s}=t,o=e===exports.HttpMethod.GET&&this.isValidQuery(r)?r:s;if(!o||"object"!=typeof o)return"string"==typeof o?o:"";if(o instanceof URLSearchParams)return o.toString();const i=l(o);return n.Serialize.queryString.stringify(i,{skipNull:!0,skipEmptyString:!0})}addHeaders(t){this.defaultHeaders=Object.assign(Object.assign({},this.defaultHeaders),t)}on(...t){const[e,r]=t,s=this.interceptors[e];return s.includes(r)||s.push(r),this.interceptors[e]=s,this}off(...t){const[e,r]=t,s=this.interceptors[e];return this.interceptors[e]=s.filter(t=>t!==r),this}getToken(){const t=u||E.authTokenKey,e=h||E.authHeaderKey,r=g||E.authHeaderType;if(!t||!e)return{key:e,value:""};let s="";this.storage&&(s=this.storage.getItem(t)||"");const o={key:e,value:""};return s&&/^[\x21-\x7E]+$/.test(s)&&(o.value=r?`${r} ${s}`:s),o}getHeaders(t={},e){const r=this.getToken();r.key in t&&t[r.key]||(t[r.key]=r.value),e&&"Content-Type"in t?delete t["Content-Type"]:t["Content-Type"]=t["Content-Type"]||this.defaultHeaders["Content-Type"]||"application/json";const s=Object.assign(Object.assign(Object.assign({},this.defaultHeaders),t),E.extraHeaders||{});return E.extraHeaders=null,s}getURL(t){const{url:e="",params:r={}}=t,o=this.getQuery(t);let i;if(e){if(e.startsWith("//"))throw new Error(`Http: protocol-relative URLs are not allowed: ${e}`);if(/^[a-z][a-z0-9+.-]*:/i.test(e)){let t;try{t=new URL(e)}catch(t){throw new Error(`Http: invalid absolute URL: ${e}`)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new Error(`Http: unsupported URL scheme: ${t.protocol}`);if(!this.isAllowedOrigin(t.origin))throw new Error(`Http: URL origin '${t.origin}' is not in allowedOrigins`);i=t.toString()}else{const t=(this.baseURL||"/").replace(/\/+$/,""),r=e.replace(/^\/+/,"");i=t?`${t}/${r}`:`/${r}`}}else i=this.baseURL||"/";if(o){const t=i.includes("?")?"&":"?";i+=`${t}${o}`}if(!i.includes("{")||!i.includes("}"))return i;const a=Array.isArray(r)?r:l(r);return i.replace(/\{([a-zA-Z0-9_.-]+)\}/g,(t,e)=>{const r=s.get(a,e);return null==r||"object"==typeof r?"":n.Serialize.URL.encode(String(r))})}getBody(t){const{method:e,body:s}=t;if(e!==exports.HttpMethod.GET&&e!==exports.HttpMethod.HEAD&&e!==exports.HttpMethod.OPTIONS&&e!==exports.HttpMethod.DELETE)return e!==exports.HttpMethod.POST&&e!==exports.HttpMethod.PUT&&e!==exports.HttpMethod.PATCH||!r.isFormData(s)?s instanceof Uint8Array||s instanceof ArrayBuffer?s:void 0!==s?JSON.stringify(s):void 0:s}async request(t){const{method:e=exports.HttpMethod.GET}=t;try{let s=Object.assign({},t);const o=[...E.interceptors.request,...this.interceptors.request];for(const t of o)s=await t(s);const n=this.getURL(s),i=this.getHeaders(s.headers||{});r.isFormData(s.body)&&"Content-Type"in i&&delete i["Content-Type"];const a={};if(s.configs)for(const t of Object.keys(s.configs))d.has(t)&&(a[t]=s.configs[t]);const c=await fetch(n,Object.assign(Object.assign({},a),{method:s.method||e,headers:i,body:this.getBody(s),signal:s.signal}));this.assertSameOriginResponse(n,c,i);const l=c.headers.get("Content-Type")||"";let p=null;p=l.includes("application/json")?await c.json():await c.text();const u=[...E.interceptors.transform,...this.interceptors.transform];let h=p;for(const t of u)h=await t(h);const g=[...E.interceptors.response,...this.interceptors.response];let f=c;for(const t of g)f=await t(f);const y={};f.headers.forEach((t,e)=>{y[e]=t});const T=f.ok;let H=null;if(!T){H=p.error||p;const t=[...E.interceptors.error,...this.interceptors.error];for(const e of t)H=await e(H)}return{data:h,success:T,error:T?null:H,status:f.status,statusText:f.statusText,headers:y}}catch(t){let e=t instanceof Error?t:new Error(String(t));const r=[...E.interceptors.error,...this.interceptors.error];for(const t of r)e=await t(e);return{data:null,status:0,statusText:"Error",headers:{},error:e,success:!1}}}get(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.GET,url:t,query:e}))}post(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.POST,url:t,body:e}))}put(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.PUT,url:t,body:e}))}patch(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.PATCH,url:t,body:e}))}delete(t,e){return this.request(Object.assign(Object.assign({},e),{method:exports.HttpMethod.DELETE,url:t}))}head(t,e){return this.request(Object.assign(Object.assign({},e),{method:exports.HttpMethod.HEAD,url:t}))}options(t,e){return this.request(Object.assign(Object.assign({},e),{method:exports.HttpMethod.OPTIONS,url:t}))}upload(s,o,n){const i=(null==n?void 0:n.body)?r.objectToFormData(n.body):new FormData;let a=(null==n?void 0:n.name)||"file";if(Array.isArray(o)?(a.endsWith("[]")&&(a=a.slice(0,-2)),o.forEach((t,e)=>{i.append(`${a}[${e}]`,t,t.name)})):t.isFileList(o)?(a.endsWith("[]")&&(a=a.slice(0,-2)),Array.from(o).forEach((t,e)=>{i.append(`${a}[${e}]`,t,t.name)})):i.append(a,o,o.name),null==n?void 0:n.body){const t=e.flatten(n.body);Object.entries(t).forEach(([t,e])=>{null!=e&&i.append(t,String(e))})}return(null==n?void 0:n.onProgress)&&"undefined"!=typeof XMLHttpRequest?new Promise(async t=>{try{let e=Object.assign(Object.assign({},n),{method:exports.HttpMethod.POST,url:s,body:i});const r=[...E.interceptors.request,...this.interceptors.request];for(const t of r)e=await t(e);const o=this.getURL(e),a=this.getHeaders(e.headers||{},!0),c=new XMLHttpRequest;c.upload.addEventListener("progress",t=>{var e;if(t.lengthComputable){const r=Math.round(t.loaded/t.total*100);null===(e=n.onProgress)||void 0===e||e.call(n,{loaded:t.loaded,total:t.total,percentage:r})}}),c.addEventListener("load",async()=>{try{const e=c.getResponseHeader("Content-Type")||"";let r=null;r=e.includes("application/json")?JSON.parse(c.responseText):c.responseText;const s=[...E.interceptors.transform,...this.interceptors.transform];let o=r;for(const t of s)o=await t(o);const n=[...E.interceptors.response,...this.interceptors.response];let i=new Response(c.responseText,{status:c.status,statusText:c.statusText,headers:a});for(const t of n)i=await t(i);const d={};i.headers.forEach((t,e)=>{d[e]=t});const l=i.ok;t({data:o,success:l,error:l?null:o,status:i.status,statusText:i.statusText,headers:d})}catch(e){const r=[...E.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}}),c.addEventListener("error",e=>{const r=[...E.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}),c.addEventListener("abort",()=>{t({data:null,status:0,statusText:"Aborted",headers:{},error:null,success:!1})}),c.open(e.method||exports.HttpMethod.POST,o,!0),Object.entries(a).forEach(([t,e])=>{"content-type"!==(null==t?void 0:t.toLowerCase())&&e&&c.setRequestHeader(t,e)}),c.send(e.body)}catch(e){const r=[...E.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}}):this.request({method:exports.HttpMethod.POST,url:s,body:i,headers:null==n?void 0:n.headers,params:null==n?void 0:n.params,signal:null==n?void 0:n.signal,query:null==n?void 0:n.query})}related(t,e,r){const s=o.sanitizeMime(r.contentType),n=o.sanitizeMime(r.metadataMimeType||"application/json"),i=`----related-boundary-${Date.now()}-${Math.random().toString(36).slice(2)}`,a=JSON.stringify(r.metadata),c=new TextEncoder,d=c.encode(`--${i}\r\nContent-Type: ${n}; charset=UTF-8\r\n\r\n`+a+"\r\n"),l=c.encode(`--${i}\r\nContent-Type: ${s}\r\nContent-Transfer-Encoding: binary\r\n\r\n`),p=c.encode(`\r\n--${i}--`),u=e instanceof Uint8Array?e:new Uint8Array(e),h=new Uint8Array(d.length+l.length+u.length+p.length);return[d,l,u,p].reduce((t,e)=>(h.set(e,t),t+e.length),0),this.request({method:exports.HttpMethod.POST,url:t,body:h,headers:Object.assign(Object.assign({},r.headers||{}),{"Content-Type":`multipart/related; boundary=${i}`}),params:r.params,signal:r.signal,query:r.query})}static createFactory(t={}){const r=t.http||new E(t.baseURL);return function(s,o){const n=e.flatten("function"==typeof t.endpoint?t.endpoint():t.endpoint||{})[s];return{key:s,fn:async(...e)=>{const s="function"==typeof t.storage?await t.storage():t.storage;switch(s&&r.setStorage(s),o){case exports.HttpMethod.POST:return await r.post(n,...e);case exports.HttpMethod.PUT:return await r.put(n,...e);case exports.HttpMethod.PATCH:return await r.patch(n,...e);case exports.HttpMethod.DELETE:return await r.delete(n,...e);case exports.HttpMethod.HEAD:return await r.head(n,...e);case exports.HttpMethod.OPTIONS:return await r.options(n,...e);case exports.HttpUpload.UPLOAD:return await r.upload(n,...e);case exports.HttpUpload.RELATED:return await r.related(n,...e);default:return await r.get(n,...e)}}}}}}E.method=exports.HttpMethod,E.Endpoint=T,E.authTokenKey="access_token",E.authHeaderKey="Authorization",E.authHeaderType="Bearer",E.authDetectToken=["localStorage","sessionStorage","cookie"],E.extraHeaders=null,E.storage=null,E.interceptors={request:[],response:[],transform:[],error:[]},exports.API_AUTH_HEADER_KEY=h,exports.API_AUTH_HEADER_TYPE=g,exports.API_AUTH_TOKEN_KEY=u,exports.DEFAULT_BASE_URL=p,exports.Endpoint=T,exports.Http=E;
1
+ "use strict";var t=require("./utilities/filelist.js"),e=require("./utilities/flatten.js"),r=require("./utilities/formdata.js"),s=require("./utilities/get.js"),o=require("./utilities/sanitize-mime.js"),n=require("./serialize.js"),i=require("./env.js");function a(t){try{return new URL(t).origin}catch(t){return null}}const c=new Set(["__proto__","constructor","prototype"]),d=new Set(["credentials","cache","mode","redirect","referrer","referrerPolicy","integrity","keepalive","priority","duplex","window","next","cf","dispatcher"]);function l(t){const e=Object.create(null);for(const r of Object.keys(t))d.has(r)&&(e[r]=t[r]);return e}function p(t){const e=Object.create(null);for(const r of Object.keys(t))c.has(r)||(e[r]=t[r]);return e}const u=i.getEnv("API_URL","/"),h=i.getEnv("API_AUTH_TOKEN_KEY"),g=i.getEnv("API_AUTH_HEADER_KEY"),f=i.getEnv("API_AUTH_HEADER_TYPE");var y,T;exports.HttpMethod=void 0,(y=exports.HttpMethod||(exports.HttpMethod={})).GET="GET",y.POST="POST",y.PUT="PUT",y.DELETE="DELETE",y.PATCH="PATCH",y.HEAD="HEAD",y.OPTIONS="OPTIONS",exports.HttpUpload=void 0,(T=exports.HttpUpload||(exports.HttpUpload={})).UPLOAD="UPLOAD",T.RELATED="RELATED";class E{static register(t,e){return this.registered[t]=Object.assign({},e),this}static all(){return Object.assign({},this.registered)}}E.registered={};class H{constructor(t){var e,r,s;this.defaultHeaders={"Content-Type":"application/json"},this.method=H.method,this.storage=H.storage,this.interceptors={request:[],response:[],transform:[],error:[]};const o="string"==typeof t||void 0===t?{baseURL:null!=t?t:u}:t;this.baseURL=null!==(r=null!==(e=o.baseURL)&&void 0!==e?e:u)&&void 0!==r?r:"/";const n=new Set;for(const t of null!==(s=o.allowedOrigins)&&void 0!==s?s:[]){const e=a(t);if(!e)throw new Error(`Http: invalid allowedOrigins entry: ${t}`);n.add(e)}const i=a(this.baseURL);i&&n.add(i),this.allowedOrigins=n,this.defaultConfigs=o.configs?l(o.configs):{}}isAllowedOrigin(t){return 0===this.allowedOrigins.size||this.allowedOrigins.has(t)}assertSameOriginResponse(t,e,r){const s=Object.keys(r).some(t=>"authorization"===t.toLowerCase()&&!!r[t]),o=Object.keys(r).some(t=>"cookie"===t.toLowerCase()&&!!r[t]);if(!s&&!o)return;const n=a(t);if(!n)return;const i=e.url?a(e.url):null;if(i&&i!==n&&!this.isAllowedOrigin(i))throw new Error(`Http: credentialed request was redirected from ${n} to untrusted origin ${i}`)}static on(...t){const[e,r]=t,s=H.interceptors[e];s.includes(r)||s.push(r),H.interceptors[e]=s}static off(...t){const[e,r]=t,s=H.interceptors[e];H.interceptors[e]=s.filter(t=>t!==r)}setStorage(t){this.storage=t}isValidQuery(t){return"string"==typeof t||t instanceof URLSearchParams||(Array.isArray(t)?t.every(t=>Array.isArray(t)&&2===t.length&&"string"==typeof t[0]&&n.Serialize.Primitive.isPrimitive(t[1])):"object"==typeof t&&null!==t&&Object.values(t).every(t=>n.Serialize.Primitive.isPrimitive(t)))}getQuery(t){const{method:e,body:r,query:s}=t,o=e===exports.HttpMethod.GET&&this.isValidQuery(r)?r:s;if(!o||"object"!=typeof o)return"string"==typeof o?o:"";if(o instanceof URLSearchParams)return o.toString();const i=p(o);return n.Serialize.queryString.stringify(i,{skipNull:!0,skipEmptyString:!0})}addHeaders(t){this.defaultHeaders=Object.assign(Object.assign({},this.defaultHeaders),t)}on(...t){const[e,r]=t,s=this.interceptors[e];return s.includes(r)||s.push(r),this.interceptors[e]=s,this}off(...t){const[e,r]=t,s=this.interceptors[e];return this.interceptors[e]=s.filter(t=>t!==r),this}getToken(){const t=h||H.authTokenKey,e=g||H.authHeaderKey,r=f||H.authHeaderType;if(!t||!e)return{key:e,value:""};let s="";this.storage&&(s=this.storage.getItem(t)||"");const o={key:e,value:""};return s&&/^[\x21-\x7E]+$/.test(s)&&(o.value=r?`${r} ${s}`:s),o}getHeaders(t={},e){const r=this.getToken();r.key in t&&t[r.key]||(t[r.key]=r.value),e&&"Content-Type"in t?delete t["Content-Type"]:t["Content-Type"]=t["Content-Type"]||this.defaultHeaders["Content-Type"]||"application/json";const s=Object.assign(Object.assign(Object.assign({},this.defaultHeaders),t),H.extraHeaders||{});return H.extraHeaders=null,s}getURL(t){const{url:e="",params:r={}}=t,o=this.getQuery(t);let i;if(e){if(e.startsWith("//"))throw new Error(`Http: protocol-relative URLs are not allowed: ${e}`);if(/^[a-z][a-z0-9+.-]*:/i.test(e)){let t;try{t=new URL(e)}catch(t){throw new Error(`Http: invalid absolute URL: ${e}`)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new Error(`Http: unsupported URL scheme: ${t.protocol}`);if(!this.isAllowedOrigin(t.origin))throw new Error(`Http: URL origin '${t.origin}' is not in allowedOrigins`);i=t.toString()}else{const t=(this.baseURL||"/").replace(/\/+$/,""),r=e.replace(/^\/+/,"");i=t?`${t}/${r}`:`/${r}`}}else i=this.baseURL||"/";if(o){const t=i.includes("?")?"&":"?";i+=`${t}${o}`}if(!i.includes("{")||!i.includes("}"))return i;const a=Array.isArray(r)?r:p(r);return i.replace(/\{([a-zA-Z0-9_.-]+)\}/g,(t,e)=>{const r=s.get(a,e);return null==r||"object"==typeof r?"":n.Serialize.URL.encode(String(r))})}getBody(t){const{method:e,body:s}=t;if(e!==exports.HttpMethod.GET&&e!==exports.HttpMethod.HEAD&&e!==exports.HttpMethod.OPTIONS&&e!==exports.HttpMethod.DELETE)return e!==exports.HttpMethod.POST&&e!==exports.HttpMethod.PUT&&e!==exports.HttpMethod.PATCH||!r.isFormData(s)?s instanceof Uint8Array||s instanceof ArrayBuffer?s:void 0!==s?JSON.stringify(s):void 0:s}async request(t){const{method:e=exports.HttpMethod.GET}=t;try{let s=Object.assign({},t);const o=[...H.interceptors.request,...this.interceptors.request];for(const t of o)s=await t(s);const n=this.getURL(s),i=this.getHeaders(s.headers||{});r.isFormData(s.body)&&"Content-Type"in i&&delete i["Content-Type"];const a=Object.assign(Object.assign({},this.defaultConfigs),s.configs?l(s.configs):{}),c=await fetch(n,Object.assign(Object.assign({},a),{method:s.method||e,headers:i,body:this.getBody(s),signal:s.signal}));this.assertSameOriginResponse(n,c,i);const d=c.headers.get("Content-Type")||"";let p=null;p=d.includes("application/json")?await c.json():await c.text();const u=[...H.interceptors.transform,...this.interceptors.transform];let h=p;for(const t of u)h=await t(h);const g=[...H.interceptors.response,...this.interceptors.response];let f=c;for(const t of g)f=await t(f);const y={};f.headers.forEach((t,e)=>{y[e]=t});const T=f.ok;let E=null;if(!T){E=p.error||p;const t=[...H.interceptors.error,...this.interceptors.error];for(const e of t)E=await e(E)}return{data:h,success:T,error:T?null:E,status:f.status,statusText:f.statusText,headers:y}}catch(t){let e=t instanceof Error?t:new Error(String(t));const r=[...H.interceptors.error,...this.interceptors.error];for(const t of r)e=await t(e);return{data:null,status:0,statusText:"Error",headers:{},error:e,success:!1}}}get(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.GET,url:t,query:e}))}post(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.POST,url:t,body:e}))}put(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.PUT,url:t,body:e}))}patch(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:exports.HttpMethod.PATCH,url:t,body:e}))}delete(t,e){return this.request(Object.assign(Object.assign({},e),{method:exports.HttpMethod.DELETE,url:t}))}head(t,e){return this.request(Object.assign(Object.assign({},e),{method:exports.HttpMethod.HEAD,url:t}))}options(t,e){return this.request(Object.assign(Object.assign({},e),{method:exports.HttpMethod.OPTIONS,url:t}))}upload(s,o,n){const i=(null==n?void 0:n.body)?r.objectToFormData(n.body):new FormData;let a=(null==n?void 0:n.name)||"file";if(Array.isArray(o)?(a.endsWith("[]")&&(a=a.slice(0,-2)),o.forEach((t,e)=>{i.append(`${a}[${e}]`,t,t.name)})):t.isFileList(o)?(a.endsWith("[]")&&(a=a.slice(0,-2)),Array.from(o).forEach((t,e)=>{i.append(`${a}[${e}]`,t,t.name)})):i.append(a,o,o.name),null==n?void 0:n.body){const t=e.flatten(n.body);Object.entries(t).forEach(([t,e])=>{null!=e&&i.append(t,String(e))})}return(null==n?void 0:n.onProgress)&&"undefined"!=typeof XMLHttpRequest?new Promise(async t=>{try{let e=Object.assign(Object.assign({},n),{method:exports.HttpMethod.POST,url:s,body:i});const r=[...H.interceptors.request,...this.interceptors.request];for(const t of r)e=await t(e);const o=this.getURL(e),a=this.getHeaders(e.headers||{},!0),c=new XMLHttpRequest;c.upload.addEventListener("progress",t=>{var e;if(t.lengthComputable){const r=Math.round(t.loaded/t.total*100);null===(e=n.onProgress)||void 0===e||e.call(n,{loaded:t.loaded,total:t.total,percentage:r})}}),c.addEventListener("load",async()=>{try{const e=c.getResponseHeader("Content-Type")||"";let r=null;r=e.includes("application/json")?JSON.parse(c.responseText):c.responseText;const s=[...H.interceptors.transform,...this.interceptors.transform];let o=r;for(const t of s)o=await t(o);const n=[...H.interceptors.response,...this.interceptors.response];let i=new Response(c.responseText,{status:c.status,statusText:c.statusText,headers:a});for(const t of n)i=await t(i);const d={};i.headers.forEach((t,e)=>{d[e]=t});const l=i.ok;t({data:o,success:l,error:l?null:o,status:i.status,statusText:i.statusText,headers:d})}catch(e){const r=[...H.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}}),c.addEventListener("error",e=>{const r=[...H.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}),c.addEventListener("abort",()=>{t({data:null,status:0,statusText:"Aborted",headers:{},error:null,success:!1})}),c.open(e.method||exports.HttpMethod.POST,o,!0),Object.entries(a).forEach(([t,e])=>{"content-type"!==(null==t?void 0:t.toLowerCase())&&e&&c.setRequestHeader(t,e)}),c.send(e.body)}catch(e){const r=[...H.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}}):this.request({method:exports.HttpMethod.POST,url:s,body:i,headers:null==n?void 0:n.headers,params:null==n?void 0:n.params,signal:null==n?void 0:n.signal,query:null==n?void 0:n.query})}related(t,e,r){const s=o.sanitizeMime(r.contentType),n=o.sanitizeMime(r.metadataMimeType||"application/json"),i=`----related-boundary-${Date.now()}-${Math.random().toString(36).slice(2)}`,a=JSON.stringify(r.metadata),c=new TextEncoder,d=c.encode(`--${i}\r\nContent-Type: ${n}; charset=UTF-8\r\n\r\n`+a+"\r\n"),l=c.encode(`--${i}\r\nContent-Type: ${s}\r\nContent-Transfer-Encoding: binary\r\n\r\n`),p=c.encode(`\r\n--${i}--`),u=e instanceof Uint8Array?e:new Uint8Array(e),h=new Uint8Array(d.length+l.length+u.length+p.length);return[d,l,u,p].reduce((t,e)=>(h.set(e,t),t+e.length),0),this.request({method:exports.HttpMethod.POST,url:t,body:h,headers:Object.assign(Object.assign({},r.headers||{}),{"Content-Type":`multipart/related; boundary=${i}`}),params:r.params,signal:r.signal,query:r.query})}static createFactory(t={}){const r=t.http||new H(t.baseURL);return function(s,o){const n=e.flatten("function"==typeof t.endpoint?t.endpoint():t.endpoint||{})[s];return{key:s,fn:async(...e)=>{const s="function"==typeof t.storage?await t.storage():t.storage;switch(s&&r.setStorage(s),o){case exports.HttpMethod.POST:return await r.post(n,...e);case exports.HttpMethod.PUT:return await r.put(n,...e);case exports.HttpMethod.PATCH:return await r.patch(n,...e);case exports.HttpMethod.DELETE:return await r.delete(n,...e);case exports.HttpMethod.HEAD:return await r.head(n,...e);case exports.HttpMethod.OPTIONS:return await r.options(n,...e);case exports.HttpUpload.UPLOAD:return await r.upload(n,...e);case exports.HttpUpload.RELATED:return await r.related(n,...e);default:return await r.get(n,...e)}}}}}}H.method=exports.HttpMethod,H.Endpoint=E,H.authTokenKey="access_token",H.authHeaderKey="Authorization",H.authHeaderType="Bearer",H.authDetectToken=["localStorage","sessionStorage","cookie"],H.extraHeaders=null,H.storage=null,H.interceptors={request:[],response:[],transform:[],error:[]},exports.API_AUTH_HEADER_KEY=g,exports.API_AUTH_HEADER_TYPE=f,exports.API_AUTH_TOKEN_KEY=h,exports.DEFAULT_BASE_URL=u,exports.Endpoint=E,exports.Http=H;
package/dist/http.mjs CHANGED
@@ -1 +1 @@
1
- import{isFileList as e}from"./utilities/filelist.mjs";import{flatten as t}from"./utilities/flatten.mjs";import{isFormData as r,objectToFormData as s}from"./utilities/formdata.mjs";import{get as n}from"./utilities/get.mjs";import{sanitizeMime as o}from"./utilities/sanitize-mime.mjs";import{Serialize as i}from"./serialize.mjs";import{getEnv as a}from"./env.mjs";function c(e){try{return new URL(e).origin}catch(e){return null}}const l=new Set(["__proto__","constructor","prototype"]),u=new Set(["credentials","cache","mode","redirect","referrer","referrerPolicy","integrity","keepalive","priority","duplex","window","next","cf","dispatcher"]);function d(e){const t=Object.create(null);for(const r of Object.keys(e))l.has(r)||(t[r]=e[r]);return t}const p=a("API_URL","/"),h=a("API_AUTH_TOKEN_KEY"),f=a("API_AUTH_HEADER_KEY"),g=a("API_AUTH_HEADER_TYPE");var y,m;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE",e.PATCH="PATCH",e.HEAD="HEAD",e.OPTIONS="OPTIONS"}(y||(y={})),function(e){e.UPLOAD="UPLOAD",e.RELATED="RELATED"}(m||(m={}));class T{static register(e,t){return this.registered[e]=Object.assign({},t),this}static all(){return Object.assign({},this.registered)}}T.registered={};class O{constructor(e){var t,r,s,n;this.defaultHeaders={"Content-Type":"application/json"},this.method=O.method,this.storage=O.storage,this.interceptors={request:[],response:[],transform:[],error:[]};const o="string"==typeof e||void 0===e?{baseURL:null!=e?e:p}:{baseURL:null!==(t=e.baseURL)&&void 0!==t?t:p,allowedOrigins:e.allowedOrigins};this.baseURL=null!==(s=null!==(r=o.baseURL)&&void 0!==r?r:p)&&void 0!==s?s:"/";const i=new Set;for(const e of null!==(n=o.allowedOrigins)&&void 0!==n?n:[]){const t=c(e);if(!t)throw new Error(`Http: invalid allowedOrigins entry: ${e}`);i.add(t)}const a=c(this.baseURL);a&&i.add(a),this.allowedOrigins=i}isAllowedOrigin(e){return 0===this.allowedOrigins.size||this.allowedOrigins.has(e)}assertSameOriginResponse(e,t,r){const s=Object.keys(r).some(e=>"authorization"===e.toLowerCase()&&!!r[e]),n=Object.keys(r).some(e=>"cookie"===e.toLowerCase()&&!!r[e]);if(!s&&!n)return;const o=c(e);if(!o)return;const i=t.url?c(t.url):null;if(i&&i!==o&&!this.isAllowedOrigin(i))throw new Error(`Http: credentialed request was redirected from ${o} to untrusted origin ${i}`)}static on(...e){const[t,r]=e,s=O.interceptors[t];s.includes(r)||s.push(r),O.interceptors[t]=s}static off(...e){const[t,r]=e,s=O.interceptors[t];O.interceptors[t]=s.filter(e=>e!==r)}setStorage(e){this.storage=e}isValidQuery(e){return"string"==typeof e||e instanceof URLSearchParams||(Array.isArray(e)?e.every(e=>Array.isArray(e)&&2===e.length&&"string"==typeof e[0]&&i.Primitive.isPrimitive(e[1])):"object"==typeof e&&null!==e&&Object.values(e).every(e=>i.Primitive.isPrimitive(e)))}getQuery(e){const{method:t,body:r,query:s}=e,n=t===y.GET&&this.isValidQuery(r)?r:s;if(!n||"object"!=typeof n)return"string"==typeof n?n:"";if(n instanceof URLSearchParams)return n.toString();const o=d(n);return i.queryString.stringify(o,{skipNull:!0,skipEmptyString:!0})}addHeaders(e){this.defaultHeaders=Object.assign(Object.assign({},this.defaultHeaders),e)}on(...e){const[t,r]=e,s=this.interceptors[t];return s.includes(r)||s.push(r),this.interceptors[t]=s,this}off(...e){const[t,r]=e,s=this.interceptors[t];return this.interceptors[t]=s.filter(e=>e!==r),this}getToken(){const e=h||O.authTokenKey,t=f||O.authHeaderKey,r=g||O.authHeaderType;if(!e||!t)return{key:t,value:""};let s="";this.storage&&(s=this.storage.getItem(e)||"");const n={key:t,value:""};return s&&/^[\x21-\x7E]+$/.test(s)&&(n.value=r?`${r} ${s}`:s),n}getHeaders(e={},t){const r=this.getToken();r.key in e&&e[r.key]||(e[r.key]=r.value),t&&"Content-Type"in e?delete e["Content-Type"]:e["Content-Type"]=e["Content-Type"]||this.defaultHeaders["Content-Type"]||"application/json";const s=Object.assign(Object.assign(Object.assign({},this.defaultHeaders),e),O.extraHeaders||{});return O.extraHeaders=null,s}getURL(e){const{url:t="",params:r={}}=e,s=this.getQuery(e);let o;if(t){if(t.startsWith("//"))throw new Error(`Http: protocol-relative URLs are not allowed: ${t}`);if(/^[a-z][a-z0-9+.-]*:/i.test(t)){let e;try{e=new URL(t)}catch(e){throw new Error(`Http: invalid absolute URL: ${t}`)}if("http:"!==e.protocol&&"https:"!==e.protocol)throw new Error(`Http: unsupported URL scheme: ${e.protocol}`);if(!this.isAllowedOrigin(e.origin))throw new Error(`Http: URL origin '${e.origin}' is not in allowedOrigins`);o=e.toString()}else{const e=(this.baseURL||"/").replace(/\/+$/,""),r=t.replace(/^\/+/,"");o=e?`${e}/${r}`:`/${r}`}}else o=this.baseURL||"/";if(s){const e=o.includes("?")?"&":"?";o+=`${e}${s}`}if(!o.includes("{")||!o.includes("}"))return o;const a=Array.isArray(r)?r:d(r);return o.replace(/\{([a-zA-Z0-9_.-]+)\}/g,(e,t)=>{const r=n(a,t);return null==r||"object"==typeof r?"":i.URL.encode(String(r))})}getBody(e){const{method:t,body:s}=e;if(t!==y.GET&&t!==y.HEAD&&t!==y.OPTIONS&&t!==y.DELETE)return t!==y.POST&&t!==y.PUT&&t!==y.PATCH||!r(s)?s instanceof Uint8Array||s instanceof ArrayBuffer?s:void 0!==s?JSON.stringify(s):void 0:s}async request(e){const{method:t=y.GET}=e;try{let s=Object.assign({},e);const n=[...O.interceptors.request,...this.interceptors.request];for(const e of n)s=await e(s);const o=this.getURL(s),i=this.getHeaders(s.headers||{});r(s.body)&&"Content-Type"in i&&delete i["Content-Type"];const a={};if(s.configs)for(const e of Object.keys(s.configs))u.has(e)&&(a[e]=s.configs[e]);const c=await fetch(o,Object.assign(Object.assign({},a),{method:s.method||t,headers:i,body:this.getBody(s),signal:s.signal}));this.assertSameOriginResponse(o,c,i);const l=c.headers.get("Content-Type")||"";let d=null;d=l.includes("application/json")?await c.json():await c.text();const p=[...O.interceptors.transform,...this.interceptors.transform];let h=d;for(const e of p)h=await e(h);const f=[...O.interceptors.response,...this.interceptors.response];let g=c;for(const e of f)g=await e(g);const y={};g.headers.forEach((e,t)=>{y[t]=e});const m=g.ok;let T=null;if(!m){T=d.error||d;const e=[...O.interceptors.error,...this.interceptors.error];for(const t of e)T=await t(T)}return{data:h,success:m,error:m?null:T,status:g.status,statusText:g.statusText,headers:y}}catch(e){let t=e instanceof Error?e:new Error(String(e));const r=[...O.interceptors.error,...this.interceptors.error];for(const e of r)t=await e(t);return{data:null,status:0,statusText:"Error",headers:{},error:t,success:!1}}}get(e,t,r){return this.request(Object.assign(Object.assign({},r),{method:y.GET,url:e,query:t}))}post(e,t,r){return this.request(Object.assign(Object.assign({},r),{method:y.POST,url:e,body:t}))}put(e,t,r){return this.request(Object.assign(Object.assign({},r),{method:y.PUT,url:e,body:t}))}patch(e,t,r){return this.request(Object.assign(Object.assign({},r),{method:y.PATCH,url:e,body:t}))}delete(e,t){return this.request(Object.assign(Object.assign({},t),{method:y.DELETE,url:e}))}head(e,t){return this.request(Object.assign(Object.assign({},t),{method:y.HEAD,url:e}))}options(e,t){return this.request(Object.assign(Object.assign({},t),{method:y.OPTIONS,url:e}))}upload(r,n,o){const i=(null==o?void 0:o.body)?s(o.body):new FormData;let a=(null==o?void 0:o.name)||"file";if(Array.isArray(n)?(a.endsWith("[]")&&(a=a.slice(0,-2)),n.forEach((e,t)=>{i.append(`${a}[${t}]`,e,e.name)})):e(n)?(a.endsWith("[]")&&(a=a.slice(0,-2)),Array.from(n).forEach((e,t)=>{i.append(`${a}[${t}]`,e,e.name)})):i.append(a,n,n.name),null==o?void 0:o.body){const e=t(o.body);Object.entries(e).forEach(([e,t])=>{null!=t&&i.append(e,String(t))})}return(null==o?void 0:o.onProgress)&&"undefined"!=typeof XMLHttpRequest?new Promise(async e=>{try{let t=Object.assign(Object.assign({},o),{method:y.POST,url:r,body:i});const s=[...O.interceptors.request,...this.interceptors.request];for(const e of s)t=await e(t);const n=this.getURL(t),a=this.getHeaders(t.headers||{},!0),c=new XMLHttpRequest;c.upload.addEventListener("progress",e=>{var t;if(e.lengthComputable){const r=Math.round(e.loaded/e.total*100);null===(t=o.onProgress)||void 0===t||t.call(o,{loaded:e.loaded,total:e.total,percentage:r})}}),c.addEventListener("load",async()=>{try{const t=c.getResponseHeader("Content-Type")||"";let r=null;r=t.includes("application/json")?JSON.parse(c.responseText):c.responseText;const s=[...O.interceptors.transform,...this.interceptors.transform];let n=r;for(const e of s)n=await e(n);const o=[...O.interceptors.response,...this.interceptors.response];let i=new Response(c.responseText,{status:c.status,statusText:c.statusText,headers:a});for(const e of o)i=await e(i);const l={};i.headers.forEach((e,t)=>{l[t]=e});const u=i.ok;e({data:n,success:u,error:u?null:n,status:i.status,statusText:i.statusText,headers:l})}catch(t){const r=[...O.interceptors.error,...this.interceptors.error];for(const e of r)e(t);e({data:null,status:0,statusText:"Error",headers:{},error:t,success:!1})}}),c.addEventListener("error",t=>{const r=[...O.interceptors.error,...this.interceptors.error];for(const e of r)e(t);e({data:null,status:0,statusText:"Error",headers:{},error:t,success:!1})}),c.addEventListener("abort",()=>{e({data:null,status:0,statusText:"Aborted",headers:{},error:null,success:!1})}),c.open(t.method||y.POST,n,!0),Object.entries(a).forEach(([e,t])=>{"content-type"!==(null==e?void 0:e.toLowerCase())&&t&&c.setRequestHeader(e,t)}),c.send(t.body)}catch(t){const r=[...O.interceptors.error,...this.interceptors.error];for(const e of r)e(t);e({data:null,status:0,statusText:"Error",headers:{},error:t,success:!1})}}):this.request({method:y.POST,url:r,body:i,headers:null==o?void 0:o.headers,params:null==o?void 0:o.params,signal:null==o?void 0:o.signal,query:null==o?void 0:o.query})}related(e,t,r){const s=o(r.contentType),n=o(r.metadataMimeType||"application/json"),i=`----related-boundary-${Date.now()}-${Math.random().toString(36).slice(2)}`,a=JSON.stringify(r.metadata),c=new TextEncoder,l=c.encode(`--${i}\r\nContent-Type: ${n}; charset=UTF-8\r\n\r\n`+a+"\r\n"),u=c.encode(`--${i}\r\nContent-Type: ${s}\r\nContent-Transfer-Encoding: binary\r\n\r\n`),d=c.encode(`\r\n--${i}--`),p=t instanceof Uint8Array?t:new Uint8Array(t),h=new Uint8Array(l.length+u.length+p.length+d.length);return[l,u,p,d].reduce((e,t)=>(h.set(t,e),e+t.length),0),this.request({method:y.POST,url:e,body:h,headers:Object.assign(Object.assign({},r.headers||{}),{"Content-Type":`multipart/related; boundary=${i}`}),params:r.params,signal:r.signal,query:r.query})}static createFactory(e={}){const r=e.http||new O(e.baseURL);return function(s,n){const o=t("function"==typeof e.endpoint?e.endpoint():e.endpoint||{})[s];return{key:s,fn:async(...t)=>{const s="function"==typeof e.storage?await e.storage():e.storage;switch(s&&r.setStorage(s),n){case y.POST:return await r.post(o,...t);case y.PUT:return await r.put(o,...t);case y.PATCH:return await r.patch(o,...t);case y.DELETE:return await r.delete(o,...t);case y.HEAD:return await r.head(o,...t);case y.OPTIONS:return await r.options(o,...t);case m.UPLOAD:return await r.upload(o,...t);case m.RELATED:return await r.related(o,...t);default:return await r.get(o,...t)}}}}}}O.method=y,O.Endpoint=T,O.authTokenKey="access_token",O.authHeaderKey="Authorization",O.authHeaderType="Bearer",O.authDetectToken=["localStorage","sessionStorage","cookie"],O.extraHeaders=null,O.storage=null,O.interceptors={request:[],response:[],transform:[],error:[]};export{f as API_AUTH_HEADER_KEY,g as API_AUTH_HEADER_TYPE,h as API_AUTH_TOKEN_KEY,p as DEFAULT_BASE_URL,T as Endpoint,O as Http,y as HttpMethod,m as HttpUpload};
1
+ import{isFileList as t}from"./utilities/filelist.mjs";import{flatten as e}from"./utilities/flatten.mjs";import{isFormData as r,objectToFormData as s}from"./utilities/formdata.mjs";import{get as n}from"./utilities/get.mjs";import{sanitizeMime as o}from"./utilities/sanitize-mime.mjs";import{Serialize as i}from"./serialize.mjs";import{getEnv as a}from"./env.mjs";function c(t){try{return new URL(t).origin}catch(t){return null}}const l=new Set(["__proto__","constructor","prototype"]),u=new Set(["credentials","cache","mode","redirect","referrer","referrerPolicy","integrity","keepalive","priority","duplex","window","next","cf","dispatcher"]);function d(t){const e=Object.create(null);for(const r of Object.keys(t))u.has(r)&&(e[r]=t[r]);return e}function p(t){const e=Object.create(null);for(const r of Object.keys(t))l.has(r)||(e[r]=t[r]);return e}const h=a("API_URL","/"),f=a("API_AUTH_TOKEN_KEY"),g=a("API_AUTH_HEADER_KEY"),y=a("API_AUTH_HEADER_TYPE");var m,T;!function(t){t.GET="GET",t.POST="POST",t.PUT="PUT",t.DELETE="DELETE",t.PATCH="PATCH",t.HEAD="HEAD",t.OPTIONS="OPTIONS"}(m||(m={})),function(t){t.UPLOAD="UPLOAD",t.RELATED="RELATED"}(T||(T={}));class O{static register(t,e){return this.registered[t]=Object.assign({},e),this}static all(){return Object.assign({},this.registered)}}O.registered={};class b{constructor(t){var e,r,s;this.defaultHeaders={"Content-Type":"application/json"},this.method=b.method,this.storage=b.storage,this.interceptors={request:[],response:[],transform:[],error:[]};const n="string"==typeof t||void 0===t?{baseURL:null!=t?t:h}:t;this.baseURL=null!==(r=null!==(e=n.baseURL)&&void 0!==e?e:h)&&void 0!==r?r:"/";const o=new Set;for(const t of null!==(s=n.allowedOrigins)&&void 0!==s?s:[]){const e=c(t);if(!e)throw new Error(`Http: invalid allowedOrigins entry: ${t}`);o.add(e)}const i=c(this.baseURL);i&&o.add(i),this.allowedOrigins=o,this.defaultConfigs=n.configs?d(n.configs):{}}isAllowedOrigin(t){return 0===this.allowedOrigins.size||this.allowedOrigins.has(t)}assertSameOriginResponse(t,e,r){const s=Object.keys(r).some(t=>"authorization"===t.toLowerCase()&&!!r[t]),n=Object.keys(r).some(t=>"cookie"===t.toLowerCase()&&!!r[t]);if(!s&&!n)return;const o=c(t);if(!o)return;const i=e.url?c(e.url):null;if(i&&i!==o&&!this.isAllowedOrigin(i))throw new Error(`Http: credentialed request was redirected from ${o} to untrusted origin ${i}`)}static on(...t){const[e,r]=t,s=b.interceptors[e];s.includes(r)||s.push(r),b.interceptors[e]=s}static off(...t){const[e,r]=t,s=b.interceptors[e];b.interceptors[e]=s.filter(t=>t!==r)}setStorage(t){this.storage=t}isValidQuery(t){return"string"==typeof t||t instanceof URLSearchParams||(Array.isArray(t)?t.every(t=>Array.isArray(t)&&2===t.length&&"string"==typeof t[0]&&i.Primitive.isPrimitive(t[1])):"object"==typeof t&&null!==t&&Object.values(t).every(t=>i.Primitive.isPrimitive(t)))}getQuery(t){const{method:e,body:r,query:s}=t,n=e===m.GET&&this.isValidQuery(r)?r:s;if(!n||"object"!=typeof n)return"string"==typeof n?n:"";if(n instanceof URLSearchParams)return n.toString();const o=p(n);return i.queryString.stringify(o,{skipNull:!0,skipEmptyString:!0})}addHeaders(t){this.defaultHeaders=Object.assign(Object.assign({},this.defaultHeaders),t)}on(...t){const[e,r]=t,s=this.interceptors[e];return s.includes(r)||s.push(r),this.interceptors[e]=s,this}off(...t){const[e,r]=t,s=this.interceptors[e];return this.interceptors[e]=s.filter(t=>t!==r),this}getToken(){const t=f||b.authTokenKey,e=g||b.authHeaderKey,r=y||b.authHeaderType;if(!t||!e)return{key:e,value:""};let s="";this.storage&&(s=this.storage.getItem(t)||"");const n={key:e,value:""};return s&&/^[\x21-\x7E]+$/.test(s)&&(n.value=r?`${r} ${s}`:s),n}getHeaders(t={},e){const r=this.getToken();r.key in t&&t[r.key]||(t[r.key]=r.value),e&&"Content-Type"in t?delete t["Content-Type"]:t["Content-Type"]=t["Content-Type"]||this.defaultHeaders["Content-Type"]||"application/json";const s=Object.assign(Object.assign(Object.assign({},this.defaultHeaders),t),b.extraHeaders||{});return b.extraHeaders=null,s}getURL(t){const{url:e="",params:r={}}=t,s=this.getQuery(t);let o;if(e){if(e.startsWith("//"))throw new Error(`Http: protocol-relative URLs are not allowed: ${e}`);if(/^[a-z][a-z0-9+.-]*:/i.test(e)){let t;try{t=new URL(e)}catch(t){throw new Error(`Http: invalid absolute URL: ${e}`)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new Error(`Http: unsupported URL scheme: ${t.protocol}`);if(!this.isAllowedOrigin(t.origin))throw new Error(`Http: URL origin '${t.origin}' is not in allowedOrigins`);o=t.toString()}else{const t=(this.baseURL||"/").replace(/\/+$/,""),r=e.replace(/^\/+/,"");o=t?`${t}/${r}`:`/${r}`}}else o=this.baseURL||"/";if(s){const t=o.includes("?")?"&":"?";o+=`${t}${s}`}if(!o.includes("{")||!o.includes("}"))return o;const a=Array.isArray(r)?r:p(r);return o.replace(/\{([a-zA-Z0-9_.-]+)\}/g,(t,e)=>{const r=n(a,e);return null==r||"object"==typeof r?"":i.URL.encode(String(r))})}getBody(t){const{method:e,body:s}=t;if(e!==m.GET&&e!==m.HEAD&&e!==m.OPTIONS&&e!==m.DELETE)return e!==m.POST&&e!==m.PUT&&e!==m.PATCH||!r(s)?s instanceof Uint8Array||s instanceof ArrayBuffer?s:void 0!==s?JSON.stringify(s):void 0:s}async request(t){const{method:e=m.GET}=t;try{let s=Object.assign({},t);const n=[...b.interceptors.request,...this.interceptors.request];for(const t of n)s=await t(s);const o=this.getURL(s),i=this.getHeaders(s.headers||{});r(s.body)&&"Content-Type"in i&&delete i["Content-Type"];const a=Object.assign(Object.assign({},this.defaultConfigs),s.configs?d(s.configs):{}),c=await fetch(o,Object.assign(Object.assign({},a),{method:s.method||e,headers:i,body:this.getBody(s),signal:s.signal}));this.assertSameOriginResponse(o,c,i);const l=c.headers.get("Content-Type")||"";let u=null;u=l.includes("application/json")?await c.json():await c.text();const p=[...b.interceptors.transform,...this.interceptors.transform];let h=u;for(const t of p)h=await t(h);const f=[...b.interceptors.response,...this.interceptors.response];let g=c;for(const t of f)g=await t(g);const y={};g.headers.forEach((t,e)=>{y[e]=t});const m=g.ok;let T=null;if(!m){T=u.error||u;const t=[...b.interceptors.error,...this.interceptors.error];for(const e of t)T=await e(T)}return{data:h,success:m,error:m?null:T,status:g.status,statusText:g.statusText,headers:y}}catch(t){let e=t instanceof Error?t:new Error(String(t));const r=[...b.interceptors.error,...this.interceptors.error];for(const t of r)e=await t(e);return{data:null,status:0,statusText:"Error",headers:{},error:e,success:!1}}}get(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:m.GET,url:t,query:e}))}post(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:m.POST,url:t,body:e}))}put(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:m.PUT,url:t,body:e}))}patch(t,e,r){return this.request(Object.assign(Object.assign({},r),{method:m.PATCH,url:t,body:e}))}delete(t,e){return this.request(Object.assign(Object.assign({},e),{method:m.DELETE,url:t}))}head(t,e){return this.request(Object.assign(Object.assign({},e),{method:m.HEAD,url:t}))}options(t,e){return this.request(Object.assign(Object.assign({},e),{method:m.OPTIONS,url:t}))}upload(r,n,o){const i=(null==o?void 0:o.body)?s(o.body):new FormData;let a=(null==o?void 0:o.name)||"file";if(Array.isArray(n)?(a.endsWith("[]")&&(a=a.slice(0,-2)),n.forEach((t,e)=>{i.append(`${a}[${e}]`,t,t.name)})):t(n)?(a.endsWith("[]")&&(a=a.slice(0,-2)),Array.from(n).forEach((t,e)=>{i.append(`${a}[${e}]`,t,t.name)})):i.append(a,n,n.name),null==o?void 0:o.body){const t=e(o.body);Object.entries(t).forEach(([t,e])=>{null!=e&&i.append(t,String(e))})}return(null==o?void 0:o.onProgress)&&"undefined"!=typeof XMLHttpRequest?new Promise(async t=>{try{let e=Object.assign(Object.assign({},o),{method:m.POST,url:r,body:i});const s=[...b.interceptors.request,...this.interceptors.request];for(const t of s)e=await t(e);const n=this.getURL(e),a=this.getHeaders(e.headers||{},!0),c=new XMLHttpRequest;c.upload.addEventListener("progress",t=>{var e;if(t.lengthComputable){const r=Math.round(t.loaded/t.total*100);null===(e=o.onProgress)||void 0===e||e.call(o,{loaded:t.loaded,total:t.total,percentage:r})}}),c.addEventListener("load",async()=>{try{const e=c.getResponseHeader("Content-Type")||"";let r=null;r=e.includes("application/json")?JSON.parse(c.responseText):c.responseText;const s=[...b.interceptors.transform,...this.interceptors.transform];let n=r;for(const t of s)n=await t(n);const o=[...b.interceptors.response,...this.interceptors.response];let i=new Response(c.responseText,{status:c.status,statusText:c.statusText,headers:a});for(const t of o)i=await t(i);const l={};i.headers.forEach((t,e)=>{l[e]=t});const u=i.ok;t({data:n,success:u,error:u?null:n,status:i.status,statusText:i.statusText,headers:l})}catch(e){const r=[...b.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}}),c.addEventListener("error",e=>{const r=[...b.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}),c.addEventListener("abort",()=>{t({data:null,status:0,statusText:"Aborted",headers:{},error:null,success:!1})}),c.open(e.method||m.POST,n,!0),Object.entries(a).forEach(([t,e])=>{"content-type"!==(null==t?void 0:t.toLowerCase())&&e&&c.setRequestHeader(t,e)}),c.send(e.body)}catch(e){const r=[...b.interceptors.error,...this.interceptors.error];for(const t of r)t(e);t({data:null,status:0,statusText:"Error",headers:{},error:e,success:!1})}}):this.request({method:m.POST,url:r,body:i,headers:null==o?void 0:o.headers,params:null==o?void 0:o.params,signal:null==o?void 0:o.signal,query:null==o?void 0:o.query})}related(t,e,r){const s=o(r.contentType),n=o(r.metadataMimeType||"application/json"),i=`----related-boundary-${Date.now()}-${Math.random().toString(36).slice(2)}`,a=JSON.stringify(r.metadata),c=new TextEncoder,l=c.encode(`--${i}\r\nContent-Type: ${n}; charset=UTF-8\r\n\r\n`+a+"\r\n"),u=c.encode(`--${i}\r\nContent-Type: ${s}\r\nContent-Transfer-Encoding: binary\r\n\r\n`),d=c.encode(`\r\n--${i}--`),p=e instanceof Uint8Array?e:new Uint8Array(e),h=new Uint8Array(l.length+u.length+p.length+d.length);return[l,u,p,d].reduce((t,e)=>(h.set(e,t),t+e.length),0),this.request({method:m.POST,url:t,body:h,headers:Object.assign(Object.assign({},r.headers||{}),{"Content-Type":`multipart/related; boundary=${i}`}),params:r.params,signal:r.signal,query:r.query})}static createFactory(t={}){const r=t.http||new b(t.baseURL);return function(s,n){const o=e("function"==typeof t.endpoint?t.endpoint():t.endpoint||{})[s];return{key:s,fn:async(...e)=>{const s="function"==typeof t.storage?await t.storage():t.storage;switch(s&&r.setStorage(s),n){case m.POST:return await r.post(o,...e);case m.PUT:return await r.put(o,...e);case m.PATCH:return await r.patch(o,...e);case m.DELETE:return await r.delete(o,...e);case m.HEAD:return await r.head(o,...e);case m.OPTIONS:return await r.options(o,...e);case T.UPLOAD:return await r.upload(o,...e);case T.RELATED:return await r.related(o,...e);default:return await r.get(o,...e)}}}}}}b.method=m,b.Endpoint=O,b.authTokenKey="access_token",b.authHeaderKey="Authorization",b.authHeaderType="Bearer",b.authDetectToken=["localStorage","sessionStorage","cookie"],b.extraHeaders=null,b.storage=null,b.interceptors={request:[],response:[],transform:[],error:[]};export{g as API_AUTH_HEADER_KEY,y as API_AUTH_HEADER_TYPE,f as API_AUTH_TOKEN_KEY,h as DEFAULT_BASE_URL,O as Endpoint,b as Http,m as HttpMethod,T as HttpUpload};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecosy/core",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "A modular, tree-shakable collection of essential utilities, serialization primitives, and event-driven patterns for modern TypeScript applications",
5
5
  "license": "MIT",
6
6
  "publishConfig": {