qortex-core 0.3.0 → 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/README.md CHANGED
@@ -13,11 +13,10 @@
13
13
 
14
14
  - 🔐 **App core data** - Authentication, user profiles accessible from anywhere
15
15
  - 🎯 **Cross-framework** - Share data between React, Vue, vanilla JS, Node.js
16
- - 🔄 **Background services** - WebSocket updates, timers, external events
17
16
  - ⚡ **Real-time apps** - Push changes from anywhere, see them everywhere instantly
18
17
 
19
18
  ```bash
20
- pnpm add qortex-core
19
+ npm install qortex-core
21
20
  ```
22
21
 
23
22
  ## 📚 Documentation
@@ -28,7 +27,7 @@ pnpm add qortex-core
28
27
 
29
28
  ## 📄 License
30
29
 
31
- MIT License - feel free to use this in your projects! 🎉
30
+ LGPL-3.0 License - see [LICENSE](../../LICENSE) file for details.
32
31
 
33
32
  ## 🎯 Support
34
33
 
@@ -45,4 +44,4 @@ Need help? Have questions? Want to chat about data fetching strategies?
45
44
  <div align="center">
46
45
  <p>Made with ❤️ by <a href="https://darshannaik.com">Darshan</a></p>
47
46
  <p>⭐ Star this repo if you found it helpful!</p>
48
- </div>
47
+ </div>
package/index.d.ts CHANGED
@@ -1,9 +1,16 @@
1
- import { D as DefaultConfig, Q as QueryKey, a as QueryOptions, F as Fetcher, I as InferFetcherResult, b as QueryState } from './types-61b54557.js';
2
- export { E as EqualityFn, c as EqualityStrategy, d as QueryStatus, R as RefetchOnSubscribeOptions } from './types-61b54557.js';
1
+ import { D as DefaultConfig, Q as QueryKey, a as QueryOptions, F as Fetcher, I as InferFetcherResult, S as SetDataUpdater, b as QueryState } from './types-15a3228d.js';
2
+ export { E as EqualityFn, c as EqualityStrategy, d as QueryStatus, R as RefetchOnSubscribeOptions } from './types-15a3228d.js';
3
3
 
4
4
  /**
5
5
  * Core query manager that handles caching, fetching, and state management
6
6
  * Implements robust throttling and race condition prevention
7
+ *
8
+ * All public methods are arrow functions to support destructuring:
9
+ * @example
10
+ * ```typescript
11
+ * const { fetchQuery, getQueryData } = queryManager;
12
+ * fetchQuery('key'); // Works correctly!
13
+ * ```
7
14
  */
8
15
  declare class QueryManagerCore {
9
16
  private cache;
@@ -12,8 +19,56 @@ declare class QueryManagerCore {
12
19
  private throttleTime;
13
20
  private persister;
14
21
  private hasQueriesBeenUsed;
15
- dangerClearCache(): void;
16
- setDefaultConfig({ throttleTime, persister, ...config }: DefaultConfig): void;
22
+ /**
23
+ * ⚠️ DANGER: Clear all cached data and subscriptions
24
+ *
25
+ * This method completely wipes all internal state including:
26
+ * - All cached query data
27
+ * - All active subscriptions
28
+ * - All state references
29
+ * - All persisted data
30
+ *
31
+ * @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.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // ✅ Safe usage in tests
36
+ * beforeEach(() => {
37
+ * queryManager.dangerClearCache();
38
+ * });
39
+ *
40
+ * // ❌ Dangerous usage in production
41
+ * // queryManager.dangerClearCache(); // Don't do this!
42
+ * ```
43
+ */
44
+ dangerClearCache: () => void;
45
+ /**
46
+ * Sets default configuration that applies to all queries
47
+ *
48
+ * @param config - Default configuration object
49
+ * @param config.enabled - Default enabled state for all queries. Default: `true`
50
+ * @param config.staleTime - Default stale time in milliseconds. Default: `0` (data becomes stale immediately after fetch)
51
+ * @param config.refetchOnSubscribe - Default refetch behavior on subscription. Default: `"stale"`
52
+ * @param config.equalityStrategy - Default equality comparison strategy. Default: `"shallow"`
53
+ * @param config.equalityFn - Default equality function. Default: `Object.is`
54
+ * @param config.usePreviousDataOnError - Default behavior for previous data on error. Default: `false`
55
+ * @param config.usePlaceholderOnError - Default behavior for placeholder data on error. Default: `false`
56
+ * @param config.throttleTime - Time in ms to throttle fetch requests. Default: `500`
57
+ * @param config.persister - Persister instance for data persistence
58
+ *
59
+ * These defaults will be merged with individual query options. Useful for setting global behavior
60
+ * like default stale times, error handling, or persistence configuration.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * queryManager.setDefaultConfig({
65
+ * staleTime: 5000,
66
+ * refetchOnSubscribe: 'stale',
67
+ * persister: createPersister('local', { burstKey: 'v1' })
68
+ * });
69
+ * ```
70
+ */
71
+ setDefaultConfig: ({ throttleTime, persister, ...config }: DefaultConfig) => void;
17
72
  /**
18
73
  * Ensures a query state exists in cache, creating it if necessary
19
74
  * User-friendly with any fallback for better developer experience
@@ -23,29 +78,187 @@ declare class QueryManagerCore {
23
78
  * Notifies all subscribers of a query state change
24
79
  */
25
80
  private emit;
26
- registerFetcher<T = any>(key: QueryKey, opts: QueryOptions<T>): void;
27
- registerFetcher<F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
28
- fetcher: F;
29
- }): void;
30
- fetchQuery<T = any>(key: QueryKey, opts?: QueryOptions<T>): Promise<T>;
31
- fetchQuery<F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
32
- fetcher: F;
33
- }): Promise<InferFetcherResult<F>>;
34
- setQueryData<T = any>(key: QueryKey, data: T): void;
35
- getQueryData<T = any>(key: QueryKey, opts?: QueryOptions<T>): T | undefined;
36
- getQueryData<F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
37
- fetcher: F;
38
- }): InferFetcherResult<F> | undefined;
39
- getQueryState<T = unknown>(key: QueryKey, opts?: QueryOptions<T>): QueryState<T>;
40
- getQueryState<F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
41
- fetcher: F;
42
- }): QueryState<InferFetcherResult<F>>;
43
- invalidateQuery(key: QueryKey): void;
44
- subscribeQuery(key: QueryKey, cb: (state: QueryState<any>) => void): () => void;
45
- subscribeQuery<F extends Fetcher>(key: QueryKey, cb: (state: QueryState<InferFetcherResult<F>>) => void, opts: QueryOptions<InferFetcherResult<F>> & {
46
- fetcher: F;
47
- }): () => void;
48
- subscribeQuery<T = any>(key: QueryKey, cb: (state: QueryState<T>) => void, opts?: QueryOptions<T>): () => void;
81
+ /**
82
+ * Registers a fetcher function for a query key and sets up the query state
83
+ *
84
+ * @param key - Unique identifier for the query (string or array of primitives)
85
+ * @param opts - Query configuration options
86
+ * @param opts.fetcher - Async function that fetches data for this query
87
+ * @param opts.enabled - Whether the query should be active (default: true)
88
+ * @param opts.staleTime - Time in ms before data is considered stale (default: 0)
89
+ * @param opts.equalityStrategy - How to compare data for changes ('shallow' | 'deep')
90
+ * @param opts.equalityFn - Custom equality function for data comparison
91
+ * @param opts.refetchOnSubscribe - When to refetch on subscription ('always' | 'stale' | false)
92
+ * @param opts.placeholderData - Initial data to show while loading
93
+ * @param opts.usePreviousDataOnError - Keep previous data when error occurs
94
+ * @param opts.usePlaceholderOnError - Use placeholder data when error occurs
95
+ *
96
+ * Automatically triggers initial fetch if enabled is not false.
97
+ * Enhanced with automatic type inference from fetcher function.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * queryManager.registerFetcher('users', {
102
+ * fetcher: async () => fetch('/api/users').then(r => r.json()),
103
+ * staleTime: 60000
104
+ * });
105
+ * ```
106
+ */
107
+ registerFetcher: {
108
+ <T = any>(key: QueryKey, opts: QueryOptions<T>): void;
109
+ <F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
110
+ fetcher: F;
111
+ }): void;
112
+ };
113
+ /**
114
+ * Executes a fetch operation with proper error handling and state management
115
+ *
116
+ * @param key - Unique identifier for the query
117
+ * @param opts - Optional query configuration (if not already registered)
118
+ * @returns Promise that resolves to the fetched data
119
+ *
120
+ * Prevents duplicate fetches by tracking ongoing promises.
121
+ * Enhanced with automatic type inference from fetcher function.
122
+ * Updates query state with loading, success, or error status.
123
+ * Handles race conditions and concurrent requests.
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const users = await queryManager.fetchQuery('users');
128
+ * ```
129
+ */
130
+ fetchQuery: {
131
+ <T = any>(key: QueryKey, opts?: QueryOptions<T>): Promise<T>;
132
+ <F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
133
+ fetcher: F;
134
+ }): Promise<InferFetcherResult<F>>;
135
+ };
136
+ /**
137
+ * Manually sets query data without triggering a fetch operation
138
+ *
139
+ * @param key - Unique identifier for the query
140
+ * @param dataOrUpdater - Data to set, or an updater function that receives previous data
141
+ *
142
+ * Marks the query as successful and updates the cache.
143
+ * Useful for optimistic updates or setting initial data.
144
+ * Triggers all subscribers with the new data.
145
+ * Does not affect the fetcher function or trigger network requests.
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * // Direct update
150
+ * setQueryData('user', { id: 1, name: 'John' });
151
+ *
152
+ * // Functional update - access previous data
153
+ * setQueryData('user', (prev) => ({ ...prev, name: 'Jane' }));
154
+ *
155
+ * // Increment counter example
156
+ * setQueryData('counter', (prev) => (prev ?? 0) + 1);
157
+ * ```
158
+ */
159
+ setQueryData: <T = any>(key: QueryKey, dataOrUpdater: T | SetDataUpdater<T>) => void;
160
+ /**
161
+ * Gets the current data for a query
162
+ *
163
+ * @param key - Unique identifier for the query
164
+ * @param opts - Optional query configuration (if not already registered)
165
+ * @returns The current data value or undefined if not available
166
+ *
167
+ * Handles mount logic to potentially start fetching if data is stale or missing.
168
+ * Returns undefined if the query has never been fetched or if an error occurred.
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const users = queryManager.getQueryData('users');
173
+ * if (users) {
174
+ * console.log('Got cached users:', users);
175
+ * }
176
+ * ```
177
+ */
178
+ getQueryData: {
179
+ <T = any>(key: QueryKey, opts?: QueryOptions<T>): T | undefined;
180
+ <F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
181
+ fetcher: F;
182
+ }): InferFetcherResult<F> | undefined;
183
+ };
184
+ /**
185
+ * Gets the complete query state including loading, error, and computed flags
186
+ *
187
+ * @param key - Unique identifier for the query
188
+ * @param opts - Optional query configuration (if not already registered)
189
+ * @returns QueryState object with data, error, status, and computed flags
190
+ *
191
+ * Returns an object containing:
192
+ * - data: The current data value
193
+ * - error: Any error that occurred during fetching
194
+ * - status: Current status ('idle' | 'fetching' | 'success' | 'error')
195
+ * - isStale: Whether the data is considered stale
196
+ * - isLoading: Whether the query is currently loading
197
+ * - isFetching: Whether a fetch is in progress
198
+ * - isError: Whether the query is in an error state
199
+ * - isSuccess: Whether the query completed successfully
200
+ * - refetch: Function to manually trigger a refetch
201
+ *
202
+ * Handles mount logic to potentially start fetching if data is stale or missing.
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * const { data, isLoading, error, refetch } = queryManager.getQueryState('users');
207
+ * ```
208
+ */
209
+ getQueryState: {
210
+ <T = unknown>(key: QueryKey, opts?: QueryOptions<T>): QueryState<T>;
211
+ <F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
212
+ fetcher: F;
213
+ }): QueryState<InferFetcherResult<F>>;
214
+ };
215
+ /**
216
+ * Invalidates a query, marking it as stale and triggering a refetch
217
+ *
218
+ * @param key - Unique identifier for the query
219
+ *
220
+ * Marks the query as invalidated and immediately triggers a refetch operation.
221
+ * Useful for forcing data refresh after mutations or when you know data is outdated.
222
+ * All subscribers will be notified of the state changes.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * // After updating a user, invalidate the users list
227
+ * await updateUser(userId, newData);
228
+ * queryManager.invalidateQuery('users');
229
+ * ```
230
+ */
231
+ invalidateQuery: (key: QueryKey) => void;
232
+ /**
233
+ * Subscribes to query state changes and returns an unsubscribe function
234
+ *
235
+ * @param key - Unique identifier for the query
236
+ * @param cb - Function called whenever the query state changes
237
+ * @param opts - Optional query configuration (if not already registered)
238
+ * @returns Unsubscribe function to stop receiving updates
239
+ *
240
+ * The callback receives the current QueryState object.
241
+ * Handles mount logic to potentially start fetching.
242
+ * Returns a cleanup function that should be called when the subscription is no longer needed.
243
+ * Multiple subscribers can be registered for the same query key.
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * const unsubscribe = queryManager.subscribeQuery('users', (state) => {
248
+ * console.log('Users state changed:', state);
249
+ * });
250
+ *
251
+ * // Later, when done
252
+ * unsubscribe();
253
+ * ```
254
+ */
255
+ subscribeQuery: {
256
+ (key: QueryKey, cb: (state: QueryState<any>) => void): () => void;
257
+ <F extends Fetcher>(key: QueryKey, cb: (state: QueryState<InferFetcherResult<F>>) => void, opts: QueryOptions<InferFetcherResult<F>> & {
258
+ fetcher: F;
259
+ }): () => void;
260
+ <T = any>(key: QueryKey, cb: (state: QueryState<T>) => void, opts?: QueryOptions<T>): () => void;
261
+ };
49
262
  /**
50
263
  * Core mount logic that determines when to fetch
51
264
  * Implements robust throttling and race condition prevention
@@ -53,24 +266,33 @@ declare class QueryManagerCore {
53
266
  private handleMountLogic;
54
267
  }
55
268
 
56
- declare const _queryManager: QueryManagerCore;
57
-
58
269
  /**
59
- * Registers a fetcher function for a query key and sets up the query state
270
+ * The global query manager instance.
271
+ * Use this to interact with the query cache directly.
272
+ *
273
+ * @example
274
+ * ```typescript
275
+ * import { queryManager } from 'qortex-core';
276
+ *
277
+ * queryManager.registerFetcher('users', { fetcher: () => fetch('/api/users') });
278
+ * const users = await queryManager.fetchQuery('users');
279
+ * ```
280
+ */
281
+ declare const queryManager: QueryManagerCore;
282
+ /**
283
+ * Registers a fetcher function for a query key and sets up the query state.
284
+ * Automatically triggers initial fetch if enabled is not false.
60
285
  *
61
286
  * @param key - Unique identifier for the query (string or array of primitives)
62
- * @param opts - Query configuration options
63
- * @param opts.fetcher - Async function that fetches data for this query
64
- * @param opts.enabled - Whether the query should be active (default: true)
65
- * @param opts.staleTime - Time in ms before data is considered stale (default: 0)
66
- * @param opts.equalityStrategy - How to compare data for changes ('shallow' | 'deep')
67
- * @param opts.equalityFn - Custom equality function for data comparison
68
- * @param opts.refetchOnSubscribe - When to refetch on subscription ('always' | 'stale' | false)
69
- * @param opts.placeholderData - Initial data to show while loading
70
- * @param opts.usePreviousDataOnError - Keep previous data when error occurs
71
- * @param opts.usePlaceholderOnError - Use placeholder data when error occurs
72
- *
73
- * Automatically triggers initial fetch if enabled is not false. Enhanced with automatic type inference from fetcher function.
287
+ * @param opts - Query configuration options including fetcher, staleTime, enabled, etc.
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * registerFetcher('users', {
292
+ * fetcher: async () => fetch('/api/users').then(r => r.json()),
293
+ * staleTime: 60000
294
+ * });
295
+ * ```
74
296
  */
75
297
  declare const registerFetcher: {
76
298
  <T = any>(key: QueryKey, opts: QueryOptions<T>): void;
@@ -79,14 +301,17 @@ declare const registerFetcher: {
79
301
  }): void;
80
302
  };
81
303
  /**
82
- * Executes a fetch operation with proper error handling and state management
304
+ * Executes a fetch operation with proper error handling and state management.
305
+ * Prevents duplicate fetches by tracking ongoing promises.
83
306
  *
84
307
  * @param key - Unique identifier for the query
85
308
  * @param opts - Optional query configuration (if not already registered)
86
309
  * @returns Promise that resolves to the fetched data
87
310
  *
88
- * Prevents duplicate fetches by tracking ongoing promises. Enhanced with automatic type inference from fetcher function.
89
- * Updates query state with loading, success, or error status. Handles race conditions and concurrent requests.
311
+ * @example
312
+ * ```typescript
313
+ * const users = await fetchQuery('users');
314
+ * ```
90
315
  */
91
316
  declare const fetchQuery: {
92
317
  <T = any>(key: QueryKey, opts?: QueryOptions<T>): Promise<T>;
@@ -95,24 +320,37 @@ declare const fetchQuery: {
95
320
  }): Promise<InferFetcherResult<F>>;
96
321
  };
97
322
  /**
98
- * Manually sets query data without triggering a fetch operation
323
+ * Manually sets query data without triggering a fetch operation.
324
+ * Useful for optimistic updates or setting initial data.
99
325
  *
100
326
  * @param key - Unique identifier for the query
101
- * @param data - Data to set for the query
327
+ * @param dataOrUpdater - Data to set, or an updater function that receives previous data
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * // Direct update
332
+ * setQueryData('user', { id: 1, name: 'John' });
333
+ *
334
+ * // Functional update - access previous data
335
+ * setQueryData('user', (prev) => ({ ...prev, name: 'Jane' }));
102
336
  *
103
- * Marks the query as successful and updates the cache. Useful for optimistic updates or setting initial data.
104
- * Triggers all subscribers with the new data. Does not affect the fetcher function or trigger network requests.
337
+ * // Increment counter example
338
+ * setQueryData('counter', (prev) => (prev ?? 0) + 1);
339
+ * ```
105
340
  */
106
- declare const setQueryData: <T = any>(key: QueryKey, data: T) => void;
341
+ declare const setQueryData: <T = any>(key: QueryKey, dataOrUpdater: T | SetDataUpdater<T>) => void;
107
342
  /**
108
- * Gets the current data for a query
343
+ * Gets the current data for a query.
344
+ * Returns undefined if the query has never been fetched or if an error occurred.
109
345
  *
110
346
  * @param key - Unique identifier for the query
111
347
  * @param opts - Optional query configuration (if not already registered)
112
348
  * @returns The current data value or undefined if not available
113
349
  *
114
- * Handles mount logic to potentially start fetching if data is stale or missing.
115
- * Returns undefined if the query has never been fetched or if an error occurred.
350
+ * @example
351
+ * ```typescript
352
+ * const users = getQueryData('users');
353
+ * ```
116
354
  */
117
355
  declare const getQueryData: {
118
356
  <T = any>(key: QueryKey, opts?: QueryOptions<T>): T | undefined;
@@ -121,24 +359,16 @@ declare const getQueryData: {
121
359
  }): InferFetcherResult<F> | undefined;
122
360
  };
123
361
  /**
124
- * Gets the complete query state including loading, error, and computed flags
362
+ * Gets the complete query state including loading, error, and computed flags.
125
363
  *
126
364
  * @param key - Unique identifier for the query
127
365
  * @param opts - Optional query configuration (if not already registered)
128
- * @returns QueryState object with data, error, status, and computed flags
129
- *
130
- * Returns an object containing:
131
- * - data: The current data value
132
- * - error: Any error that occurred during fetching
133
- * - status: Current status ('idle' | 'fetching' | 'success' | 'error')
134
- * - isStale: Whether the data is considered stale
135
- * - isLoading: Whether the query is currently loading
136
- * - isFetching: Whether a fetch is in progress
137
- * - isError: Whether the query is in an error state
138
- * - isSuccess: Whether the query completed successfully
139
- * - refetch: Function to manually trigger a refetch
140
- *
141
- * Handles mount logic to potentially start fetching if data is stale or missing.
366
+ * @returns QueryState object with data, error, status, isLoading, isFetching, isError, isSuccess, isStale, and refetch
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * const { data, isLoading, error, refetch } = getQueryState('users');
371
+ * ```
142
372
  */
143
373
  declare const getQueryState: {
144
374
  <T = unknown>(key: QueryKey, opts?: QueryOptions<T>): QueryState<T>;
@@ -147,26 +377,33 @@ declare const getQueryState: {
147
377
  }): QueryState<InferFetcherResult<F>>;
148
378
  };
149
379
  /**
150
- * Invalidates a query, marking it as stale and triggering a refetch
380
+ * Invalidates a query, marking it as stale and triggering a refetch.
381
+ * Useful for forcing data refresh after mutations.
151
382
  *
152
383
  * @param key - Unique identifier for the query
153
384
  *
154
- * Marks the query as invalidated and immediately triggers a refetch operation.
155
- * Useful for forcing data refresh after mutations or when you know data is outdated.
156
- * All subscribers will be notified of the state changes.
385
+ * @example
386
+ * ```typescript
387
+ * await updateUser(userId, newData);
388
+ * invalidateQuery('users');
389
+ * ```
157
390
  */
158
391
  declare const invalidateQuery: (key: QueryKey) => void;
159
392
  /**
160
- * Subscribes to query state changes and returns an unsubscribe function
393
+ * Subscribes to query state changes and returns an unsubscribe function.
161
394
  *
162
395
  * @param key - Unique identifier for the query
163
- * @param callback - Function called whenever the query state changes
396
+ * @param cb - Function called whenever the query state changes
164
397
  * @param opts - Optional query configuration (if not already registered)
165
398
  * @returns Unsubscribe function to stop receiving updates
166
399
  *
167
- * The callback receives the current QueryState object. Handles mount logic to potentially start fetching.
168
- * Returns a cleanup function that should be called when the subscription is no longer needed.
169
- * Multiple subscribers can be registered for the same query key.
400
+ * @example
401
+ * ```typescript
402
+ * const unsubscribe = subscribeQuery('users', (state) => {
403
+ * console.log('Users state changed:', state);
404
+ * });
405
+ * unsubscribe(); // When done
406
+ * ```
170
407
  */
171
408
  declare const subscribeQuery: {
172
409
  (key: QueryKey, cb: (state: QueryState<any>) => void): () => void;
@@ -176,43 +413,28 @@ declare const subscribeQuery: {
176
413
  <T = any>(key: QueryKey, cb: (state: QueryState<T>) => void, opts?: QueryOptions<T>): () => void;
177
414
  };
178
415
  /**
179
- * Sets default configuration that applies to all queries
180
- *
181
- * @param config - Default configuration object
182
- * @param config.enabled - Default enabled state for all queries. Default: `true`
183
- * @param config.staleTime - Default stale time in milliseconds. Default: `0` (data becomes stale immediately after fetch)
184
- * @param config.refetchOnSubscribe - Default refetch behavior on subscription. Default: `"stale"`
185
- * @param config.equalityStrategy - Default equality comparison strategy. Default: `"shallow"`
186
- * @param config.equalityFn - Default equality function. Default: `Object.is`
187
- * @param config.usePreviousDataOnError - Default behavior for previous data on error. Default: `false`
188
- * @param config.usePlaceholderOnError - Default behavior for placeholder data on error. Default: `false`
189
- * @param config.throttleTime - Time in ms to throttle fetch requests. Default: `50`
190
- * @param config.persister - Persister instance for data persistence
191
- *
192
- * These defaults will be merged with individual query options. Useful for setting global behavior
193
- * like default stale times, error handling, or persistence configuration.
416
+ * Sets default configuration that applies to all queries.
417
+ *
418
+ * @param config - Default configuration object (staleTime, enabled, refetchOnSubscribe, throttleTime, persister, etc.)
419
+ *
420
+ * @example
421
+ * ```typescript
422
+ * setDefaultConfig({
423
+ * staleTime: 5000,
424
+ * refetchOnSubscribe: 'stale'
425
+ * });
426
+ * ```
194
427
  */
195
428
  declare const setDefaultConfig: ({ throttleTime, persister, ...config }: DefaultConfig) => void;
196
429
  /**
197
- * ⚠️ DANGER: Clear all cached data and subscriptions
198
- *
199
- * This method completely wipes all internal state including:
200
- * - All cached query data
201
- * - All active subscriptions
202
- * - All state references
203
- * - All persisted data
204
- *
205
- * @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.
430
+ * ⚠️ DANGER: Clear all cached data and subscriptions.
431
+ * Only use in testing environments!
206
432
  *
207
433
  * @example
208
434
  * ```typescript
209
- * // ✅ Safe usage in tests
210
435
  * beforeEach(() => {
211
436
  * dangerClearCache();
212
437
  * });
213
- *
214
- * // ❌ Dangerous usage in production
215
- * // dangerClearCache(); // Don't do this!
216
438
  * ```
217
439
  */
218
440
  declare const dangerClearCache: () => void;
@@ -223,4 +445,4 @@ declare const dangerClearCache: () => void;
223
445
  */
224
446
  declare function serializeKey(key: QueryKey): string;
225
447
 
226
- export { DefaultConfig, Fetcher, InferFetcherResult, QueryKey, QueryManagerCore, QueryOptions, QueryState, _queryManager, dangerClearCache, fetchQuery, getQueryData, getQueryState, invalidateQuery, registerFetcher, serializeKey, setDefaultConfig, setQueryData, subscribeQuery };
448
+ export { DefaultConfig, Fetcher, InferFetcherResult, QueryKey, QueryManagerCore, QueryOptions, QueryState, SetDataUpdater, dangerClearCache, fetchQuery, getQueryData, getQueryState, invalidateQuery, queryManager, registerFetcher, serializeKey, setDefaultConfig, setQueryData, subscribeQuery };
package/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
- function c(t){return Array.isArray(t)?t.join("-"):String(t)}function l(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,s=r;if(Array.isArray(e)&&Array.isArray(s)){if(e.length!==s.length)return !1;for(let o=0;o<e.length;o++)if(a==="deep"){if(!l(e[o],s[o],a))return !1}else if(e[o]!==s[o])return !1;return !0}if(Array.isArray(e)||Array.isArray(s))return !1;let n=Object.keys(e),u=Object.keys(s);if(n.length!==u.length)return !1;for(let o=0;o<n.length;o++){let y=n[o];if(a==="deep"){if(!l(e[y],s[y],a))return !1}else if(e[y]!==s[y])return !1}return !0}catch{return !1}}function f(t,r){return r||((a,e)=>l(a,e,t||"shallow"))}function p(t,r){return {status:"idle",updatedAt:void 0,staleTime:t?.staleTime??0,isInvalidated:!1,fetcher:t?.fetcher,equalityFn:f(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,s=!1;switch(t.status){case"error":t.usePreviousDataOnError&&t.data!==void 0?e=t.data:t.usePlaceholderOnError&&t.placeholderData!==void 0&&(e=t.placeholderData,s=!0);break;case"fetching":t.data!==void 0?(e=t.data,s=!1):t.placeholderData&&(e=t.placeholderData,s=!0);break;case"success":case"idle":e=t.data??t.placeholderData,s=t.data?!1:!!t.placeholderData;break}return {data:e,error:t.error,status:t.status,updatedAt:t.updatedAt,isStale:a,isPlaceholderData:s,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 h=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:a,...e}){this.defaultConfig={...this.defaultConfig,...e},r!==void 0&&(this.throttleTime=r),a&&(this.persister=a,this.persister?.load(this.cache,this.hasQueriesBeenUsed));}ensureState(r,a={}){this.hasQueriesBeenUsed=!0;let e=c(r),s=this.cache.get(e);if(s){let n=s.fromPersisterCache?{...s,...this.defaultConfig,...a}:{...this.defaultConfig,...s,...a};Object.assign(s,n),s.enabled=n.enabled!==!1,s.fromPersisterCache=!1,this.cache.set(e,s);}else {let n={...this.defaultConfig,...a},u=p(n,()=>this.fetchQuery(r));this.cache.set(e,u);}return this.persister?.sync(this.cache),this.cache.get(e)}emit(r,a){let e=c(r);this.cache.set(e,a),this.persister?.sync(this.cache);let s=this.subs.get(e);if(!s)return;let n=d(a);for(let u of Array.from(s))u(n);}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 s=e.fetcher;if(!s)return e.updatedAt===void 0&&Q(r),Promise.resolve(e.data);let n=s();return e.fetchPromise=n,e.status="fetching",e.lastFetchTime=Date.now(),this.emit(r,e),n.then(u=>{let o=f(e.equalityStrategy,e.equalityFn);e.data=o(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);}),n}setQueryData(r,a){let e=this.ensureState(r),s=e.data;f(e.equalityStrategy,e.equalityFn)(s,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 s=d(e),n=e.lastReturnedState;return !n||!l(n,s,"shallow")?(e.lastReturnedState=s,s):n}invalidateQuery(r){let a=this.ensureState(r);a.isInvalidated=!0,this.emit(r,a),this.fetchQuery(r);}subscribeQuery(r,a,e){let s=c(r),n=this.ensureState(r,e);return this.subs.has(s)||this.subs.set(s,new Set),this.subs.get(s).add(a),this.handleMountLogic(r,n),()=>{this.subs.get(s).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 s=Date.now(),n=a.updatedAt==null||s-(a.updatedAt||0)>a.staleTime||a.isInvalidated,u=!1;a.updatedAt==null?u=!0:(a.refetchOnSubscribe==="always"&&(u=!0),a.refetchOnSubscribe==="stale"&&(u=n)),u&&this.fetchQuery(r);}},g=h;var i=new g;var D=i.registerFetcher.bind(i),O=i.fetchQuery.bind(i),K=i.setQueryData.bind(i),x=i.getQueryData.bind(i),E=i.getQueryState.bind(i),w=i.invalidateQuery.bind(i),A=i.subscribeQuery.bind(i),q=i.setDefaultConfig.bind(i),I=i.dangerClearCache.bind(i);
3
+ function c(t){return Array.isArray(t)?t.join("-"):String(t)}function l(t,a,r="shallow"){if(t===a)return !0;if(t==null||a==null)return t===a;if(typeof t!="object"||typeof a!="object")return !1;try{let e=t,s=a;if(Array.isArray(e)&&Array.isArray(s)){if(e.length!==s.length)return !1;for(let u=0;u<e.length;u++)if(r==="deep"){if(!l(e[u],s[u],r))return !1}else if(e[u]!==s[u])return !1;return !0}if(Array.isArray(e)||Array.isArray(s))return !1;let n=Object.keys(e),i=Object.keys(s);if(n.length!==i.length)return !1;for(let u=0;u<n.length;u++){let f=n[u];if(r==="deep"){if(!l(e[f],s[f],r))return !1}else if(e[f]!==s[f])return !1}return !0}catch{return !1}}function y(t,a){return a||((r,e)=>l(r,e,t||"shallow"))}function p(t,a){return {status:"idle",updatedAt:void 0,staleTime:t?.staleTime??0,isInvalidated:!1,fetcher:t?.fetcher,equalityFn:y(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:a||(()=>Promise.resolve(void 0)),isSuccess:!1,isError:!1,lastReturnedState:void 0,persist:t?.persist!==!1}}function d(t){let a=Date.now(),r=t.updatedAt!==void 0&&a-t.updatedAt>t.staleTime||t.isInvalidated,e,s=!1;switch(t.status){case"error":t.usePreviousDataOnError&&t.data!==void 0?e=t.data:t.usePlaceholderOnError&&t.placeholderData!==void 0&&(e=t.placeholderData,s=!0);break;case"fetching":t.data!==void 0?(e=t.data,s=!1):t.placeholderData&&(e=t.placeholderData,s=!0);break;case"success":case"idle":e=t.data??t.placeholderData,s=t.data?!1:!!t.placeholderData;break}return {data:e,error:t.error,status:t.status,updatedAt:t.updatedAt,isStale:r,isPlaceholderData:s,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 h=class{constructor(){this.cache=new Map;this.subs=new Map;this.defaultConfig={};this.throttleTime=500;this.persister=null;this.hasQueriesBeenUsed=!1;this.dangerClearCache=()=>{this.cache.clear(),this.subs.clear(),this.persister?.clear();};this.setDefaultConfig=({throttleTime:a,persister:r,...e})=>{this.defaultConfig={...this.defaultConfig,...e},a!==void 0&&(this.throttleTime=a),r&&(this.persister=r,this.persister?.load(this.cache,this.hasQueriesBeenUsed));};this.registerFetcher=(a,r)=>{let e=this.ensureState(a,r);this.handleMountLogic(a,e);};this.fetchQuery=(a,r)=>{let e=this.ensureState(a,r);if(e.fetchPromise)return e.fetchPromise;let s=e.fetcher;if(!s)return e.updatedAt===void 0&&Q(a),Promise.resolve(e.data);let n=s();return e.fetchPromise=n,e.status="fetching",e.lastFetchTime=Date.now(),this.emit(a,e),n.then(i=>{let u=y(e.equalityStrategy,e.equalityFn);e.data=u(e.data,i)?e.data:i,e.status="success",e.isError=!1,e.isSuccess=!0,e.updatedAt=Date.now(),e.fetchPromise=void 0,e.error=void 0,this.emit(a,e);}).catch(i=>{e.error=i,e.status="error",e.isError=!0,e.isSuccess=!1,e.updatedAt=Date.now(),e.fetchPromise=void 0,this.emit(a,e);}),n};this.setQueryData=(a,r)=>{let e=this.ensureState(a),s=e.data,n=typeof r=="function"?r(s):r;y(e.equalityStrategy,e.equalityFn)(s,n)||(e.data=n,e.updatedAt=Date.now(),e.error=void 0,e.status="success",e.isInvalidated=!1,e.isError=!1,e.isSuccess=!0,this.emit(a,e));};this.getQueryData=(a,r)=>{let e=this.ensureState(a,r);return this.handleMountLogic(a,e),d(e).data};this.getQueryState=(a,r)=>{let e=this.ensureState(a,r);this.handleMountLogic(a,e);let s=d(e),n=e.lastReturnedState;return !n||!l(n,s,"shallow")?(e.lastReturnedState=s,s):n};this.invalidateQuery=a=>{let r=this.ensureState(a);r.isInvalidated=!0,this.emit(a,r),this.fetchQuery(a);};this.subscribeQuery=(a,r,e)=>{let s=c(a),n=this.ensureState(a,e);return this.subs.has(s)||this.subs.set(s,new Set),this.subs.get(s).add(r),this.handleMountLogic(a,n),()=>{this.subs.get(s).delete(r);}};}ensureState(a,r={}){this.hasQueriesBeenUsed=!0;let e=c(a),s=this.cache.get(e);if(s){let n=s.fromPersisterCache?{...s,...this.defaultConfig,...r}:{...this.defaultConfig,...s,...r};Object.assign(s,n),s.enabled=n.enabled!==!1,s.persist=n.persist!==!1,s.fromPersisterCache=!1,this.cache.set(e,s);}else {let n={...this.defaultConfig,...r},i=p(n,()=>this.fetchQuery(a));this.cache.set(e,i);}return this.persister?.sync(this.cache),this.cache.get(e)}emit(a,r){let e=c(a);this.cache.set(e,r),this.persister?.sync(this.cache);let s=this.subs.get(e);if(!s)return;let n=d(r);for(let i of Array.from(s))i(n);}handleMountLogic(a,r){let e=r.lastFetchTime&&Date.now()-r.lastFetchTime<this.throttleTime;if(r.status==="fetching"||!r.enabled||e||!r.fetcher)return;let s=Date.now(),n=r.updatedAt==null||s-(r.updatedAt||0)>r.staleTime||r.isInvalidated,i=!1;r.updatedAt==null?i=!0:(r.refetchOnSubscribe==="always"&&(i=!0),r.refetchOnSubscribe==="stale"&&(i=n)),i&&this.fetchQuery(a);}},T=h;var o=new T,b=o.registerFetcher,O=o.fetchQuery,K=o.setQueryData,w=o.getQueryData,x=o.getQueryState,E=o.invalidateQuery,A=o.subscribeQuery,q=o.setDefaultConfig,I=o.dangerClearCache;
4
4
 
5
5
  exports.QueryManagerCore = h;
6
- exports._queryManager = i;
7
6
  exports.dangerClearCache = I;
8
7
  exports.fetchQuery = O;
9
- exports.getQueryData = x;
10
- exports.getQueryState = E;
11
- exports.invalidateQuery = w;
12
- exports.registerFetcher = D;
8
+ exports.getQueryData = w;
9
+ exports.getQueryState = x;
10
+ exports.invalidateQuery = E;
11
+ exports.queryManager = o;
12
+ exports.registerFetcher = b;
13
13
  exports.serializeKey = c;
14
14
  exports.setDefaultConfig = q;
15
15
  exports.setQueryData = K;
package/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- function c(t){return Array.isArray(t)?t.join("-"):String(t)}function l(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,s=r;if(Array.isArray(e)&&Array.isArray(s)){if(e.length!==s.length)return !1;for(let o=0;o<e.length;o++)if(a==="deep"){if(!l(e[o],s[o],a))return !1}else if(e[o]!==s[o])return !1;return !0}if(Array.isArray(e)||Array.isArray(s))return !1;let n=Object.keys(e),u=Object.keys(s);if(n.length!==u.length)return !1;for(let o=0;o<n.length;o++){let y=n[o];if(a==="deep"){if(!l(e[y],s[y],a))return !1}else if(e[y]!==s[y])return !1}return !0}catch{return !1}}function f(t,r){return r||((a,e)=>l(a,e,t||"shallow"))}function p(t,r){return {status:"idle",updatedAt:void 0,staleTime:t?.staleTime??0,isInvalidated:!1,fetcher:t?.fetcher,equalityFn:f(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,s=!1;switch(t.status){case"error":t.usePreviousDataOnError&&t.data!==void 0?e=t.data:t.usePlaceholderOnError&&t.placeholderData!==void 0&&(e=t.placeholderData,s=!0);break;case"fetching":t.data!==void 0?(e=t.data,s=!1):t.placeholderData&&(e=t.placeholderData,s=!0);break;case"success":case"idle":e=t.data??t.placeholderData,s=t.data?!1:!!t.placeholderData;break}return {data:e,error:t.error,status:t.status,updatedAt:t.updatedAt,isStale:a,isPlaceholderData:s,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 h=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:a,...e}){this.defaultConfig={...this.defaultConfig,...e},r!==void 0&&(this.throttleTime=r),a&&(this.persister=a,this.persister?.load(this.cache,this.hasQueriesBeenUsed));}ensureState(r,a={}){this.hasQueriesBeenUsed=!0;let e=c(r),s=this.cache.get(e);if(s){let n=s.fromPersisterCache?{...s,...this.defaultConfig,...a}:{...this.defaultConfig,...s,...a};Object.assign(s,n),s.enabled=n.enabled!==!1,s.fromPersisterCache=!1,this.cache.set(e,s);}else {let n={...this.defaultConfig,...a},u=p(n,()=>this.fetchQuery(r));this.cache.set(e,u);}return this.persister?.sync(this.cache),this.cache.get(e)}emit(r,a){let e=c(r);this.cache.set(e,a),this.persister?.sync(this.cache);let s=this.subs.get(e);if(!s)return;let n=d(a);for(let u of Array.from(s))u(n);}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 s=e.fetcher;if(!s)return e.updatedAt===void 0&&Q(r),Promise.resolve(e.data);let n=s();return e.fetchPromise=n,e.status="fetching",e.lastFetchTime=Date.now(),this.emit(r,e),n.then(u=>{let o=f(e.equalityStrategy,e.equalityFn);e.data=o(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);}),n}setQueryData(r,a){let e=this.ensureState(r),s=e.data;f(e.equalityStrategy,e.equalityFn)(s,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 s=d(e),n=e.lastReturnedState;return !n||!l(n,s,"shallow")?(e.lastReturnedState=s,s):n}invalidateQuery(r){let a=this.ensureState(r);a.isInvalidated=!0,this.emit(r,a),this.fetchQuery(r);}subscribeQuery(r,a,e){let s=c(r),n=this.ensureState(r,e);return this.subs.has(s)||this.subs.set(s,new Set),this.subs.get(s).add(a),this.handleMountLogic(r,n),()=>{this.subs.get(s).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 s=Date.now(),n=a.updatedAt==null||s-(a.updatedAt||0)>a.staleTime||a.isInvalidated,u=!1;a.updatedAt==null?u=!0:(a.refetchOnSubscribe==="always"&&(u=!0),a.refetchOnSubscribe==="stale"&&(u=n)),u&&this.fetchQuery(r);}},g=h;var i=new g;var D=i.registerFetcher.bind(i),O=i.fetchQuery.bind(i),K=i.setQueryData.bind(i),x=i.getQueryData.bind(i),E=i.getQueryState.bind(i),w=i.invalidateQuery.bind(i),A=i.subscribeQuery.bind(i),q=i.setDefaultConfig.bind(i),I=i.dangerClearCache.bind(i);
1
+ function c(t){return Array.isArray(t)?t.join("-"):String(t)}function l(t,a,r="shallow"){if(t===a)return !0;if(t==null||a==null)return t===a;if(typeof t!="object"||typeof a!="object")return !1;try{let e=t,s=a;if(Array.isArray(e)&&Array.isArray(s)){if(e.length!==s.length)return !1;for(let u=0;u<e.length;u++)if(r==="deep"){if(!l(e[u],s[u],r))return !1}else if(e[u]!==s[u])return !1;return !0}if(Array.isArray(e)||Array.isArray(s))return !1;let n=Object.keys(e),i=Object.keys(s);if(n.length!==i.length)return !1;for(let u=0;u<n.length;u++){let f=n[u];if(r==="deep"){if(!l(e[f],s[f],r))return !1}else if(e[f]!==s[f])return !1}return !0}catch{return !1}}function y(t,a){return a||((r,e)=>l(r,e,t||"shallow"))}function p(t,a){return {status:"idle",updatedAt:void 0,staleTime:t?.staleTime??0,isInvalidated:!1,fetcher:t?.fetcher,equalityFn:y(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:a||(()=>Promise.resolve(void 0)),isSuccess:!1,isError:!1,lastReturnedState:void 0,persist:t?.persist!==!1}}function d(t){let a=Date.now(),r=t.updatedAt!==void 0&&a-t.updatedAt>t.staleTime||t.isInvalidated,e,s=!1;switch(t.status){case"error":t.usePreviousDataOnError&&t.data!==void 0?e=t.data:t.usePlaceholderOnError&&t.placeholderData!==void 0&&(e=t.placeholderData,s=!0);break;case"fetching":t.data!==void 0?(e=t.data,s=!1):t.placeholderData&&(e=t.placeholderData,s=!0);break;case"success":case"idle":e=t.data??t.placeholderData,s=t.data?!1:!!t.placeholderData;break}return {data:e,error:t.error,status:t.status,updatedAt:t.updatedAt,isStale:r,isPlaceholderData:s,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 h=class{constructor(){this.cache=new Map;this.subs=new Map;this.defaultConfig={};this.throttleTime=500;this.persister=null;this.hasQueriesBeenUsed=!1;this.dangerClearCache=()=>{this.cache.clear(),this.subs.clear(),this.persister?.clear();};this.setDefaultConfig=({throttleTime:a,persister:r,...e})=>{this.defaultConfig={...this.defaultConfig,...e},a!==void 0&&(this.throttleTime=a),r&&(this.persister=r,this.persister?.load(this.cache,this.hasQueriesBeenUsed));};this.registerFetcher=(a,r)=>{let e=this.ensureState(a,r);this.handleMountLogic(a,e);};this.fetchQuery=(a,r)=>{let e=this.ensureState(a,r);if(e.fetchPromise)return e.fetchPromise;let s=e.fetcher;if(!s)return e.updatedAt===void 0&&Q(a),Promise.resolve(e.data);let n=s();return e.fetchPromise=n,e.status="fetching",e.lastFetchTime=Date.now(),this.emit(a,e),n.then(i=>{let u=y(e.equalityStrategy,e.equalityFn);e.data=u(e.data,i)?e.data:i,e.status="success",e.isError=!1,e.isSuccess=!0,e.updatedAt=Date.now(),e.fetchPromise=void 0,e.error=void 0,this.emit(a,e);}).catch(i=>{e.error=i,e.status="error",e.isError=!0,e.isSuccess=!1,e.updatedAt=Date.now(),e.fetchPromise=void 0,this.emit(a,e);}),n};this.setQueryData=(a,r)=>{let e=this.ensureState(a),s=e.data,n=typeof r=="function"?r(s):r;y(e.equalityStrategy,e.equalityFn)(s,n)||(e.data=n,e.updatedAt=Date.now(),e.error=void 0,e.status="success",e.isInvalidated=!1,e.isError=!1,e.isSuccess=!0,this.emit(a,e));};this.getQueryData=(a,r)=>{let e=this.ensureState(a,r);return this.handleMountLogic(a,e),d(e).data};this.getQueryState=(a,r)=>{let e=this.ensureState(a,r);this.handleMountLogic(a,e);let s=d(e),n=e.lastReturnedState;return !n||!l(n,s,"shallow")?(e.lastReturnedState=s,s):n};this.invalidateQuery=a=>{let r=this.ensureState(a);r.isInvalidated=!0,this.emit(a,r),this.fetchQuery(a);};this.subscribeQuery=(a,r,e)=>{let s=c(a),n=this.ensureState(a,e);return this.subs.has(s)||this.subs.set(s,new Set),this.subs.get(s).add(r),this.handleMountLogic(a,n),()=>{this.subs.get(s).delete(r);}};}ensureState(a,r={}){this.hasQueriesBeenUsed=!0;let e=c(a),s=this.cache.get(e);if(s){let n=s.fromPersisterCache?{...s,...this.defaultConfig,...r}:{...this.defaultConfig,...s,...r};Object.assign(s,n),s.enabled=n.enabled!==!1,s.persist=n.persist!==!1,s.fromPersisterCache=!1,this.cache.set(e,s);}else {let n={...this.defaultConfig,...r},i=p(n,()=>this.fetchQuery(a));this.cache.set(e,i);}return this.persister?.sync(this.cache),this.cache.get(e)}emit(a,r){let e=c(a);this.cache.set(e,r),this.persister?.sync(this.cache);let s=this.subs.get(e);if(!s)return;let n=d(r);for(let i of Array.from(s))i(n);}handleMountLogic(a,r){let e=r.lastFetchTime&&Date.now()-r.lastFetchTime<this.throttleTime;if(r.status==="fetching"||!r.enabled||e||!r.fetcher)return;let s=Date.now(),n=r.updatedAt==null||s-(r.updatedAt||0)>r.staleTime||r.isInvalidated,i=!1;r.updatedAt==null?i=!0:(r.refetchOnSubscribe==="always"&&(i=!0),r.refetchOnSubscribe==="stale"&&(i=n)),i&&this.fetchQuery(a);}},T=h;var o=new T,b=o.registerFetcher,O=o.fetchQuery,K=o.setQueryData,w=o.getQueryData,x=o.getQueryState,E=o.invalidateQuery,A=o.subscribeQuery,q=o.setDefaultConfig,I=o.dangerClearCache;
2
2
 
3
- export { h as QueryManagerCore, i as _queryManager, I as dangerClearCache, O as fetchQuery, x as getQueryData, E as getQueryState, w as invalidateQuery, D as registerFetcher, c as serializeKey, q as setDefaultConfig, K as setQueryData, A as subscribeQuery };
3
+ export { h as QueryManagerCore, I as dangerClearCache, O as fetchQuery, w as getQueryData, x as getQueryState, E as invalidateQuery, o as queryManager, b as registerFetcher, c as serializeKey, q as setDefaultConfig, K as setQueryData, A as subscribeQuery };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qortex-core",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Framework-agnostic query cache & fetch registry (MFE friendly).",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -28,7 +28,7 @@
28
28
  "persister.js",
29
29
  "persister.mjs",
30
30
  "persister.d.ts",
31
- "types-61b54557.d.ts",
31
+ "types-15a3228d.d.ts",
32
32
  "README.md"
33
33
  ],
34
34
  "repository": {
package/persister.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PersisterConfig, B as BasePersister } from './types-61b54557.js';
2
- export { e as Persister } from './types-61b54557.js';
1
+ import { P as PersisterConfig, B as BasePersister } from './types-15a3228d.js';
2
+ export { e as Persister } from './types-15a3228d.js';
3
3
 
4
4
  /**
5
5
  * Creates a persister instance for data persistence.
@@ -12,7 +12,7 @@ export { e as Persister } from './types-61b54557.js';
12
12
  * - `'local'`: Uses localStorage for persistent data across browser sessions
13
13
  * - `'session'`: Uses sessionStorage for data that persists only during the current session
14
14
  * @param {PersisterConfig} [config] - Optional configuration for the persister
15
- * - `burstKey`: Default `"0.3.0"`
15
+ * - `burstKey`: Default `"package version"`
16
16
  * - `prefix`: Default `"qortex"`
17
17
  * - `debounceTime`: Default `100` (ms)
18
18
  * @returns {Persister | undefined} A persister instance, or undefined if storage is not available
package/persister.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
2
 
3
- function g(e){return typeof e=="string"&&["idle","fetching","success","error"].includes(e)}function h(e){return typeof e=="string"&&["shallow","deep"].includes(e)}function b(e){return e===!1||typeof e=="string"&&["always","stale"].includes(e)}function P(e){return !(!e||typeof e!="object"||!g(e.status)||typeof e.staleTime!="number"||e.staleTime<0||typeof e.isInvalidated!="boolean"||!h(e.equalityStrategy)||!b(e.refetchOnSubscribe))}function l(e){if(!e||typeof e!="object"||!e.queries||typeof e.queries!="object")return !1;for(let[t,r]of Object.entries(e.queries))if(typeof t!="string"||!P(r))return !1;return !(typeof e.burstKey!="string"||typeof e.timestamp!="number"||e.timestamp<0)}function u(e){let{fetcher:t,equalityFn:r,fetchPromise:s,refetch:i,fromPersisterCache:o,...n}=e;return n}function f(e,t){return {...t??{},...e,fromPersisterCache:!t}}function y(e){try{let t=JSON.parse(e);return l(t)?t:null}catch{return null}}var c=()=>{console.warn("[Qortex] No storage found, persister will not be able to persist data");},p=()=>{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 a=class{constructor(t,r){this.syncTimeout=null;this.debounceTime=100;this.burstKey="0.3.0";this.storageKey="qortex";this.storage=t,this.burstKey=r?.burstKey??this.burstKey,this.storageKey=r?.prefix??this.storageKey,this.debounceTime=r?.debounceTime??this.debounceTime;}save(t){try{let r={queries:{},burstKey:this.burstKey,timestamp:Date.now()};for(let[i,o]of Object.entries(t))r.queries[i]=o;let s=JSON.stringify(r);this.storage.setItem(this.storageKey,s);}catch(r){console.warn("[Qortex] Failed to persist state:",r);}}load(t,r){r&&p();try{let s=this.storage.getItem(this.storageKey);if(!s)return;let i=y(s);if(!i){console.warn("[Qortex] Invalid persisted state format, clearing cache"),this.clear();return}if(i.burstKey!==this.burstKey){console.warn("[Qortex] Burst key mismatch, clearing cache"),this.clear();return}for(let[o,n]of Object.entries(i.queries)){let S=n,m=t.get(o),d=f(S,m);t.set(o,d);}}catch(s){console.warn("[Qortex] Failed to load persisted state:",s),this.clear();}}clear(){try{this.storage.removeItem(this.storageKey);}catch(t){console.warn("[Qortex] Failed to clear persisted data:",t);}}sync(t){this.syncTimeout&&clearTimeout(this.syncTimeout),this.syncTimeout=setTimeout(()=>{let r={};for(let[s,i]of t.entries())r[s]=u(i);this.save(r);},this.debounceTime);}};var Q=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}`)}},w=(e,t)=>{let r=Q(e);if(!r){c();return}return new a(r,t)};
3
+ function g(e){return typeof e=="string"&&["idle","fetching","success","error"].includes(e)}function h(e){return typeof e=="string"&&["shallow","deep"].includes(e)}function b(e){return e===!1||typeof e=="string"&&["always","stale"].includes(e)}function P(e){return !(!e||typeof e!="object"||!g(e.status)||typeof e.staleTime!="number"||e.staleTime<0||typeof e.isInvalidated!="boolean"||!h(e.equalityStrategy)||!b(e.refetchOnSubscribe))}function l(e){if(!e||typeof e!="object"||!e.queries||typeof e.queries!="object")return !1;for(let[t,r]of Object.entries(e.queries))if(typeof t!="string"||!P(r))return !1;return !(typeof e.burstKey!="string"||typeof e.timestamp!="number"||e.timestamp<0)}function u(e){let{fetcher:t,equalityFn:r,fetchPromise:s,refetch:i,fromPersisterCache:o,...n}=e;return n}function f(e,t){return {...t??{},...e,fromPersisterCache:!t}}function y(e){try{let t=JSON.parse(e);return l(t)?t:null}catch{return null}}var c=()=>{console.warn("[Qortex] No storage found, persister will not be able to persist data");},p=()=>{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 a=class{constructor(t,r){this.syncTimeout=null;this.debounceTime=100;this.burstKey="0.3.2";this.storageKey="qortex";this.storage=t,this.burstKey=r?.burstKey??this.burstKey,this.storageKey=r?.prefix??this.storageKey,this.debounceTime=r?.debounceTime??this.debounceTime;}save(t){try{let r={queries:{},burstKey:this.burstKey,timestamp:Date.now()};for(let[i,o]of Object.entries(t))r.queries[i]=o;let s=JSON.stringify(r);this.storage.setItem(this.storageKey,s);}catch(r){console.warn("[Qortex] Failed to persist state:",r);}}load(t,r){r&&p();try{let s=this.storage.getItem(this.storageKey);if(!s)return;let i=y(s);if(!i){console.warn("[Qortex] Invalid persisted state format, clearing cache"),this.clear();return}if(i.burstKey!==this.burstKey){console.warn("[Qortex] Burst key mismatch, clearing cache"),this.clear();return}for(let[o,n]of Object.entries(i.queries)){let S=n,m=t.get(o),d=f(S,m);t.set(o,d);}}catch(s){console.warn("[Qortex] Failed to load persisted state:",s),this.clear();}}clear(){try{this.storage.removeItem(this.storageKey);}catch(t){console.warn("[Qortex] Failed to clear persisted data:",t);}}sync(t){this.syncTimeout&&clearTimeout(this.syncTimeout),this.syncTimeout=setTimeout(()=>{let r={};for(let[s,i]of t.entries())i.persist!==!1&&(r[s]=u(i));this.save(r);},this.debounceTime);}};var Q=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}`)}},w=(e,t)=>{let r=Q(e);if(!r){c();return}return new a(r,t)};
4
4
 
5
5
  exports.createPersister = w;
package/persister.mjs CHANGED
@@ -1,3 +1,3 @@
1
- function g(e){return typeof e=="string"&&["idle","fetching","success","error"].includes(e)}function h(e){return typeof e=="string"&&["shallow","deep"].includes(e)}function b(e){return e===!1||typeof e=="string"&&["always","stale"].includes(e)}function P(e){return !(!e||typeof e!="object"||!g(e.status)||typeof e.staleTime!="number"||e.staleTime<0||typeof e.isInvalidated!="boolean"||!h(e.equalityStrategy)||!b(e.refetchOnSubscribe))}function l(e){if(!e||typeof e!="object"||!e.queries||typeof e.queries!="object")return !1;for(let[t,r]of Object.entries(e.queries))if(typeof t!="string"||!P(r))return !1;return !(typeof e.burstKey!="string"||typeof e.timestamp!="number"||e.timestamp<0)}function u(e){let{fetcher:t,equalityFn:r,fetchPromise:s,refetch:i,fromPersisterCache:o,...n}=e;return n}function f(e,t){return {...t??{},...e,fromPersisterCache:!t}}function y(e){try{let t=JSON.parse(e);return l(t)?t:null}catch{return null}}var c=()=>{console.warn("[Qortex] No storage found, persister will not be able to persist data");},p=()=>{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 a=class{constructor(t,r){this.syncTimeout=null;this.debounceTime=100;this.burstKey="0.3.0";this.storageKey="qortex";this.storage=t,this.burstKey=r?.burstKey??this.burstKey,this.storageKey=r?.prefix??this.storageKey,this.debounceTime=r?.debounceTime??this.debounceTime;}save(t){try{let r={queries:{},burstKey:this.burstKey,timestamp:Date.now()};for(let[i,o]of Object.entries(t))r.queries[i]=o;let s=JSON.stringify(r);this.storage.setItem(this.storageKey,s);}catch(r){console.warn("[Qortex] Failed to persist state:",r);}}load(t,r){r&&p();try{let s=this.storage.getItem(this.storageKey);if(!s)return;let i=y(s);if(!i){console.warn("[Qortex] Invalid persisted state format, clearing cache"),this.clear();return}if(i.burstKey!==this.burstKey){console.warn("[Qortex] Burst key mismatch, clearing cache"),this.clear();return}for(let[o,n]of Object.entries(i.queries)){let S=n,m=t.get(o),d=f(S,m);t.set(o,d);}}catch(s){console.warn("[Qortex] Failed to load persisted state:",s),this.clear();}}clear(){try{this.storage.removeItem(this.storageKey);}catch(t){console.warn("[Qortex] Failed to clear persisted data:",t);}}sync(t){this.syncTimeout&&clearTimeout(this.syncTimeout),this.syncTimeout=setTimeout(()=>{let r={};for(let[s,i]of t.entries())r[s]=u(i);this.save(r);},this.debounceTime);}};var Q=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}`)}},w=(e,t)=>{let r=Q(e);if(!r){c();return}return new a(r,t)};
1
+ function g(e){return typeof e=="string"&&["idle","fetching","success","error"].includes(e)}function h(e){return typeof e=="string"&&["shallow","deep"].includes(e)}function b(e){return e===!1||typeof e=="string"&&["always","stale"].includes(e)}function P(e){return !(!e||typeof e!="object"||!g(e.status)||typeof e.staleTime!="number"||e.staleTime<0||typeof e.isInvalidated!="boolean"||!h(e.equalityStrategy)||!b(e.refetchOnSubscribe))}function l(e){if(!e||typeof e!="object"||!e.queries||typeof e.queries!="object")return !1;for(let[t,r]of Object.entries(e.queries))if(typeof t!="string"||!P(r))return !1;return !(typeof e.burstKey!="string"||typeof e.timestamp!="number"||e.timestamp<0)}function u(e){let{fetcher:t,equalityFn:r,fetchPromise:s,refetch:i,fromPersisterCache:o,...n}=e;return n}function f(e,t){return {...t??{},...e,fromPersisterCache:!t}}function y(e){try{let t=JSON.parse(e);return l(t)?t:null}catch{return null}}var c=()=>{console.warn("[Qortex] No storage found, persister will not be able to persist data");},p=()=>{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 a=class{constructor(t,r){this.syncTimeout=null;this.debounceTime=100;this.burstKey="0.3.2";this.storageKey="qortex";this.storage=t,this.burstKey=r?.burstKey??this.burstKey,this.storageKey=r?.prefix??this.storageKey,this.debounceTime=r?.debounceTime??this.debounceTime;}save(t){try{let r={queries:{},burstKey:this.burstKey,timestamp:Date.now()};for(let[i,o]of Object.entries(t))r.queries[i]=o;let s=JSON.stringify(r);this.storage.setItem(this.storageKey,s);}catch(r){console.warn("[Qortex] Failed to persist state:",r);}}load(t,r){r&&p();try{let s=this.storage.getItem(this.storageKey);if(!s)return;let i=y(s);if(!i){console.warn("[Qortex] Invalid persisted state format, clearing cache"),this.clear();return}if(i.burstKey!==this.burstKey){console.warn("[Qortex] Burst key mismatch, clearing cache"),this.clear();return}for(let[o,n]of Object.entries(i.queries)){let S=n,m=t.get(o),d=f(S,m);t.set(o,d);}}catch(s){console.warn("[Qortex] Failed to load persisted state:",s),this.clear();}}clear(){try{this.storage.removeItem(this.storageKey);}catch(t){console.warn("[Qortex] Failed to clear persisted data:",t);}}sync(t){this.syncTimeout&&clearTimeout(this.syncTimeout),this.syncTimeout=setTimeout(()=>{let r={};for(let[s,i]of t.entries())i.persist!==!1&&(r[s]=u(i));this.save(r);},this.debounceTime);}};var Q=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}`)}},w=(e,t)=>{let r=Q(e);if(!r){c();return}return new a(r,t)};
2
2
 
3
3
  export { w as createPersister };
@@ -25,6 +25,7 @@ type QueryStateInternal<T = any, E = unknown> = {
25
25
  isError: boolean;
26
26
  lastReturnedState?: QueryState<T>;
27
27
  fromPersisterCache?: boolean;
28
+ persist: boolean;
28
29
  };
29
30
 
30
31
  type SerializedQueryState = Omit<QueryStateInternal, 'fetcher' | 'fetchPromise' | 'refetch' | 'equalityFn'>;
@@ -62,6 +63,7 @@ declare class BasePersister {
62
63
  /**
63
64
  * Sync with debounced save (100ms delay)
64
65
  * Handles serialization internally
66
+ * Filters out queries with persist: false
65
67
  */
66
68
  sync(cache: Map<string, QueryStateInternal>): void;
67
69
  }
@@ -76,8 +78,13 @@ type QueryKey = string | readonly (string | number)[];
76
78
  type Fetcher<T = any> = () => Promise<T>;
77
79
  /** Function that compares two values for equality */
78
80
  type EqualityFn<T = any> = (a: T | undefined, b: T | undefined) => boolean;
81
+ /**
82
+ * Updater function for setQueryData
83
+ * Receives previous data and returns new data
84
+ */
85
+ type SetDataUpdater<T> = (prevData: T | undefined) => T;
79
86
  /** Strategy for equality comparison */
80
- type EqualityStrategy = 'shallow' | 'deep';
87
+ type EqualityStrategy = "shallow" | "deep";
81
88
  /**
82
89
  * Infers the return type of a fetcher function
83
90
  *
@@ -117,6 +124,8 @@ type QueryOptions<T = any> = {
117
124
  placeholderData?: T;
118
125
  usePreviousDataOnError?: boolean;
119
126
  usePlaceholderOnError?: boolean;
127
+ /** Whether to persist this query's data. Default: true */
128
+ persist?: boolean;
120
129
  };
121
130
  /**
122
131
  * Default configuration options that can be set globally
@@ -151,4 +160,4 @@ type QueryState<T = any, E = unknown> = {
151
160
  refetch: () => Promise<T>;
152
161
  };
153
162
 
154
- export { BasePersister as B, DefaultConfig as D, EqualityFn as E, Fetcher as F, InferFetcherResult as I, PersisterConfig as P, QueryKey as Q, RefetchOnSubscribeOptions as R, QueryOptions as a, QueryState as b, EqualityStrategy as c, QueryStatus as d, Persister as e };
163
+ export { BasePersister as B, DefaultConfig as D, EqualityFn as E, Fetcher as F, InferFetcherResult as I, PersisterConfig as P, QueryKey as Q, RefetchOnSubscribeOptions as R, SetDataUpdater as S, QueryOptions as a, QueryState as b, EqualityStrategy as c, QueryStatus as d, Persister as e };