UNPKG

synapse-storage

Version:

Набор инструментов для управления состоянием и апи-запросами

2 lines (1 loc) 13.4 kB
var k={debug:(r,...e)=>{process.env.NODE_ENV},log:(r,...e)=>{process.env.NODE_ENV},info:(r,...e)=>{},warn:(r,...e)=>{},error:(r,...e)=>{}};function O(r){return`${r?`${r}|`:""}${Math.random().toString(36).substring(2,9)+Date.now().toString(36)}`}function I(r){let e={};return r.forEach((t,a)=>{e[a.toLowerCase()]=t}),e}function P(r={},e={}){return{...r,...e,getFromStorage:r.getFromStorage||(t=>{try{let a=localStorage.getItem(t);return a?JSON.parse(a):void 0}catch{return}}),getCookie:r.getCookie||(t=>{try{let a=document.cookie.match(new RegExp(`(?:^|; )${t.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g,"\\$1")}=([^;]*)`));return a?decodeURIComponent(a[1]):void 0}catch{return}})}}async function D(r,e){let t=new Headers,a=e||P({},{});if(r)try{t=await Promise.resolve(r(t,a))}catch{}return t}function K(r,e){return async(t,a)=>{let n=new Headers(t);if(r)try{n=await Promise.resolve(r(n,a))}catch{}if(e)try{n=await Promise.resolve(e(n,a))}catch{}return n}}var q=(s=>(s.Json="json",s.Blob="blob",s.ArrayBuffer="arrayBuffer",s.Text="text",s.FormData="formData",s.Raw="raw",s))(q||{});function Q(r){let e=r.toLowerCase().split(";")[0].trim();if(e.includes("application/json"))return"json";if(e.includes("text/"))return"text";if(e.includes("multipart/form-data"))return"formData";if(e.includes("application/octet-stream")||e.includes("application/pdf")||e.includes("image/")||e.includes("audio/")||e.includes("video/"))return"blob"}function H(r){let e=r.get("content-type")||"",t=r.get("content-disposition")||"",a=e.includes("application/octet-stream")||e.includes("application/pdf")||e.includes("image/")||e.includes("audio/")||e.includes("video/"),n=t.includes("attachment")||t.includes("filename=");return a||n}function L(r){let e=r.get("content-disposition");if(!e)return;let t=e.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);if(t&&t[1])return t[1].replace(/['"]/g,"").trim()}function B(r){let e=r.get("content-type")||"",t=r.get("content-disposition")||"",a=r.get("content-length");return H(r)?{filename:L(r),contentType:e,contentDisposition:t,size:a?parseInt(a,10):void 0}:void 0}async function J(r,e){let t=e,a=r.headers.get("content-type")||"";!t&&a&&(H(r.headers)?t="blob":t=Q(a)),t||(t="json");try{let n;switch((t==="blob"||t==="arrayBuffer")&&(n=B(r.headers)),t){case"json":try{let s=await r.json();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}catch{let d=await r.text();return r.ok?{data:d,fileMetadata:n}:{error:d,fileMetadata:n}}case"text":{let s=await r.text();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"blob":{let s=await r.blob();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"arrayBuffer":{let s=await r.arrayBuffer();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"formData":{let s=await r.formData();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"raw":return r.ok?{data:r,fileMetadata:n}:{error:r,fileMetadata:n};default:let i=await r.blob();return r.ok?{data:i,fileMetadata:n}:{error:i,fileMetadata:n}}}catch(n){return r.ok?{data:void 0}:{error:n}}}function M(r){let{baseUrl:e,timeout:t=3e4,fetchFn:a=fetch,credentials:n="same-origin"}=r;return async(i,s={},d)=>{let{path:g,method:C,body:o,query:u,responseFormat:h}=i,{signal:b,timeout:R=t,responseFormat:l}=s,A=l||h,m=new URL(g.startsWith("http")?g:`${e}${g}`);u&&Object.entries(u).forEach(([p,c])=>{c!=null&&(Array.isArray(c)?c.forEach(w=>m.searchParams.append(p,String(w))):m.searchParams.append(p,String(c)))});let E;if(o!==void 0)if(o instanceof FormData||o instanceof Blob)E=o;else if(typeof o=="object"&&o!==null)try{E=JSON.stringify(o),d.has("Content-Type")||d.set("Content-Type","application/json")}catch{E=String(o)}else E=String(o);let T,f=new Promise((p,c)=>{R&&(T=window.setTimeout(()=>{c(new Error(`\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D\u043E \u0432\u0440\u0435\u043C\u044F \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u0430 (${R}\u043C\u0441)`))},R))});try{let p=a(m.toString(),{method:C,headers:d,body:E,signal:b,credentials:n}),c=await Promise.race([p,f]),{data:w,error:F,fileMetadata:j}=await J(c,A);return{data:w,error:F,ok:c.ok,status:c.status,statusText:c.statusText,headers:c.headers,fileDownloadResult:j}}catch(p){let c=p;return{error:c,ok:!1,status:0,statusText:c.message,headers:new Headers}}finally{T&&window.clearTimeout(T)}}}function $(r,e=[]){let t={};return!r||e.length===0||e.forEach(a=>{r.has(a)&&(t[a]=r.get(a)||"")}),t}var v=class{constructor(e,t,a,n,i,s){this.name=e;this.queryStorage=t;this.configCurrentEndpoint=a;this.cacheableHeaderKeys=n;this.globalCacheConfig=i;this.baseQueryConfig=s;this.prepareHeaders=K(s.prepareHeaders,a.prepareHeaders),this.queryFunction=M({baseUrl:s.baseUrl,fetchFn:s.fetchFn,timeout:s.timeout,credentials:s.credentials}),this.cacheableHeaders=[...n||[],...a.includeCacheableHeaderKeys||[]].filter(d=>!a.excludeCacheableHeaderKeys?.includes(d)),this.meta.name=e,this.meta.tags=a.tags??this.meta.tags,this.meta.invalidatesTags=a.invalidatesTags??this.meta.invalidatesTags,this.meta.cache=this.queryStorage.createCacheConfig(this.configCurrentEndpoint)??this.meta.cache}endpointSubscribers=new Set;fetchCounts=0;meta={cache:!1,invalidatesTags:[],name:"",tags:[]};queryFunction;cacheableHeaders;prepareHeaders;request(e,t){this.fetchCounts++;let a=O(this.name),n=new AbortController,i=new Set,s={status:"idle",requestParams:e,headers:{},error:void 0,data:void 0,fromCache:!1},d=P({requestParams:e},t?.context||{}),g=o=>{Object.assign(s,o),i.forEach(u=>{u({...s})})},C=new Promise(async(o,u)=>{try{let h=await D(this.prepareHeaders,d),b=$(h,t?.cacheableHeaderKeys?t.cacheableHeaderKeys:this.cacheableHeaders),R=this.queryStorage.shouldCache(this.configCurrentEndpoint,t),[l,A]=this.queryStorage.createCacheKey(this.name,{...e,...b}),m;if(R&&(m=await this.queryStorage.getCachedResult(l)),m)g({fromCache:!0,status:"success",data:m.data,error:void 0,headers:m.headers,requestParams:e}),o({...m,fromCache:!0});else{g({fromCache:!1,status:"loading"});let E=this.configCurrentEndpoint.request(e,t?.context),T={...t,signal:n.signal},f=await this.queryFunction(E,T,h);if(f.ok){let{headers:p,...c}=f;if(this.configCurrentEndpoint.invalidatesTags?.length&&await this.queryStorage.invalidateCacheByTags(this.configCurrentEndpoint.invalidatesTags),R){let w=this.queryStorage.createCacheConfig(this.configCurrentEndpoint);await this.queryStorage.setCachedResult(l,{...c,headers:I(p)},w,A??{},this.configCurrentEndpoint.tags??[])}g({fromCache:!1,status:"success",data:f.data,error:void 0,headers:f.headers,requestParams:e}),this.endpointSubscribers.forEach(w=>{let F={status:"success",fetchCounts:this.fetchCounts,meta:this.meta,cacheableHeaders:this.cacheableHeaders,error:void 0};w(F)}),o({...f,fromCache:!1})}else g({fromCache:!1,status:"error",data:void 0,error:f.error,headers:f.headers,requestParams:e}),this.endpointSubscribers.forEach(p=>{let c={status:"error",fetchCounts:this.fetchCounts,meta:this.meta,cacheableHeaders:this.cacheableHeaders,error:f.error};p(c)}),u(f.error)}}catch(h){g({fromCache:!1,status:"error",data:void 0,error:h,headers:void 0,requestParams:e}),u(h)}});return{id:a,subscribe(o,u={}){let{autoUnsubscribe:h=!0}=u;i.add(o),o(s);let b=()=>i.delete(o);return h&&C.finally(()=>{b()}),b},wait:()=>C,waitWithCallbacks(o={}){let{idle:u,loading:h,success:b,error:R}=o;return this.subscribe(l=>{switch(l.status){case"idle":u?.(l);break;case"loading":h?.(l);break;case"success":b?.(l.data,l);break;case"error":R?.(l.error,l);break}},{autoUnsubscribe:!0}),C},abort:()=>{n&&!n.signal.aborted&&n.abort()},then:(o,u)=>C.then(o,u),catch:o=>C.catch(o),finally:o=>C.finally(o)}}subscribe(e){this.endpointSubscribers.add(e);let t={status:"idle",fetchCounts:this.fetchCounts,meta:this.meta,cacheableHeaders:this.cacheableHeaders,error:void 0};return e(t),()=>this.endpointSubscribers.delete(e)}reset(){return this.fetchCounts=0,Promise.resolve()}destroy(){this.endpointSubscribers.clear()}};var x=class{constructor(e,t=!1){this.value=e;this.isRawKey=t}toString(){return this.value}toJSON(){return this.value}valueOf(){return this.value}isUnparseable(){return this.isRawKey}};var y=class{static createMetadata(e=0,t=[]){let a=Date.now(),n=e>0?a+e:1/0;return{createdAt:a,updatedAt:a,expiresAt:n,tags:t,createdAtDateTime:this.formatDateTime(a),updatedAtDateTime:this.formatDateTime(a),expiresAtDateTime:n===1/0?"never":this.formatDateTime(n)}}static formatDateTime(e){return new Date(e).toISOString()}static isExpired(e){return Date.now()>e.expiresAt}static updateMetadata(e){return{...e,updatedAt:Date.now()}}static createKey(...e){return new x(e.join("_"))}static createApiKey(e,t){if(!t)return[new x(e,!0),t];let a=Object.entries(t).sort(([n],[i])=>n.localeCompare(i)).map(([n,i])=>`${n}=${i}`).join("&");return[new x(`${e}_${a}`,!0),t]}static hasAnyTag(e,t=[]){return!e.tags||!t.length?!1:t.some(a=>e.tags?.includes(a))}};var S=class{constructor(e,t){this.storageExternal=e;this.globalCacheConfig=t}storage=null;cleanupInterval=null;defaultCacheOptions={ttl:5*60*1e3,cleanup:{enabled:!0,interval:10*60*1e3},invalidateOnError:!0};async initialize(){return await this.createStorage(),this.startCleanupInterval(),this}async createStorage(){try{let e=this.storageExternal;await e.initialize(),this.storage=e}catch(e){throw e}}startCleanupInterval(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null);let e=typeof this.globalCacheConfig=="object"?this.globalCacheConfig.cleanup:this.defaultCacheOptions.cleanup;e?.enabled&&e.interval&&(this.cleanupInterval=setInterval(()=>{this.cleanup().catch(t=>{})},e.interval))}getStorage(){return this.storage}createCacheKey(e,t){return y.createApiKey(e,t)}async getCachedResult(e){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let t=await this.storage.get(e);if(!t)return;if(y.isExpired(t.metadata)){await this.storage.delete(e);return}let a={...t,metadata:y.updateMetadata(t.metadata)};return await this.storage.set(e,a),t.data}async setCachedResult(e,t,a,n,i){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let s=y.createMetadata(a.ttl,i),d={data:t,metadata:s,params:n};await this.storage.set(e,d)}shouldCache(e,t){return!(this.globalCacheConfig===!1||e?.cache===!1||typeof e?.cache=="object"&&e?.cache.ttl===0||t?.disableCache===!0||this.globalCacheConfig===void 0&&e?.cache===void 0)}createCacheConfig(e){let t=this.defaultCacheOptions;if(typeof this.globalCacheConfig=="object"&&(t=this.globalCacheConfig),typeof e?.cache=="object"){let a=e.cache;t={...t,...a}}return t}async invalidateCacheByTags(e){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let t=await this.storage.keys();for(let a of t){let n=await this.storage.get(a);n&&y.hasAnyTag(n.metadata,e)&&await this.storage.delete(a)}}async invalidateCache(e){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");await this.storage.delete(e)}async cleanup(){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let e=await this.storage.keys();for(let t of e){let a=await this.storage.get(t);a&&y.isExpired(a.metadata)&&await this.storage.delete(t)}}async destroy(){this.cleanupInterval&&(window.clearInterval(this.cleanupInterval),this.cleanupInterval=null),this.storage&&(await this.storage.destroy(),this.storage=null)}};var U=class{queryStorage;cacheableHeaderKeys;globalCacheConfig;baseQueryConfig;storageExternal;createEndpoints;endpoints={};constructor(e){this.cacheableHeaderKeys=e.cacheableHeaderKeys,this.globalCacheConfig=e.cache,this.baseQueryConfig=e.baseQuery,this.storageExternal=e.storage,this.createEndpoints=e.endpoints}async init(){return this.queryStorage=await new S(this.storageExternal,this.globalCacheConfig).initialize(),await this.initializeEndpoints(),this}async initializeEndpoints(){let e=a=>a,t=await this.createEndpoints(e)||{};for(let[a,n]of Object.entries(t)){let i=a;this.endpoints[i]=new v(a,this.queryStorage,n,this.cacheableHeaderKeys,this.globalCacheConfig,this.baseQueryConfig)}}getEndpoints(){return this.endpoints}async request(e,t,a){let i=this.getEndpoints()[e];if(!i)throw new Error(`\u042D\u043D\u0434\u043F\u043E\u0438\u043D\u0442 ${String(e)} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D`);try{return await i.request(t,a).wait()}catch(s){throw k.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u0430 \u043A ${String(e)}`,{error:s,params:t}),s}}async destroy(){await Promise.all(Object.values(this.endpoints).map(async e=>(e.destroy(),Promise.resolve()))),this.endpoints={},await this.queryStorage.destroy()}};export{U as ApiClient,q as ResponseFormat,k as apiLogger,O as createUniqueId,I as headersToObject};