@asaidimu/utils-remote-store 1.2.1 → 1.2.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/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./store"),t=require("./hash"),r=require("./error"),o=require("./types");Object.keys(e).forEach((function(t){"default"===t||Object.prototype.hasOwnProperty.call(exports,t)||Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})})),Object.keys(t).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return t[e]}})})),Object.keys(r).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return r[e]}})})),Object.keys(o).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return o[e]}})}));
|
|
1
|
+
"use strict";require("uuid");var e,t,s=Object.create,r=Object.defineProperty,a=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,o=Object.getPrototypeOf,n=Object.prototype.hasOwnProperty,c=(e={"node_modules/@asaidimu/events/index.js"(e,t){var s,r=Object.defineProperty,a=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,n={};((e,t)=>{for(var s in t)r(e,s,{get:t[s],enumerable:!0})})(n,{createEventBus:()=>c}),t.exports=(s=n,((e,t,s,n)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))o.call(e,c)||c===s||r(e,c,{get:()=>t[c],enumerable:!(n=a(t,c))||n.enumerable});return e})(r({},"__esModule",{value:!0}),s));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let s=[],r=0,a=0;const i=new Map,o=new Map;let n=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?n=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{r++,a+=t,i.set(e,(i.get(e)||0)+1)},h=()=>{const t=s;s=[],t.forEach((({name:t,payload:s})=>{const r=performance.now();try{(o.get(t)||[]).forEach((e=>e(s)))}catch(r){e.errorHandler({...r,eventName:t,payload:s})}c(t,performance.now()-r)}))},u=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(h,e.batchDelay)}})(),l=e=>{const s=t.get(e);s?o.set(e,Array.from(s)):o.delete(e)};return n&&(n.onmessage=e=>{const{name:t,payload:s}=e.data;(o.get(t)||[]).forEach((e=>e(s)))}),{subscribe:(e,s)=>{t.has(e)||t.set(e,new Set);const r=t.get(e);return r.add(s),l(e),()=>{r.delete(s),0===r.size?(t.delete(e),o.delete(e)):l(e)}},emit:({name:t,payload:r})=>{if(e.async)return s.push({name:t,payload:r}),s.length>=e.batchSize?h():u(),void(n&&n.postMessage({name:t,payload:r}));const a=performance.now();try{(o.get(t)||[]).forEach((e=>e(r))),n&&n.postMessage({name:t,payload:r})}catch(s){e.errorHandler({...s,eventName:t,payload:r})}c(t,performance.now()-a)},getMetrics:()=>({totalEvents:r,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:i,averageEmitDuration:r>0?a/r:0}),clear:()=>{t.clear(),o.clear(),s=[],r=0,a=0,i.clear(),n&&(n.close(),n=null)}}}}},function(){return t||(0,e[i(e)[0]])((t={exports:{}}).exports,t),t.exports});((e,t,c)=>{c=null!=e?s(o(e)):{},((e,t,s,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))n.call(e,c)||c===s||r(e,c,{get:()=>t[c],enumerable:!(o=a(t,c))||o.enumerable})})(e&&e.__esModule?c:r(c,"default",{value:e,enumerable:!0}),e)})(c());var h=class e extends Error{code;status;data;isRetryable;originalError;constructor(e,t){super(e.message),this.name="StoreError",this.code=e.code,this.status=e.status,this.data=e.data,this.isRetryable=e.isRetryable,this.originalError=t}static fromError(t,s){if(t.isAbort||"AbortError"===t.name)return new e({code:"ABORTED",message:"Request was cancelled",isRetryable:!1},t);if("NetworkError"===t.name||!navigator.onLine)return new e({code:"NETWORK_ERROR",message:"Network connection failed. Please check your internet connection.",isRetryable:!0},t);if(t.status)switch(t.status){case 400:return new e({code:"VALIDATION_ERROR",message:t.message||"Invalid request data",status:400,data:t.data,isRetryable:!1},t);case 401:return new e({code:"UNAUTHORIZED",message:"Authentication required or invalid credentials",status:401,isRetryable:!1},t);case 403:return new e({code:"FORBIDDEN",message:"Access denied for this resource",status:403,isRetryable:!1},t);case 404:return new e({code:"NOT_FOUND",message:"Resource not found",status:404,isRetryable:!1},t);case 409:return new e({code:"CONFLICT",message:t.message||"Resource conflict occurred",status:409,isRetryable:!1},t);case 429:return new e({code:"RATE_LIMITED",message:"Too many requests. Please try again later.",status:429,isRetryable:!0},t);case 500:case 502:case 503:case 504:return new e({code:"SERVER_ERROR",message:"Server error occurred. Please try again later.",status:t.status,isRetryable:!0},t);default:return new e({code:"HTTP_ERROR",message:t.message||`HTTP ${t.status} error occurred`,status:t.status,isRetryable:t.status>=500},t)}return"TimeoutError"===t.name||"TIMEOUT"===t.code?new e({code:"TIMEOUT",message:"Request timed out. Please try again.",isRetryable:!0},t):new e({code:"UNKNOWN_ERROR",message:t.message||`Unknown error occurred during ${s}`,isRetryable:!0},t)}};function u(e,t=new WeakMap){return void 0===e?"undefined":"function"==typeof e||"symbol"==typeof e?"":"string"==typeof e?`"${e}"`:"number"==typeof e||"boolean"==typeof e||null===e?String(e):Array.isArray(e)?`[${e.map((e=>u(e,t))).join(",")}]`:"object"==typeof e?t.has(e)?'"__circular__"':(t.set(e,!0),`{${Object.keys(e).sort().map((s=>`"${s}":${u(e[s],t)}`)).join(",")}}`):""}function l(e){let t=3421674724,s=2216829733;const r=u(e);for(let e=0;e<r.length;e++){s^=r.charCodeAt(e);const a=Math.imul(s,435),i=Math.imul(s,435)+Math.imul(t,435);s=a>>>0,t=i>>>0}return(t>>>0).toString(16)+(s>>>0).toString(16)}var d=class{constructor(e,t,s){this.operation=e,this.params=t,this.currentResult=s,this.currentResultHash=l(s),this.defaultResult=s}currentResult;currentResultHash;subscribers=new Set;defaultResult;idle=!1;getResult(){return this.currentResult}getParams(){return this.params}getOperation(){return this.operation}updateParams(e){this.params=e}reset(){this.currentResult=this.defaultResult,this.currentResultHash=l(this.defaultResult),this.notifySubscribers(),this.idle=!0}updateResult(e,t=!1){if(this.idle&&!t)return;this.idle=!1;const s=l(e);this.currentResultHash!==s&&(this.currentResult=e,this.currentResultHash=s,this.notifySubscribers())}subscribe(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}notifySubscribers(){this.subscribers.forEach((e=>{try{e()}catch(e){console.error("QueryState: Subscriber callback error:",e)}}))}hasSubscribers(){return this.subscribers.size>0}};exports.ReactiveRemoteStore=class{constructor(e,t,s,r){if(this.cache=e,this.baseStore=t,this.correlator=s,this.storeEventCorrelator=r,this.storeEventCorrelator){queueMicrotask((async()=>{this.unsubscribeFromBaseStore=await this.baseStore.subscribe("*",this.handleStoreEvent.bind(this))}))}this.setupCacheEventListeners()}queryStates=new Map;stableResults=new Map;stablePaginationMethods=new Map;errorCache=new Map;keyCache=new WeakMap;unsubscribeFromBaseStore;cacheEventCleanups=new Set;setupCacheEventListeners(){["cache:fetch:success","cache:fetch:error","cache:data:set","cache:data:invalidate","cache:read:hit"].forEach((e=>{const t=this.cache.on(e,(e=>{this.handleCacheEvent(e)}));this.cacheEventCleanups.add(t)}))}handleCacheEvent(e){const t=this.queryStates.get(e.key);if(t){const s=this.computeResult(e.key);t.updateResult(s)}}buildKey(e,t){if("object"==typeof t&&null!==t&&this.keyCache.has(t))return this.keyCache.get(t);const s=`${e}:${l(t)}`;return"object"==typeof t&&null!==t&&this.keyCache.set(t,s),s}getOrCreateError(e){if(this.errorCache.has(e))return this.errorCache.get(e);const t=new Error(e);return this.errorCache.set(e,t),t}getOrCreateStoreError(e){const t=`store:${e}`;if(this.errorCache.has(t))return this.errorCache.get(t);const s=h.fromError(new Error(e),"query");return this.errorCache.set(t,s),s}computeResult(e){const t=this.cache.getStats().entries.find((t=>t.key===e)),s=this.cache.peek(e);this.scheduleBackgroundFetch(e,t,s);if("read"===e.split(":")[0])return{data:s,loading:t?.isLoading??void 0===s,error:t?.error?this.getOrCreateError("Query failed"):void 0,stale:t?.isStale??!0,updated:t?.lastUpdated??0};{const r=this.getCurrentPageForQuery(e),a=this.getOrCreatePaginationMethods(e);return{page:s,loading:t?.isLoading??void 0===s,error:t?.error?this.getOrCreateStoreError("Query failed"):void 0,stale:t?.isStale??!0,updated:t?.lastUpdated??0,hasNext:!!s&&r<s.page.pages,hasPrevious:r>1,...a}}}scheduleBackgroundFetch(e,t,s){t?.isStale&&!t?.isLoading&&queueMicrotask((()=>{this.cache.get(e,{waitForFresh:!1}).catch((t=>{console.warn(`ReactiveRemoteStore: Background refetch failed for ${e}:`,t)}))})),void 0!==s||this.cache.has(e)||t?.isLoading||queueMicrotask((()=>{this.cache.get(e,{waitForFresh:!1}).catch((t=>{console.warn(`ReactiveRemoteStore: Background fetch failed for ${e}:`,t)}))}))}getCurrentPageForQuery(e){const t=this.queryStates.get(e);if(t){return t.getParams().page||1}return 1}getOrCreatePaginationMethods(e){if(this.stablePaginationMethods.has(e))return this.stablePaginationMethods.get(e);const t=this.queryStates.get(e);if(!t)throw new Error(`QueryState not found for ${e}`);const s=t.getOperation(),r={next:async()=>{const r=t.getParams(),a=r.page||1,i=this.buildKey(s,r),o=this.cache.peek(i);if(o&&a<o.page.pages){const i={...r,page:a+1},o=this.buildKey(s,i);if(!this.cache.has(o)){const e="list"===s?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(o,(()=>e(i)))}t.updateParams(i),await this.cache.get(o,{waitForFresh:!0});const n=this.computeResultForParams(s,i,e);t.updateResult(n)}},previous:async()=>{const r=t.getParams(),a=r.page||1;if(a>1){const i={...r,page:a-1},o=this.buildKey(s,i);if(!this.cache.has(o)){const e="list"===s?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(o,(()=>e(i)))}t.updateParams(i),await this.cache.get(o,{waitForFresh:!0});const n=this.computeResultForParams(s,i,e);t.updateResult(n)}},navigate:async r=>{if(r<1)return;const a={...t.getParams(),page:r},i=this.buildKey(s,a);if(!this.cache.has(i)){const e="list"===s?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(i,(()=>e(a)))}t.updateParams(a),await this.cache.get(i,{waitForFresh:!0});const o=this.computeResultForParams(s,a,e);t.updateResult(o)},refresh:async(s=1e3)=>{const r=t.getParams(),a=this.buildKey(t.getOperation(),r);t.reset();const i=this.cache.refresh(a),o=new Promise((e=>setTimeout(e,s)));await Promise.all([i,o]);const n=this.computeResultForParams(t.getOperation(),t.getParams(),e);t.updateResult(n,!0)},changeParams:async s=>{const r=s(t.getParams());if(!r)return void console.error("Setter function for changeParams must return a new parameters object.");const a=this.buildKey(t.getOperation(),r);if(!this.cache.has(a)){const e="list"===t.getOperation()?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(a,(()=>e(r)))}t.updateParams(r),await this.cache.get(a,{waitForFresh:!0});const i=this.computeResultForParams(t.getOperation(),r,e);t.updateResult(i)}};return this.stablePaginationMethods.set(e,r),r}computeResultForParams(e,t,s){const r=this.buildKey(e,t),a=this.cache.getStats().entries.find((e=>e.key===r)),i=this.cache.peek(r);if("read"===e)return{data:i,loading:a?.isLoading??void 0===i,error:a?.error?this.getOrCreateError("Query failed"):void 0,stale:a?.isStale??!0,updated:a?.lastUpdated??0};{const e=t.page||1,r=this.stablePaginationMethods.get(s)??{};return{page:i,loading:a?.isLoading??void 0===i,error:a?.error?this.getOrCreateStoreError("Query failed"):void 0,stale:a?.isStale??!0,updated:a?.lastUpdated??0,hasNext:!!i&&e<i.page.pages,hasPrevious:e>1,...r}}}hasActiveQuery(e,t){const s=this.buildKey(e,t);return this.stableResults.has(s)}getActiveQuery(e,t){const s=this.buildKey(e,t);return this.stableResults.get(s)}read(e){const t=this.buildKey("read",e);if(this.stableResults.has(t))return this.stableResults.get(t);this.cache.has(t)||this.cache.registerQuery(t,(async()=>await this.baseStore.read(e)));const s=this.computeResult(t),r=new d("read",e,s);this.queryStates.set(t,r);const a={value:()=>r.getResult(),onValueChange:e=>{const t=r.subscribe(e);return()=>{t()}}};return this.stableResults.set(t,a),a}list(e){return this.setupPagedQuery("list",e)}find(e){return this.setupPagedQuery("find",e)}setupPagedQuery(e,t){const s=this.buildKey(e,t);if(this.stableResults.has(s))return this.stableResults.get(s);if(!this.cache.has(s)){const r="list"===e?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(s,(()=>r(t)))}const r=this.cache.peek(s),a=new d(e,t,{page:r,loading:void 0===r,error:void 0,stale:!0,updated:0,hasNext:!1,hasPrevious:!1});this.queryStates.set(s,a);const i=this.computeResult(s);a.updateResult(i);const o={value:()=>a.getResult(),onValueChange:e=>{const t=a.subscribe(e);return()=>{t()}}};return this.stableResults.set(s,o),o}async invalidateQueries(e){if(this.correlator){const t=Array.from(this.queryStates.values()).map((e=>({queryKey:this.buildKey(e.getOperation(),e.getParams()),operation:e.getOperation(),params:e.getParams()}))),s=this.correlator(e,t).map((e=>this.cache.invalidate(e)));await Promise.all(s)}else await this.cache.invalidatePattern(/^list:/),await this.cache.invalidatePattern(/^find:/)}handleStoreEvent(e){if(this.storeEventCorrelator){const t=Array.from(this.queryStates.values()).map((e=>({queryKey:this.buildKey(e.getOperation(),e.getParams()),operation:e.getOperation(),params:e.getParams()})));this.storeEventCorrelator(e,t).forEach((e=>this.cache.invalidate(e)))}}async create(e){try{const t=await this.baseStore.create(e);return t&&(this.cache.setData(this.buildKey("read",{id:t.id}),t),await this.invalidateQueries({operation:"create",params:e})),t}catch(e){throw console.error("ReactiveRemoteStore: Create operation failed:",e),e}}async update(e){try{const t=await this.baseStore.update(e);return t&&await this.invalidateQueries({operation:"update",params:e}),t}catch(e){throw console.error("ReactiveRemoteStore: Update operation failed:",e),e}}async delete(e){try{await this.baseStore.delete(e),await this.invalidateQueries({operation:"delete",params:e})}catch(e){throw console.error("ReactiveRemoteStore: Delete operation failed:",e),e}}async notify(e){return this.baseStore.notify(e)}stream(e,t){return this.baseStore.stream(e,t)}async subscribe(e,t){return this.baseStore.subscribe(e,t)}async upload(e){try{const t=await this.baseStore.upload(e);return t&&(this.cache.setData(this.buildKey("read",{id:t.id}),t),await this.invalidateQueries({operation:"upload",params:e})),t}catch(e){throw console.error("ReactiveRemoteStore: Upload operation failed:",e),e}}async refresh(e,t){const s=this.buildKey(e,t);return this.cache.refresh(s)}prefetch(e,t){const s=this.buildKey(e,t);this.cache.prefetch(s).catch((e=>{console.warn(`ReactiveRemoteStore: Prefetch failed for ${s}:`,e)}))}async invalidate(e,t){const s=this.buildKey(e,t);await this.cache.invalidate(s)}async invalidateAll(){const e=Array.from(this.queryStates.keys()).map((e=>this.cache.invalidate(e)));await Promise.all(e)}getStats(){return{...this.cache.getStats(),activeSubscriptions:this.queryStates.size}}destroy(){this.cacheEventCleanups.forEach((e=>e())),this.cacheEventCleanups.clear(),this.queryStates.clear(),this.stableResults.clear(),this.stablePaginationMethods.clear(),this.errorCache.clear(),this.keyCache=new WeakMap,this.unsubscribeFromBaseStore&&this.unsubscribeFromBaseStore()}},exports.StoreError=h,exports.hash=l;
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./store";export*from"./hash";export*from"./error";export*from"./types";
|
|
1
|
+
import"uuid";var e,t,s=Object.create,a=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,o=Object.getPrototypeOf,n=Object.prototype.hasOwnProperty,c=(e={"node_modules/@asaidimu/events/index.js"(e,t){var s,a=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,n={};((e,t)=>{for(var s in t)a(e,s,{get:t[s],enumerable:!0})})(n,{createEventBus:()=>c}),t.exports=(s=n,((e,t,s,n)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))o.call(e,c)||c===s||a(e,c,{get:()=>t[c],enumerable:!(n=r(t,c))||n.enumerable});return e})(a({},"__esModule",{value:!0}),s));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let s=[],a=0,r=0;const i=new Map,o=new Map;let n=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?n=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{a++,r+=t,i.set(e,(i.get(e)||0)+1)},h=()=>{const t=s;s=[],t.forEach((({name:t,payload:s})=>{const a=performance.now();try{(o.get(t)||[]).forEach((e=>e(s)))}catch(a){e.errorHandler({...a,eventName:t,payload:s})}c(t,performance.now()-a)}))},u=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(h,e.batchDelay)}})(),l=e=>{const s=t.get(e);s?o.set(e,Array.from(s)):o.delete(e)};return n&&(n.onmessage=e=>{const{name:t,payload:s}=e.data;(o.get(t)||[]).forEach((e=>e(s)))}),{subscribe:(e,s)=>{t.has(e)||t.set(e,new Set);const a=t.get(e);return a.add(s),l(e),()=>{a.delete(s),0===a.size?(t.delete(e),o.delete(e)):l(e)}},emit:({name:t,payload:a})=>{if(e.async)return s.push({name:t,payload:a}),s.length>=e.batchSize?h():u(),void(n&&n.postMessage({name:t,payload:a}));const r=performance.now();try{(o.get(t)||[]).forEach((e=>e(a))),n&&n.postMessage({name:t,payload:a})}catch(s){e.errorHandler({...s,eventName:t,payload:a})}c(t,performance.now()-r)},getMetrics:()=>({totalEvents:a,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:i,averageEmitDuration:a>0?r/a:0}),clear:()=>{t.clear(),o.clear(),s=[],a=0,r=0,i.clear(),n&&(n.close(),n=null)}}}}},function(){return t||(0,e[i(e)[0]])((t={exports:{}}).exports,t),t.exports});((e,t,c)=>{c=null!=e?s(o(e)):{},((e,t,s,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of i(t))n.call(e,c)||c===s||a(e,c,{get:()=>t[c],enumerable:!(o=r(t,c))||o.enumerable})})(e&&e.__esModule?c:a(c,"default",{value:e,enumerable:!0}),e)})(c());var h=class e extends Error{code;status;data;isRetryable;originalError;constructor(e,t){super(e.message),this.name="StoreError",this.code=e.code,this.status=e.status,this.data=e.data,this.isRetryable=e.isRetryable,this.originalError=t}static fromError(t,s){if(t.isAbort||"AbortError"===t.name)return new e({code:"ABORTED",message:"Request was cancelled",isRetryable:!1},t);if("NetworkError"===t.name||!navigator.onLine)return new e({code:"NETWORK_ERROR",message:"Network connection failed. Please check your internet connection.",isRetryable:!0},t);if(t.status)switch(t.status){case 400:return new e({code:"VALIDATION_ERROR",message:t.message||"Invalid request data",status:400,data:t.data,isRetryable:!1},t);case 401:return new e({code:"UNAUTHORIZED",message:"Authentication required or invalid credentials",status:401,isRetryable:!1},t);case 403:return new e({code:"FORBIDDEN",message:"Access denied for this resource",status:403,isRetryable:!1},t);case 404:return new e({code:"NOT_FOUND",message:"Resource not found",status:404,isRetryable:!1},t);case 409:return new e({code:"CONFLICT",message:t.message||"Resource conflict occurred",status:409,isRetryable:!1},t);case 429:return new e({code:"RATE_LIMITED",message:"Too many requests. Please try again later.",status:429,isRetryable:!0},t);case 500:case 502:case 503:case 504:return new e({code:"SERVER_ERROR",message:"Server error occurred. Please try again later.",status:t.status,isRetryable:!0},t);default:return new e({code:"HTTP_ERROR",message:t.message||`HTTP ${t.status} error occurred`,status:t.status,isRetryable:t.status>=500},t)}return"TimeoutError"===t.name||"TIMEOUT"===t.code?new e({code:"TIMEOUT",message:"Request timed out. Please try again.",isRetryable:!0},t):new e({code:"UNKNOWN_ERROR",message:t.message||`Unknown error occurred during ${s}`,isRetryable:!0},t)}};function u(e,t=new WeakMap){return void 0===e?"undefined":"function"==typeof e||"symbol"==typeof e?"":"string"==typeof e?`"${e}"`:"number"==typeof e||"boolean"==typeof e||null===e?String(e):Array.isArray(e)?`[${e.map((e=>u(e,t))).join(",")}]`:"object"==typeof e?t.has(e)?'"__circular__"':(t.set(e,!0),`{${Object.keys(e).sort().map((s=>`"${s}":${u(e[s],t)}`)).join(",")}}`):""}function l(e){let t=3421674724,s=2216829733;const a=u(e);for(let e=0;e<a.length;e++){s^=a.charCodeAt(e);const r=Math.imul(s,435),i=Math.imul(s,435)+Math.imul(t,435);s=r>>>0,t=i>>>0}return(t>>>0).toString(16)+(s>>>0).toString(16)}var d=class{constructor(e,t,s){this.operation=e,this.params=t,this.currentResult=s,this.currentResultHash=l(s),this.defaultResult=s}currentResult;currentResultHash;subscribers=new Set;defaultResult;idle=!1;getResult(){return this.currentResult}getParams(){return this.params}getOperation(){return this.operation}updateParams(e){this.params=e}reset(){this.currentResult=this.defaultResult,this.currentResultHash=l(this.defaultResult),this.notifySubscribers(),this.idle=!0}updateResult(e,t=!1){if(this.idle&&!t)return;this.idle=!1;const s=l(e);this.currentResultHash!==s&&(this.currentResult=e,this.currentResultHash=s,this.notifySubscribers())}subscribe(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}notifySubscribers(){this.subscribers.forEach((e=>{try{e()}catch(e){console.error("QueryState: Subscriber callback error:",e)}}))}hasSubscribers(){return this.subscribers.size>0}},p=class{constructor(e,t,s,a){if(this.cache=e,this.baseStore=t,this.correlator=s,this.storeEventCorrelator=a,this.storeEventCorrelator){queueMicrotask((async()=>{this.unsubscribeFromBaseStore=await this.baseStore.subscribe("*",this.handleStoreEvent.bind(this))}))}this.setupCacheEventListeners()}queryStates=new Map;stableResults=new Map;stablePaginationMethods=new Map;errorCache=new Map;keyCache=new WeakMap;unsubscribeFromBaseStore;cacheEventCleanups=new Set;setupCacheEventListeners(){["cache:fetch:success","cache:fetch:error","cache:data:set","cache:data:invalidate","cache:read:hit"].forEach((e=>{const t=this.cache.on(e,(e=>{this.handleCacheEvent(e)}));this.cacheEventCleanups.add(t)}))}handleCacheEvent(e){const t=this.queryStates.get(e.key);if(t){const s=this.computeResult(e.key);t.updateResult(s)}}buildKey(e,t){if("object"==typeof t&&null!==t&&this.keyCache.has(t))return this.keyCache.get(t);const s=`${e}:${l(t)}`;return"object"==typeof t&&null!==t&&this.keyCache.set(t,s),s}getOrCreateError(e){if(this.errorCache.has(e))return this.errorCache.get(e);const t=new Error(e);return this.errorCache.set(e,t),t}getOrCreateStoreError(e){const t=`store:${e}`;if(this.errorCache.has(t))return this.errorCache.get(t);const s=h.fromError(new Error(e),"query");return this.errorCache.set(t,s),s}computeResult(e){const t=this.cache.getStats().entries.find((t=>t.key===e)),s=this.cache.peek(e);this.scheduleBackgroundFetch(e,t,s);if("read"===e.split(":")[0])return{data:s,loading:t?.isLoading??void 0===s,error:t?.error?this.getOrCreateError("Query failed"):void 0,stale:t?.isStale??!0,updated:t?.lastUpdated??0};{const a=this.getCurrentPageForQuery(e),r=this.getOrCreatePaginationMethods(e);return{page:s,loading:t?.isLoading??void 0===s,error:t?.error?this.getOrCreateStoreError("Query failed"):void 0,stale:t?.isStale??!0,updated:t?.lastUpdated??0,hasNext:!!s&&a<s.page.pages,hasPrevious:a>1,...r}}}scheduleBackgroundFetch(e,t,s){t?.isStale&&!t?.isLoading&&queueMicrotask((()=>{this.cache.get(e,{waitForFresh:!1}).catch((t=>{console.warn(`ReactiveRemoteStore: Background refetch failed for ${e}:`,t)}))})),void 0!==s||this.cache.has(e)||t?.isLoading||queueMicrotask((()=>{this.cache.get(e,{waitForFresh:!1}).catch((t=>{console.warn(`ReactiveRemoteStore: Background fetch failed for ${e}:`,t)}))}))}getCurrentPageForQuery(e){const t=this.queryStates.get(e);if(t){return t.getParams().page||1}return 1}getOrCreatePaginationMethods(e){if(this.stablePaginationMethods.has(e))return this.stablePaginationMethods.get(e);const t=this.queryStates.get(e);if(!t)throw new Error(`QueryState not found for ${e}`);const s=t.getOperation(),a={next:async()=>{const a=t.getParams(),r=a.page||1,i=this.buildKey(s,a),o=this.cache.peek(i);if(o&&r<o.page.pages){const i={...a,page:r+1},o=this.buildKey(s,i);if(!this.cache.has(o)){const e="list"===s?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(o,(()=>e(i)))}t.updateParams(i),await this.cache.get(o,{waitForFresh:!0});const n=this.computeResultForParams(s,i,e);t.updateResult(n)}},previous:async()=>{const a=t.getParams(),r=a.page||1;if(r>1){const i={...a,page:r-1},o=this.buildKey(s,i);if(!this.cache.has(o)){const e="list"===s?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(o,(()=>e(i)))}t.updateParams(i),await this.cache.get(o,{waitForFresh:!0});const n=this.computeResultForParams(s,i,e);t.updateResult(n)}},navigate:async a=>{if(a<1)return;const r={...t.getParams(),page:a},i=this.buildKey(s,r);if(!this.cache.has(i)){const e="list"===s?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(i,(()=>e(r)))}t.updateParams(r),await this.cache.get(i,{waitForFresh:!0});const o=this.computeResultForParams(s,r,e);t.updateResult(o)},refresh:async(s=1e3)=>{const a=t.getParams(),r=this.buildKey(t.getOperation(),a);t.reset();const i=this.cache.refresh(r),o=new Promise((e=>setTimeout(e,s)));await Promise.all([i,o]);const n=this.computeResultForParams(t.getOperation(),t.getParams(),e);t.updateResult(n,!0)},changeParams:async s=>{const a=s(t.getParams());if(!a)return void console.error("Setter function for changeParams must return a new parameters object.");const r=this.buildKey(t.getOperation(),a);if(!this.cache.has(r)){const e="list"===t.getOperation()?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(r,(()=>e(a)))}t.updateParams(a),await this.cache.get(r,{waitForFresh:!0});const i=this.computeResultForParams(t.getOperation(),a,e);t.updateResult(i)}};return this.stablePaginationMethods.set(e,a),a}computeResultForParams(e,t,s){const a=this.buildKey(e,t),r=this.cache.getStats().entries.find((e=>e.key===a)),i=this.cache.peek(a);if("read"===e)return{data:i,loading:r?.isLoading??void 0===i,error:r?.error?this.getOrCreateError("Query failed"):void 0,stale:r?.isStale??!0,updated:r?.lastUpdated??0};{const e=t.page||1,a=this.stablePaginationMethods.get(s)??{};return{page:i,loading:r?.isLoading??void 0===i,error:r?.error?this.getOrCreateStoreError("Query failed"):void 0,stale:r?.isStale??!0,updated:r?.lastUpdated??0,hasNext:!!i&&e<i.page.pages,hasPrevious:e>1,...a}}}hasActiveQuery(e,t){const s=this.buildKey(e,t);return this.stableResults.has(s)}getActiveQuery(e,t){const s=this.buildKey(e,t);return this.stableResults.get(s)}read(e){const t=this.buildKey("read",e);if(this.stableResults.has(t))return this.stableResults.get(t);this.cache.has(t)||this.cache.registerQuery(t,(async()=>await this.baseStore.read(e)));const s=this.computeResult(t),a=new d("read",e,s);this.queryStates.set(t,a);const r={value:()=>a.getResult(),onValueChange:e=>{const t=a.subscribe(e);return()=>{t()}}};return this.stableResults.set(t,r),r}list(e){return this.setupPagedQuery("list",e)}find(e){return this.setupPagedQuery("find",e)}setupPagedQuery(e,t){const s=this.buildKey(e,t);if(this.stableResults.has(s))return this.stableResults.get(s);if(!this.cache.has(s)){const a="list"===e?this.baseStore.list.bind(this.baseStore):this.baseStore.find.bind(this.baseStore);this.cache.registerQuery(s,(()=>a(t)))}const a=this.cache.peek(s),r=new d(e,t,{page:a,loading:void 0===a,error:void 0,stale:!0,updated:0,hasNext:!1,hasPrevious:!1});this.queryStates.set(s,r);const i=this.computeResult(s);r.updateResult(i);const o={value:()=>r.getResult(),onValueChange:e=>{const t=r.subscribe(e);return()=>{t()}}};return this.stableResults.set(s,o),o}async invalidateQueries(e){if(this.correlator){const t=Array.from(this.queryStates.values()).map((e=>({queryKey:this.buildKey(e.getOperation(),e.getParams()),operation:e.getOperation(),params:e.getParams()}))),s=this.correlator(e,t).map((e=>this.cache.invalidate(e)));await Promise.all(s)}else await this.cache.invalidatePattern(/^list:/),await this.cache.invalidatePattern(/^find:/)}handleStoreEvent(e){if(this.storeEventCorrelator){const t=Array.from(this.queryStates.values()).map((e=>({queryKey:this.buildKey(e.getOperation(),e.getParams()),operation:e.getOperation(),params:e.getParams()})));this.storeEventCorrelator(e,t).forEach((e=>this.cache.invalidate(e)))}}async create(e){try{const t=await this.baseStore.create(e);return t&&(this.cache.setData(this.buildKey("read",{id:t.id}),t),await this.invalidateQueries({operation:"create",params:e})),t}catch(e){throw console.error("ReactiveRemoteStore: Create operation failed:",e),e}}async update(e){try{const t=await this.baseStore.update(e);return t&&await this.invalidateQueries({operation:"update",params:e}),t}catch(e){throw console.error("ReactiveRemoteStore: Update operation failed:",e),e}}async delete(e){try{await this.baseStore.delete(e),await this.invalidateQueries({operation:"delete",params:e})}catch(e){throw console.error("ReactiveRemoteStore: Delete operation failed:",e),e}}async notify(e){return this.baseStore.notify(e)}stream(e,t){return this.baseStore.stream(e,t)}async subscribe(e,t){return this.baseStore.subscribe(e,t)}async upload(e){try{const t=await this.baseStore.upload(e);return t&&(this.cache.setData(this.buildKey("read",{id:t.id}),t),await this.invalidateQueries({operation:"upload",params:e})),t}catch(e){throw console.error("ReactiveRemoteStore: Upload operation failed:",e),e}}async refresh(e,t){const s=this.buildKey(e,t);return this.cache.refresh(s)}prefetch(e,t){const s=this.buildKey(e,t);this.cache.prefetch(s).catch((e=>{console.warn(`ReactiveRemoteStore: Prefetch failed for ${s}:`,e)}))}async invalidate(e,t){const s=this.buildKey(e,t);await this.cache.invalidate(s)}async invalidateAll(){const e=Array.from(this.queryStates.keys()).map((e=>this.cache.invalidate(e)));await Promise.all(e)}getStats(){return{...this.cache.getStats(),activeSubscriptions:this.queryStates.size}}destroy(){this.cacheEventCleanups.forEach((e=>e())),this.cacheEventCleanups.clear(),this.queryStates.clear(),this.stableResults.clear(),this.stablePaginationMethods.clear(),this.errorCache.clear(),this.keyCache=new WeakMap,this.unsubscribeFromBaseStore&&this.unsubscribeFromBaseStore()}};export{p as ReactiveRemoteStore,h as StoreError,l as hash};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asaidimu/utils-remote-store",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "A reactive store for remote data, built on top of @asaidimu/utils-cache",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"./*"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@asaidimu/utils-cache": "2.1.
|
|
12
|
+
"@asaidimu/utils-cache": "2.1.2",
|
|
13
13
|
"eventsource": "^4.0.0"
|
|
14
14
|
},
|
|
15
15
|
"exports": {
|