qortex-core 0.2.8 → 0.3.0-beta.1

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.
Files changed (4) hide show
  1. package/index.d.ts +121 -4
  2. package/index.js +13 -12
  3. package/index.mjs +2 -2
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1,3 +1,115 @@
1
+ /**
2
+ * Internal query state that tracks all aspects of a query's lifecycle
3
+ * Used internally by QueryManager for state management
4
+ * NOT EXPORTED - internal implementation detail
5
+ */
6
+ type QueryStateInternal<T = any, E = unknown> = {
7
+ data?: T;
8
+ error?: E;
9
+ status: QueryStatus;
10
+ updatedAt?: number;
11
+ staleTime: number;
12
+ isInvalidated: boolean;
13
+ fetcher?: Fetcher<T> | null;
14
+ equalityFn: EqualityFn<T>;
15
+ equalityStrategy: EqualityStrategy;
16
+ placeholderData?: T;
17
+ usePreviousDataOnError?: boolean;
18
+ usePlaceholderOnError?: boolean;
19
+ refetchOnSubscribe: "always" | "stale" | false;
20
+ enabled: boolean;
21
+ lastFetchTime?: number;
22
+ fetchPromise?: Promise<T> | T;
23
+ refetch?: () => Promise<T>;
24
+ isSuccess: boolean;
25
+ isError: boolean;
26
+ lastReturnedState?: QueryState<T>;
27
+ };
28
+
29
+ type SerializedQueryState = Omit<QueryStateInternal, 'fetcher' | 'fetchPromise' | 'refetch' | 'equalityFn'>;
30
+ /**
31
+ * Persister configuration
32
+ */
33
+ interface PersisterConfig {
34
+ burstKey?: string;
35
+ prefix?: string;
36
+ debounceTime?: number;
37
+ }
38
+
39
+ /**
40
+ * Base persister implementation
41
+ */
42
+ declare class BasePersister {
43
+ protected readonly storage: Storage;
44
+ private syncTimeout;
45
+ private debounceTime;
46
+ private burstKey;
47
+ private storageKey;
48
+ constructor(storage: Storage, config?: PersisterConfig);
49
+ /**
50
+ * Save state to storage
51
+ */
52
+ save(state: Record<string, SerializedQueryState>): void;
53
+ /**
54
+ * Load state from storage and hydrate cache
55
+ */
56
+ load(cache: Map<string, QueryStateInternal>, hasQueriesBeenUsed: boolean): void;
57
+ /**
58
+ * Clear all persisted data
59
+ */
60
+ clear(): void;
61
+ /**
62
+ * Sync with debounced save (100ms delay)
63
+ * Handles serialization internally
64
+ */
65
+ sync(cache: Map<string, QueryStateInternal>): void;
66
+ }
67
+ type Persister = BasePersister;
68
+
69
+ /**
70
+ * Creates a persister instance for data persistence.
71
+ *
72
+ * This factory function creates a persister that can save and load query state data
73
+ * to/from browser storage (localStorage or sessionStorage). The persister handles
74
+ * serialization, validation, burst key management, and debounced syncing automatically.
75
+ *
76
+ * @param {'local' | 'session'} type - The type of storage to use
77
+ * - `'local'`: Uses localStorage for persistent data across browser sessions
78
+ * - `'session'`: Uses sessionStorage for data that persists only during the current session
79
+ * @param {PersisterConfig} [config] - Optional configuration for the persister
80
+ * @returns {Persister | undefined} A persister instance, or undefined if storage is not available
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // Basic usage with localStorage
85
+ * const persister = createPersister('local');
86
+ *
87
+ * // With custom configuration
88
+ * const persister = createPersister('local', {
89
+ * burstKey: 'v1.0.0',
90
+ * prefix: 'my_app',
91
+ * debounceTime: 50
92
+ * });
93
+ *
94
+ * // Use with query manager
95
+ * setDefaultConfig({ persister });
96
+ * ```
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * // Session storage for temporary data
101
+ * const sessionPersister = createPersister('session', {
102
+ * prefix: 'temp_data',
103
+ * debounceTime: 200
104
+ * });
105
+ *
106
+ * setDefaultConfig({ persister: sessionPersister });
107
+ * ```
108
+ *
109
+ * @throws {Error} If an invalid storage type is provided
110
+ */
111
+ declare const createPersister: (type: "local" | "session", config?: PersisterConfig) => BasePersister | undefined;
112
+
1
113
  /**
2
114
  * Query key can be a string or readonly array of strings/numbers
3
115
  * Using readonly to prevent accidental mutations
@@ -32,13 +144,14 @@ type InferFetcherResult<F> = F extends Fetcher<infer R> ? R : any;
32
144
  * Query status types for better type safety
33
145
  */
34
146
  type QueryStatus = "idle" | "fetching" | "success" | "error";
147
+ type RefetchOnSubscribeOptions = "always" | "stale" | false;
35
148
  /**
36
149
  * Comprehensive options for all query operations
37
150
  * Improved with better type constraints
38
151
  */
39
152
  type QueryOptions<T = any> = {
40
153
  enabled?: boolean;
41
- refetchOnSubscribe?: "always" | "stale" | false;
154
+ refetchOnSubscribe?: RefetchOnSubscribeOptions;
42
155
  fetcher?: Fetcher<T>;
43
156
  equalityFn?: EqualityFn<T>;
44
157
  equalityStrategy?: EqualityStrategy;
@@ -54,13 +167,14 @@ type QueryOptions<T = any> = {
54
167
  */
55
168
  type DefaultConfig = {
56
169
  enabled?: boolean;
57
- refetchOnSubscribe?: "always" | "stale" | false;
170
+ refetchOnSubscribe?: RefetchOnSubscribeOptions;
58
171
  staleTime?: number;
59
172
  usePreviousDataOnError?: boolean;
60
173
  usePlaceholderOnError?: boolean;
61
174
  equalityFn?: EqualityFn<any>;
62
175
  equalityStrategy?: EqualityStrategy;
63
176
  throttleTime?: number;
177
+ persister?: Persister;
64
178
  };
65
179
  /**
66
180
  * Public query state returned by getQueryState
@@ -89,6 +203,8 @@ declare class QueryManagerCore {
89
203
  private subs;
90
204
  private defaultConfig;
91
205
  private throttleTime;
206
+ private persister;
207
+ private hasQueriesBeenUsed;
92
208
  /**
93
209
  * ⚠️ DANGER: Clear all cached data and subscriptions
94
210
  *
@@ -96,6 +212,7 @@ declare class QueryManagerCore {
96
212
  * - All cached query data
97
213
  * - All active subscriptions
98
214
  * - All state references
215
+ * - All persisted data
99
216
  *
100
217
  * @warning This should ONLY be used in testing environments or when you need to completely reset the query manager state. Using this in production will cause all active queries to lose their data and subscriptions to break.
101
218
  *
@@ -114,7 +231,7 @@ declare class QueryManagerCore {
114
231
  /**
115
232
  * Set default configuration for all queries
116
233
  */
117
- setDefaultConfig({ throttleTime, ...config }: DefaultConfig): void;
234
+ setDefaultConfig({ throttleTime, persister, ...config }: DefaultConfig): void;
118
235
  /**
119
236
  * Ensures a query state exists in cache, creating it if necessary
120
237
  * User-friendly with any fallback for better developer experience
@@ -201,4 +318,4 @@ declare const dangerClearCache: QueryManagerCore["dangerClearCache"];
201
318
  */
202
319
  declare function serializeKey(key: QueryKey): string;
203
320
 
204
- export { DefaultConfig, EqualityFn, EqualityStrategy, Fetcher, InferFetcherResult, QueryKey, QueryManagerCore, QueryOptions, QueryState, QueryStatus, _queryManager, dangerClearCache, fetchQuery, getQueryData, getQueryState, invalidateQuery, registerFetcher, serializeKey, setDefaultConfig, setQueryData, subscribeQuery };
321
+ export { DefaultConfig, EqualityFn, EqualityStrategy, Fetcher, InferFetcherResult, Persister, PersisterConfig, QueryKey, QueryManagerCore, QueryOptions, QueryState, QueryStatus, RefetchOnSubscribeOptions, _queryManager, createPersister, dangerClearCache, fetchQuery, getQueryData, getQueryState, invalidateQuery, registerFetcher, serializeKey, setDefaultConfig, setQueryData, subscribeQuery };
package/index.js CHANGED
@@ -1,16 +1,17 @@
1
1
  'use strict';
2
2
 
3
- function c(t){return Array.isArray(t)?t.join(","):String(t)}function y(t,r,a="shallow"){if(t===r)return !0;if(t==null||r==null)return t===r;if(typeof t!="object"||typeof r!="object")return !1;try{let e=t,n=r;if(Array.isArray(e)&&Array.isArray(n)){if(e.length!==n.length)return !1;for(let o=0;o<e.length;o++)if(a==="deep"){if(!y(e[o],n[o],a))return !1}else if(e[o]!==n[o])return !1;return !0}if(Array.isArray(e)||Array.isArray(n))return !1;let s=Object.keys(e),u=Object.keys(n);if(s.length!==u.length)return !1;for(let o=0;o<s.length;o++){let l=s[o];if(a==="deep"){if(!y(e[l],n[l],a))return !1}else if(e[l]!==n[l])return !1}return !0}catch{return !1}}function g(t,r){return r||((a,e)=>y(a,e,t||"shallow"))}function h(t,r){return {status:"idle",updatedAt:void 0,staleTime:t?.staleTime??0,isInvalidated:!1,fetcher:t?.fetcher,equalityFn:g(t?.equalityStrategy,t?.equalityFn),equalityStrategy:t?.equalityStrategy??"shallow",placeholderData:t?.placeholderData,usePreviousDataOnError:t?.usePreviousDataOnError??!1,usePlaceholderOnError:t?.usePlaceholderOnError??!1,refetchOnSubscribe:t?.refetchOnSubscribe??"stale",enabled:t?.enabled!==!1,refetch:r||(()=>Promise.resolve(void 0)),isSuccess:!1,isError:!1,lastReturnedState:void 0}}function d(t){let r=Date.now(),a=t.updatedAt!==void 0&&r-t.updatedAt>t.staleTime||t.isInvalidated,e,n=!1;switch(t.status){case"error":t.usePreviousDataOnError&&t.data!==void 0?e=t.data:t.usePlaceholderOnError&&t.placeholderData!==void 0&&(e=t.placeholderData,n=!0);break;case"fetching":t.data!==void 0?(e=t.data,n=!1):t.placeholderData&&(e=t.placeholderData,n=!0);break;case"success":case"idle":e=t.data??t.placeholderData,n=t.data?!1:!!t.placeholderData;break}return {data:e,error:t.error,status:t.status,updatedAt:t.updatedAt,isStale:a,isPlaceholderData:n,isLoading:t.status==="fetching"&&!t.updatedAt,isFetching:t.status==="fetching",isError:t.isError,isSuccess:t.isSuccess,refetch:t.refetch}}function Q(t){console.warn(`[qortex] No fetcher or data for key "${c(t)}". Register a fetcher or set initial data.`);}var f=class{constructor(){this.cache=new Map;this.subs=new Map;this.defaultConfig={};this.throttleTime=50;}dangerClearCache(){this.cache.clear(),this.subs.clear();}setDefaultConfig({throttleTime:r,...a}){this.defaultConfig={...this.defaultConfig,...a},r!==void 0&&(this.throttleTime=r);}ensureState(r,a={}){let e=c(r),n=this.cache.get(e);if(n){let s={...this.defaultConfig,...n,...a};Object.assign(n,s),n.enabled=s.enabled!==!1,this.cache.set(e,n);}else {let s={...this.defaultConfig,...a},u=h(s,()=>this.fetchQuery(r));this.cache.set(e,u);}return this.cache.get(e)}emit(r,a){let e=c(r);this.cache.set(e,a);let n=this.subs.get(e);if(!n)return;let s=d(a);for(let u of Array.from(n))u(s);}registerFetcher(r,a){let e=this.ensureState(r,a);this.handleMountLogic(r,e);}fetchQuery(r,a){let e=this.ensureState(r,a);if(e.fetchPromise)return e.fetchPromise;let n=e.fetcher;if(!n)return e.updatedAt===void 0&&Q(r),Promise.resolve(e.data);let s=n();return e.fetchPromise=s,e.status="fetching",e.lastFetchTime=Date.now(),this.emit(r,e),s.then(u=>{e.data=e.equalityFn(e.data,u)?e.data:u,e.status="success",e.isError=!1,e.isSuccess=!0,e.updatedAt=Date.now(),e.fetchPromise=void 0,e.error=void 0,this.emit(r,e);}).catch(u=>{e.error=u,e.status="error",e.isError=!0,e.isSuccess=!1,e.updatedAt=Date.now(),e.fetchPromise=void 0,this.emit(r,e);}),s}setQueryData(r,a){let e=this.ensureState(r),n=e.data;e.equalityFn(n,a)||(e.data=a,e.updatedAt=Date.now(),e.error=void 0,e.status="success",e.isInvalidated=!1,e.isError=!1,e.isSuccess=!0,this.emit(r,e));}getQueryData(r,a){let e=this.ensureState(r,a);return this.handleMountLogic(r,e),d(e).data}getQueryState(r,a){let e=this.ensureState(r,a);this.handleMountLogic(r,e);let n=d(e),s=e.lastReturnedState;return !s||!y(s,n,"shallow")?(e.lastReturnedState=n,n):s}invalidateQuery(r){let a=this.ensureState(r);a.isInvalidated=!0,this.emit(r,a),this.fetchQuery(r);}subscribeQuery(r,a,e){let n=c(r),s=this.ensureState(r,e);return this.subs.has(n)||this.subs.set(n,new Set),this.subs.get(n).add(a),this.handleMountLogic(r,s),()=>{this.subs.get(n).delete(a);}}handleMountLogic(r,a){let e=a.lastFetchTime&&Date.now()-a.lastFetchTime<this.throttleTime;if(a.status==="fetching"||!a.enabled||e||!a.fetcher)return;let n=Date.now(),s=a.updatedAt==null||n-(a.updatedAt||0)>a.staleTime||a.isInvalidated,u=!1;a.updatedAt==null?u=!0:(a.refetchOnSubscribe==="always"&&(u=!0),a.refetchOnSubscribe==="stale"&&(u=s)),u&&this.fetchQuery(r);}},p=f;var i=new p,v=i.registerFetcher.bind(i),O=i.fetchQuery.bind(i),K=i.setQueryData.bind(i),C=i.getQueryData.bind(i),w=i.getQueryState.bind(i),x=i.invalidateQuery.bind(i),A=i.subscribeQuery.bind(i),E=i.setDefaultConfig.bind(i),I=i.dangerClearCache.bind(i);
3
+ function c(e){return Array.isArray(e)?e.join(","):String(e)}function y(e,r,s="shallow"){if(e===r)return !0;if(e==null||r==null)return e===r;if(typeof e!="object"||typeof r!="object")return !1;try{let t=e,a=r;if(Array.isArray(t)&&Array.isArray(a)){if(t.length!==a.length)return !1;for(let u=0;u<t.length;u++)if(s==="deep"){if(!y(t[u],a[u],s))return !1}else if(t[u]!==a[u])return !1;return !0}if(Array.isArray(t)||Array.isArray(a))return !1;let i=Object.keys(t),o=Object.keys(a);if(i.length!==o.length)return !1;for(let u=0;u<i.length;u++){let l=i[u];if(s==="deep"){if(!y(t[l],a[l],s))return !1}else if(t[l]!==a[l])return !1}return !0}catch{return !1}}function p(e,r){return r||((s,t)=>y(s,t,e||"shallow"))}function Q(e,r){return {status:"idle",updatedAt:void 0,staleTime:e?.staleTime??0,isInvalidated:!1,fetcher:e?.fetcher,equalityFn:p(e?.equalityStrategy,e?.equalityFn),equalityStrategy:e?.equalityStrategy??"shallow",placeholderData:e?.placeholderData,usePreviousDataOnError:e?.usePreviousDataOnError??!1,usePlaceholderOnError:e?.usePlaceholderOnError??!1,refetchOnSubscribe:e?.refetchOnSubscribe??"stale",enabled:e?.enabled!==!1,refetch:r||(()=>Promise.resolve(void 0)),isSuccess:!1,isError:!1,lastReturnedState:void 0}}function f(e){let r=Date.now(),s=e.updatedAt!==void 0&&r-e.updatedAt>e.staleTime||e.isInvalidated,t,a=!1;switch(e.status){case"error":e.usePreviousDataOnError&&e.data!==void 0?t=e.data:e.usePlaceholderOnError&&e.placeholderData!==void 0&&(t=e.placeholderData,a=!0);break;case"fetching":e.data!==void 0?(t=e.data,a=!1):e.placeholderData&&(t=e.placeholderData,a=!0);break;case"success":case"idle":t=e.data??e.placeholderData,a=e.data?!1:!!e.placeholderData;break}return {data:t,error:e.error,status:e.status,updatedAt:e.updatedAt,isStale:s,isPlaceholderData:a,isLoading:e.status==="fetching"&&!e.updatedAt,isFetching:e.status==="fetching",isError:e.isError,isSuccess:e.isSuccess,refetch:e.refetch}}function S(e){console.warn(`[qortex] No fetcher or data for key "${c(e)}". Register a fetcher or set initial data.`);}var d=class{constructor(){this.cache=new Map;this.subs=new Map;this.defaultConfig={};this.throttleTime=50;this.persister=null;this.hasQueriesBeenUsed=!1;}dangerClearCache(){this.cache.clear(),this.subs.clear(),this.persister?.clear();}setDefaultConfig({throttleTime:r,persister:s,...t}){this.defaultConfig={...this.defaultConfig,...t},r!==void 0&&(this.throttleTime=r),s&&(this.persister=s,this.persister?.load(this.cache,this.hasQueriesBeenUsed));}ensureState(r,s={}){this.hasQueriesBeenUsed=!0;let t=c(r),a=this.cache.get(t);if(a){let i={...this.defaultConfig,...a,...s};Object.assign(a,i),a.enabled=i.enabled!==!1,this.cache.set(t,a);}else {let i={...this.defaultConfig,...s},o=Q(i,()=>this.fetchQuery(r));this.cache.set(t,o);}return this.cache.get(t)}emit(r,s){let t=c(r);this.cache.set(t,s),this.persister?.sync(this.cache);let a=this.subs.get(t);if(!a)return;let i=f(s);for(let o of Array.from(a))o(i);}registerFetcher(r,s){let t=this.ensureState(r,s);this.handleMountLogic(r,t);}fetchQuery(r,s){let t=this.ensureState(r,s);if(t.fetchPromise)return t.fetchPromise;let a=t.fetcher;if(!a)return t.updatedAt===void 0&&S(r),Promise.resolve(t.data);let i=a();return t.fetchPromise=i,t.status="fetching",t.lastFetchTime=Date.now(),this.emit(r,t),i.then(o=>{t.data=t.equalityFn(t.data,o)?t.data:o,t.status="success",t.isError=!1,t.isSuccess=!0,t.updatedAt=Date.now(),t.fetchPromise=void 0,t.error=void 0,this.emit(r,t);}).catch(o=>{t.error=o,t.status="error",t.isError=!0,t.isSuccess=!1,t.updatedAt=Date.now(),t.fetchPromise=void 0,this.emit(r,t);}),i}setQueryData(r,s){let t=this.ensureState(r),a=t.data;t.equalityFn(a,s)||(t.data=s,t.updatedAt=Date.now(),t.error=void 0,t.status="success",t.isInvalidated=!1,t.isError=!1,t.isSuccess=!0,this.emit(r,t));}getQueryData(r,s){let t=this.ensureState(r,s);return this.handleMountLogic(r,t),f(t).data}getQueryState(r,s){let t=this.ensureState(r,s);this.handleMountLogic(r,t);let a=f(t),i=t.lastReturnedState;return !i||!y(i,a,"shallow")?(t.lastReturnedState=a,a):i}invalidateQuery(r){let s=this.ensureState(r);s.isInvalidated=!0,this.emit(r,s),this.fetchQuery(r);}subscribeQuery(r,s,t){let a=c(r),i=this.ensureState(r,t);return this.subs.has(a)||this.subs.set(a,new Set),this.subs.get(a).add(s),this.handleMountLogic(r,i),()=>{this.subs.get(a).delete(s);}}handleMountLogic(r,s){let t=s.lastFetchTime&&Date.now()-s.lastFetchTime<this.throttleTime;if(s.status==="fetching"||!s.enabled||t||!s.fetcher)return;let a=Date.now(),i=s.updatedAt==null||a-(s.updatedAt||0)>s.staleTime||s.isInvalidated,o=!1;s.updatedAt==null?o=!0:(s.refetchOnSubscribe==="always"&&(o=!0),s.refetchOnSubscribe==="stale"&&(o=i)),o&&this.fetchQuery(r);}},g=d;var n=new g,k=n.registerFetcher.bind(n),j=n.fetchQuery.bind(n),N=n.setQueryData.bind(n),L=n.getQueryData.bind(n),B=n.getQueryState.bind(n),U=n.invalidateQuery.bind(n),J=n.subscribeQuery.bind(n),_=n.setDefaultConfig.bind(n),V=n.dangerClearCache.bind(n);function P(e){return typeof e=="string"&&["idle","fetching","success","error"].includes(e)}function K(e){return typeof e=="string"&&["shallow","deep"].includes(e)}function O(e){return e===!1||typeof e=="string"&&["always","stale"].includes(e)}function D(e){return !(!e||typeof e!="object"||!P(e.status)||typeof e.staleTime!="number"||e.staleTime<0||typeof e.isInvalidated!="boolean"||!K(e.equalityStrategy)||!O(e.refetchOnSubscribe))}function m(e){if(!e||typeof e!="object"||!e.entries||typeof e.entries!="object")return !1;for(let[r,s]of Object.entries(e.entries))if(typeof r!="string"||!D(s))return !1;return !(typeof e.burstKey!="string"||typeof e.timestamp!="number"||e.timestamp<0)}function b(e){let{fetcher:r,equalityFn:s,fetchPromise:t,refetch:a,...i}=e;return i}function T(e,r){let s={...r??{},...e};return {...s,equalityFn:r?.equalityFn||p(s.equalityStrategy)}}function F(e){try{let r=JSON.parse(e);return m(r)?r:null}catch{return null}}var v=()=>{console.warn("[Qortex] No storage found, persister will not be able to persist data");},w=()=>{console.warn("[Qortex] Persister is being set after queries have been used. This may cause data inconsistency. It is recommended to set the persister before any query usage.");};var h=class{constructor(r,s){this.syncTimeout=null;this.debounceTime=100;this.burstKey="0.3.0";this.storageKey="qortex";this.storage=r,this.burstKey=s?.burstKey??this.burstKey,this.storageKey=s?.prefix??this.storageKey,this.debounceTime=s?.debounceTime??this.debounceTime;}save(r){try{let s={entries:{},burstKey:this.burstKey,timestamp:Date.now()};for(let[a,i]of Object.entries(r))s.entries[a]=i;let t=JSON.stringify(s);this.storage.setItem(this.storageKey,t);}catch(s){console.warn("[Qortex] Failed to persist state:",s);}}load(r,s){s&&w();try{let t=this.storage.getItem(this.storageKey);if(!t)return;let a=F(t);if(!a){console.warn("[Qortex] Invalid persisted state format, clearing cache"),this.clear();return}if(a.burstKey!==this.burstKey){console.warn("[Qortex] Burst key mismatch, clearing cache"),this.clear();return}for(let[i,o]of Object.entries(a.entries)){let u=o,l=r.get(i),x=T(u,l);r.set(i,x);}}catch(t){console.warn("[Qortex] Failed to load persisted state:",t),this.clear();}}clear(){try{this.storage.removeItem(this.storageKey);}catch(r){console.warn("[Qortex] Failed to clear persisted data:",r);}}sync(r){this.syncTimeout&&clearTimeout(this.syncTimeout),this.syncTimeout=setTimeout(()=>{let s={};for(let[t,a]of r.entries())s[t]=b(a);this.save(s);},this.debounceTime);}};var I=e=>{switch(e){case"local":if(typeof localStorage<"u")return window.localStorage;break;case"session":if(typeof sessionStorage<"u")return window.sessionStorage;break;default:throw new Error(`Invalid storage type: ${e}`)}},C=(e,r)=>{let s=I(e);if(!s){v();return}return new h(s,r)};
4
4
 
5
- exports.QueryManagerCore = f;
6
- exports._queryManager = i;
7
- exports.dangerClearCache = I;
8
- exports.fetchQuery = O;
9
- exports.getQueryData = C;
10
- exports.getQueryState = w;
11
- exports.invalidateQuery = x;
12
- exports.registerFetcher = v;
5
+ exports.QueryManagerCore = d;
6
+ exports._queryManager = n;
7
+ exports.createPersister = C;
8
+ exports.dangerClearCache = V;
9
+ exports.fetchQuery = j;
10
+ exports.getQueryData = L;
11
+ exports.getQueryState = B;
12
+ exports.invalidateQuery = U;
13
+ exports.registerFetcher = k;
13
14
  exports.serializeKey = c;
14
- exports.setDefaultConfig = E;
15
- exports.setQueryData = K;
16
- exports.subscribeQuery = A;
15
+ exports.setDefaultConfig = _;
16
+ exports.setQueryData = N;
17
+ exports.subscribeQuery = J;
package/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- function c(t){return Array.isArray(t)?t.join(","):String(t)}function y(t,r,a="shallow"){if(t===r)return !0;if(t==null||r==null)return t===r;if(typeof t!="object"||typeof r!="object")return !1;try{let e=t,n=r;if(Array.isArray(e)&&Array.isArray(n)){if(e.length!==n.length)return !1;for(let o=0;o<e.length;o++)if(a==="deep"){if(!y(e[o],n[o],a))return !1}else if(e[o]!==n[o])return !1;return !0}if(Array.isArray(e)||Array.isArray(n))return !1;let s=Object.keys(e),u=Object.keys(n);if(s.length!==u.length)return !1;for(let o=0;o<s.length;o++){let l=s[o];if(a==="deep"){if(!y(e[l],n[l],a))return !1}else if(e[l]!==n[l])return !1}return !0}catch{return !1}}function g(t,r){return r||((a,e)=>y(a,e,t||"shallow"))}function h(t,r){return {status:"idle",updatedAt:void 0,staleTime:t?.staleTime??0,isInvalidated:!1,fetcher:t?.fetcher,equalityFn:g(t?.equalityStrategy,t?.equalityFn),equalityStrategy:t?.equalityStrategy??"shallow",placeholderData:t?.placeholderData,usePreviousDataOnError:t?.usePreviousDataOnError??!1,usePlaceholderOnError:t?.usePlaceholderOnError??!1,refetchOnSubscribe:t?.refetchOnSubscribe??"stale",enabled:t?.enabled!==!1,refetch:r||(()=>Promise.resolve(void 0)),isSuccess:!1,isError:!1,lastReturnedState:void 0}}function d(t){let r=Date.now(),a=t.updatedAt!==void 0&&r-t.updatedAt>t.staleTime||t.isInvalidated,e,n=!1;switch(t.status){case"error":t.usePreviousDataOnError&&t.data!==void 0?e=t.data:t.usePlaceholderOnError&&t.placeholderData!==void 0&&(e=t.placeholderData,n=!0);break;case"fetching":t.data!==void 0?(e=t.data,n=!1):t.placeholderData&&(e=t.placeholderData,n=!0);break;case"success":case"idle":e=t.data??t.placeholderData,n=t.data?!1:!!t.placeholderData;break}return {data:e,error:t.error,status:t.status,updatedAt:t.updatedAt,isStale:a,isPlaceholderData:n,isLoading:t.status==="fetching"&&!t.updatedAt,isFetching:t.status==="fetching",isError:t.isError,isSuccess:t.isSuccess,refetch:t.refetch}}function Q(t){console.warn(`[qortex] No fetcher or data for key "${c(t)}". Register a fetcher or set initial data.`);}var f=class{constructor(){this.cache=new Map;this.subs=new Map;this.defaultConfig={};this.throttleTime=50;}dangerClearCache(){this.cache.clear(),this.subs.clear();}setDefaultConfig({throttleTime:r,...a}){this.defaultConfig={...this.defaultConfig,...a},r!==void 0&&(this.throttleTime=r);}ensureState(r,a={}){let e=c(r),n=this.cache.get(e);if(n){let s={...this.defaultConfig,...n,...a};Object.assign(n,s),n.enabled=s.enabled!==!1,this.cache.set(e,n);}else {let s={...this.defaultConfig,...a},u=h(s,()=>this.fetchQuery(r));this.cache.set(e,u);}return this.cache.get(e)}emit(r,a){let e=c(r);this.cache.set(e,a);let n=this.subs.get(e);if(!n)return;let s=d(a);for(let u of Array.from(n))u(s);}registerFetcher(r,a){let e=this.ensureState(r,a);this.handleMountLogic(r,e);}fetchQuery(r,a){let e=this.ensureState(r,a);if(e.fetchPromise)return e.fetchPromise;let n=e.fetcher;if(!n)return e.updatedAt===void 0&&Q(r),Promise.resolve(e.data);let s=n();return e.fetchPromise=s,e.status="fetching",e.lastFetchTime=Date.now(),this.emit(r,e),s.then(u=>{e.data=e.equalityFn(e.data,u)?e.data:u,e.status="success",e.isError=!1,e.isSuccess=!0,e.updatedAt=Date.now(),e.fetchPromise=void 0,e.error=void 0,this.emit(r,e);}).catch(u=>{e.error=u,e.status="error",e.isError=!0,e.isSuccess=!1,e.updatedAt=Date.now(),e.fetchPromise=void 0,this.emit(r,e);}),s}setQueryData(r,a){let e=this.ensureState(r),n=e.data;e.equalityFn(n,a)||(e.data=a,e.updatedAt=Date.now(),e.error=void 0,e.status="success",e.isInvalidated=!1,e.isError=!1,e.isSuccess=!0,this.emit(r,e));}getQueryData(r,a){let e=this.ensureState(r,a);return this.handleMountLogic(r,e),d(e).data}getQueryState(r,a){let e=this.ensureState(r,a);this.handleMountLogic(r,e);let n=d(e),s=e.lastReturnedState;return !s||!y(s,n,"shallow")?(e.lastReturnedState=n,n):s}invalidateQuery(r){let a=this.ensureState(r);a.isInvalidated=!0,this.emit(r,a),this.fetchQuery(r);}subscribeQuery(r,a,e){let n=c(r),s=this.ensureState(r,e);return this.subs.has(n)||this.subs.set(n,new Set),this.subs.get(n).add(a),this.handleMountLogic(r,s),()=>{this.subs.get(n).delete(a);}}handleMountLogic(r,a){let e=a.lastFetchTime&&Date.now()-a.lastFetchTime<this.throttleTime;if(a.status==="fetching"||!a.enabled||e||!a.fetcher)return;let n=Date.now(),s=a.updatedAt==null||n-(a.updatedAt||0)>a.staleTime||a.isInvalidated,u=!1;a.updatedAt==null?u=!0:(a.refetchOnSubscribe==="always"&&(u=!0),a.refetchOnSubscribe==="stale"&&(u=s)),u&&this.fetchQuery(r);}},p=f;var i=new p,v=i.registerFetcher.bind(i),O=i.fetchQuery.bind(i),K=i.setQueryData.bind(i),C=i.getQueryData.bind(i),w=i.getQueryState.bind(i),x=i.invalidateQuery.bind(i),A=i.subscribeQuery.bind(i),E=i.setDefaultConfig.bind(i),I=i.dangerClearCache.bind(i);
1
+ function c(e){return Array.isArray(e)?e.join(","):String(e)}function y(e,r,s="shallow"){if(e===r)return !0;if(e==null||r==null)return e===r;if(typeof e!="object"||typeof r!="object")return !1;try{let t=e,a=r;if(Array.isArray(t)&&Array.isArray(a)){if(t.length!==a.length)return !1;for(let u=0;u<t.length;u++)if(s==="deep"){if(!y(t[u],a[u],s))return !1}else if(t[u]!==a[u])return !1;return !0}if(Array.isArray(t)||Array.isArray(a))return !1;let i=Object.keys(t),o=Object.keys(a);if(i.length!==o.length)return !1;for(let u=0;u<i.length;u++){let l=i[u];if(s==="deep"){if(!y(t[l],a[l],s))return !1}else if(t[l]!==a[l])return !1}return !0}catch{return !1}}function p(e,r){return r||((s,t)=>y(s,t,e||"shallow"))}function Q(e,r){return {status:"idle",updatedAt:void 0,staleTime:e?.staleTime??0,isInvalidated:!1,fetcher:e?.fetcher,equalityFn:p(e?.equalityStrategy,e?.equalityFn),equalityStrategy:e?.equalityStrategy??"shallow",placeholderData:e?.placeholderData,usePreviousDataOnError:e?.usePreviousDataOnError??!1,usePlaceholderOnError:e?.usePlaceholderOnError??!1,refetchOnSubscribe:e?.refetchOnSubscribe??"stale",enabled:e?.enabled!==!1,refetch:r||(()=>Promise.resolve(void 0)),isSuccess:!1,isError:!1,lastReturnedState:void 0}}function f(e){let r=Date.now(),s=e.updatedAt!==void 0&&r-e.updatedAt>e.staleTime||e.isInvalidated,t,a=!1;switch(e.status){case"error":e.usePreviousDataOnError&&e.data!==void 0?t=e.data:e.usePlaceholderOnError&&e.placeholderData!==void 0&&(t=e.placeholderData,a=!0);break;case"fetching":e.data!==void 0?(t=e.data,a=!1):e.placeholderData&&(t=e.placeholderData,a=!0);break;case"success":case"idle":t=e.data??e.placeholderData,a=e.data?!1:!!e.placeholderData;break}return {data:t,error:e.error,status:e.status,updatedAt:e.updatedAt,isStale:s,isPlaceholderData:a,isLoading:e.status==="fetching"&&!e.updatedAt,isFetching:e.status==="fetching",isError:e.isError,isSuccess:e.isSuccess,refetch:e.refetch}}function S(e){console.warn(`[qortex] No fetcher or data for key "${c(e)}". Register a fetcher or set initial data.`);}var d=class{constructor(){this.cache=new Map;this.subs=new Map;this.defaultConfig={};this.throttleTime=50;this.persister=null;this.hasQueriesBeenUsed=!1;}dangerClearCache(){this.cache.clear(),this.subs.clear(),this.persister?.clear();}setDefaultConfig({throttleTime:r,persister:s,...t}){this.defaultConfig={...this.defaultConfig,...t},r!==void 0&&(this.throttleTime=r),s&&(this.persister=s,this.persister?.load(this.cache,this.hasQueriesBeenUsed));}ensureState(r,s={}){this.hasQueriesBeenUsed=!0;let t=c(r),a=this.cache.get(t);if(a){let i={...this.defaultConfig,...a,...s};Object.assign(a,i),a.enabled=i.enabled!==!1,this.cache.set(t,a);}else {let i={...this.defaultConfig,...s},o=Q(i,()=>this.fetchQuery(r));this.cache.set(t,o);}return this.cache.get(t)}emit(r,s){let t=c(r);this.cache.set(t,s),this.persister?.sync(this.cache);let a=this.subs.get(t);if(!a)return;let i=f(s);for(let o of Array.from(a))o(i);}registerFetcher(r,s){let t=this.ensureState(r,s);this.handleMountLogic(r,t);}fetchQuery(r,s){let t=this.ensureState(r,s);if(t.fetchPromise)return t.fetchPromise;let a=t.fetcher;if(!a)return t.updatedAt===void 0&&S(r),Promise.resolve(t.data);let i=a();return t.fetchPromise=i,t.status="fetching",t.lastFetchTime=Date.now(),this.emit(r,t),i.then(o=>{t.data=t.equalityFn(t.data,o)?t.data:o,t.status="success",t.isError=!1,t.isSuccess=!0,t.updatedAt=Date.now(),t.fetchPromise=void 0,t.error=void 0,this.emit(r,t);}).catch(o=>{t.error=o,t.status="error",t.isError=!0,t.isSuccess=!1,t.updatedAt=Date.now(),t.fetchPromise=void 0,this.emit(r,t);}),i}setQueryData(r,s){let t=this.ensureState(r),a=t.data;t.equalityFn(a,s)||(t.data=s,t.updatedAt=Date.now(),t.error=void 0,t.status="success",t.isInvalidated=!1,t.isError=!1,t.isSuccess=!0,this.emit(r,t));}getQueryData(r,s){let t=this.ensureState(r,s);return this.handleMountLogic(r,t),f(t).data}getQueryState(r,s){let t=this.ensureState(r,s);this.handleMountLogic(r,t);let a=f(t),i=t.lastReturnedState;return !i||!y(i,a,"shallow")?(t.lastReturnedState=a,a):i}invalidateQuery(r){let s=this.ensureState(r);s.isInvalidated=!0,this.emit(r,s),this.fetchQuery(r);}subscribeQuery(r,s,t){let a=c(r),i=this.ensureState(r,t);return this.subs.has(a)||this.subs.set(a,new Set),this.subs.get(a).add(s),this.handleMountLogic(r,i),()=>{this.subs.get(a).delete(s);}}handleMountLogic(r,s){let t=s.lastFetchTime&&Date.now()-s.lastFetchTime<this.throttleTime;if(s.status==="fetching"||!s.enabled||t||!s.fetcher)return;let a=Date.now(),i=s.updatedAt==null||a-(s.updatedAt||0)>s.staleTime||s.isInvalidated,o=!1;s.updatedAt==null?o=!0:(s.refetchOnSubscribe==="always"&&(o=!0),s.refetchOnSubscribe==="stale"&&(o=i)),o&&this.fetchQuery(r);}},g=d;var n=new g,k=n.registerFetcher.bind(n),j=n.fetchQuery.bind(n),N=n.setQueryData.bind(n),L=n.getQueryData.bind(n),B=n.getQueryState.bind(n),U=n.invalidateQuery.bind(n),J=n.subscribeQuery.bind(n),_=n.setDefaultConfig.bind(n),V=n.dangerClearCache.bind(n);function P(e){return typeof e=="string"&&["idle","fetching","success","error"].includes(e)}function K(e){return typeof e=="string"&&["shallow","deep"].includes(e)}function O(e){return e===!1||typeof e=="string"&&["always","stale"].includes(e)}function D(e){return !(!e||typeof e!="object"||!P(e.status)||typeof e.staleTime!="number"||e.staleTime<0||typeof e.isInvalidated!="boolean"||!K(e.equalityStrategy)||!O(e.refetchOnSubscribe))}function m(e){if(!e||typeof e!="object"||!e.entries||typeof e.entries!="object")return !1;for(let[r,s]of Object.entries(e.entries))if(typeof r!="string"||!D(s))return !1;return !(typeof e.burstKey!="string"||typeof e.timestamp!="number"||e.timestamp<0)}function b(e){let{fetcher:r,equalityFn:s,fetchPromise:t,refetch:a,...i}=e;return i}function T(e,r){let s={...r??{},...e};return {...s,equalityFn:r?.equalityFn||p(s.equalityStrategy)}}function F(e){try{let r=JSON.parse(e);return m(r)?r:null}catch{return null}}var v=()=>{console.warn("[Qortex] No storage found, persister will not be able to persist data");},w=()=>{console.warn("[Qortex] Persister is being set after queries have been used. This may cause data inconsistency. It is recommended to set the persister before any query usage.");};var h=class{constructor(r,s){this.syncTimeout=null;this.debounceTime=100;this.burstKey="0.3.0";this.storageKey="qortex";this.storage=r,this.burstKey=s?.burstKey??this.burstKey,this.storageKey=s?.prefix??this.storageKey,this.debounceTime=s?.debounceTime??this.debounceTime;}save(r){try{let s={entries:{},burstKey:this.burstKey,timestamp:Date.now()};for(let[a,i]of Object.entries(r))s.entries[a]=i;let t=JSON.stringify(s);this.storage.setItem(this.storageKey,t);}catch(s){console.warn("[Qortex] Failed to persist state:",s);}}load(r,s){s&&w();try{let t=this.storage.getItem(this.storageKey);if(!t)return;let a=F(t);if(!a){console.warn("[Qortex] Invalid persisted state format, clearing cache"),this.clear();return}if(a.burstKey!==this.burstKey){console.warn("[Qortex] Burst key mismatch, clearing cache"),this.clear();return}for(let[i,o]of Object.entries(a.entries)){let u=o,l=r.get(i),x=T(u,l);r.set(i,x);}}catch(t){console.warn("[Qortex] Failed to load persisted state:",t),this.clear();}}clear(){try{this.storage.removeItem(this.storageKey);}catch(r){console.warn("[Qortex] Failed to clear persisted data:",r);}}sync(r){this.syncTimeout&&clearTimeout(this.syncTimeout),this.syncTimeout=setTimeout(()=>{let s={};for(let[t,a]of r.entries())s[t]=b(a);this.save(s);},this.debounceTime);}};var I=e=>{switch(e){case"local":if(typeof localStorage<"u")return window.localStorage;break;case"session":if(typeof sessionStorage<"u")return window.sessionStorage;break;default:throw new Error(`Invalid storage type: ${e}`)}},C=(e,r)=>{let s=I(e);if(!s){v();return}return new h(s,r)};
2
2
 
3
- export { f as QueryManagerCore, i as _queryManager, I as dangerClearCache, O as fetchQuery, C as getQueryData, w as getQueryState, x as invalidateQuery, v as registerFetcher, c as serializeKey, E as setDefaultConfig, K as setQueryData, A as subscribeQuery };
3
+ export { d as QueryManagerCore, n as _queryManager, C as createPersister, V as dangerClearCache, j as fetchQuery, L as getQueryData, B as getQueryState, U as invalidateQuery, k as registerFetcher, c as serializeKey, _ as setDefaultConfig, N as setQueryData, J as subscribeQuery };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qortex-core",
3
- "version": "0.2.8",
3
+ "version": "0.3.0-beta.1",
4
4
  "description": "Framework-agnostic query cache & fetch registry (MFE friendly).",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",