@choksheak/react-utils 0.3.6 → 0.3.8

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 (54) hide show
  1. package/NoSSR.cjs +37 -0
  2. package/NoSSR.d.mts +24 -0
  3. package/NoSSR.d.ts +20 -0
  4. package/NoSSR.min.cjs +2 -0
  5. package/NoSSR.min.cjs.map +1 -0
  6. package/NoSSR.min.mjs +2 -0
  7. package/NoSSR.min.mjs.map +1 -0
  8. package/NoSSR.mjs +12 -0
  9. package/README.md +10 -1
  10. package/fetcher.cjs +3 -3
  11. package/fetcher.d.mts +5 -4
  12. package/fetcher.d.ts +4 -3
  13. package/fetcher.min.cjs +1 -1
  14. package/fetcher.min.cjs.map +1 -1
  15. package/fetcher.min.mjs +1 -1
  16. package/fetcher.min.mjs.map +1 -1
  17. package/fetcher.mjs +2 -2
  18. package/package.json +21 -3
  19. package/sharedQuery.cjs +486 -486
  20. package/sharedQuery.d.mts +64 -61
  21. package/sharedQuery.d.ts +62 -59
  22. package/sharedQuery.min.cjs +1 -1
  23. package/sharedQuery.min.cjs.map +1 -1
  24. package/sharedQuery.min.mjs +1 -1
  25. package/sharedQuery.min.mjs.map +1 -1
  26. package/sharedQuery.mjs +487 -486
  27. package/sharedState.cjs +201 -199
  28. package/sharedState.d.mts +48 -38
  29. package/sharedState.d.ts +45 -36
  30. package/sharedState.min.cjs +1 -1
  31. package/sharedState.min.cjs.map +1 -1
  32. package/sharedState.min.mjs +1 -1
  33. package/sharedState.min.mjs.map +1 -1
  34. package/sharedState.mjs +202 -199
  35. package/storage.cjs +79 -65
  36. package/storage.d.mts +39 -2
  37. package/storage.d.ts +37 -1
  38. package/storage.min.cjs +1 -1
  39. package/storage.min.cjs.map +1 -1
  40. package/storage.min.mjs +1 -1
  41. package/storage.min.mjs.map +1 -1
  42. package/storage.mjs +77 -65
  43. package/stringify.d.mts +9 -0
  44. package/stringify.d.ts +9 -0
  45. package/stringify.min.cjs.map +1 -1
  46. package/stringify.min.mjs.map +1 -1
  47. package/useDeepMemo.cjs +1 -1
  48. package/useDeepMemo.d.mts +11 -0
  49. package/useDeepMemo.d.ts +11 -0
  50. package/useDeepMemo.min.cjs +1 -1
  51. package/useDeepMemo.min.cjs.map +1 -1
  52. package/useDeepMemo.min.mjs +1 -1
  53. package/useDeepMemo.min.mjs.map +1 -1
  54. package/useDeepMemo.mjs +1 -1
package/sharedQuery.d.mts CHANGED
@@ -1,6 +1,7 @@
1
- import { SharedStateOptions, SharedState } from './sharedState.mjs';
1
+ import { SetStateAction } from 'react';
2
+ import { SharedStateOptions } from './sharedState.mjs';
2
3
  import { PersistTo } from './storage.mjs';
3
- import 'react';
4
+ import '@choksheak/ts-utils/duration';
4
5
  import '@choksheak/ts-utils/storageAdapter';
5
6
 
6
7
  /**
@@ -16,9 +17,13 @@ import '@choksheak/ts-utils/storageAdapter';
16
17
  * records and the total byte size of data can be limited so as to ensure the
17
18
  * query does not take up too much memory.
18
19
  *
20
+ * Think of shared queries as like the open source npm package "react-query",
21
+ * but with strong type-checking and built-in support for persistence.
22
+ *
19
23
  * Example:
20
24
  * ```
21
25
  * import { sharedQuery, useSharedQuery } from "@choksheak/react-utils/sharedQuery";
26
+ * import { MS_PER_DAY } from "@choksheak/ts-utils/timeConstants";
22
27
  *
23
28
  * // Create a new shared query in the top level scope.
24
29
  * // The query function `queryFn` here does not take any arguments.
@@ -37,11 +42,6 @@ import '@choksheak/ts-utils/storageAdapter';
37
42
  * staleMs: MS_PER_DAY,
38
43
  * });
39
44
  *
40
- * // Note that the query will only start fetching on mount in React.
41
- * // But you can do `usersQuery.getCachedOrFetch()` here to prefetch the
42
- * // data if necessary.
43
- * usersQuery.getCachedOrFetch();
44
- *
45
45
  * // Example of using a query function with arguments.
46
46
  * export const getUserQuery = sharedQuery({
47
47
  * queryName: "getUser",
@@ -80,7 +80,9 @@ import '@choksheak/ts-utils/storageAdapter';
80
80
  * export const DisplayOneUser: React.FC<{userId: string}> = ({userId}) => {
81
81
  * // Example of using the query with an argument. Whenever the argument
82
82
  * // changes, the data will be fetched and updated automatically.
83
- * const user = useSharedQuery(getUserQuery, [userId]);
83
+ * const user = useSharedQuery(getUserQuery, userId);
84
+ *
85
+ * // You can check for user.loading and user.error if needed.
84
86
  *
85
87
  * return <>User: {user.data ? JSON.stringify(user.data) : "-"}</>;
86
88
  * };
@@ -121,7 +123,7 @@ type UseQueryResult<TData> = QueryStateValue<TData> & Readonly<{
121
123
  /**
122
124
  * Manually refresh the data by doing a new query.
123
125
  */
124
- refetch: () => void;
126
+ refetch: () => Promise<void>;
125
127
  /**
126
128
  * If you got the data from somewhere else (e.g. an in-memory data update),
127
129
  * just set it directly.
@@ -211,16 +213,25 @@ declare const SharedQueryConfig: {
211
213
  type SharedQueryConfig = typeof SharedQueryConfig;
212
214
  /** Convenience function to update global defaults. */
213
215
  declare function configureSharedQuery(config: Partial<SharedQueryConfig>): void;
214
- /** Please use sharedQuery() instead. */
215
- declare class SharedQuery<TArgs extends unknown[], TData> {
216
- private readonly inflightQueries;
217
- readonly queryState: SharedState<SharedQueryState<TData>>;
218
- /**
219
- * Keep track of the mounted query keys. This handles the case where an
220
- * earlier-started query returns later, and when it returns, it was already
221
- * unmounted, thus making it eligible for clean up right after fetch.
222
- */
223
- private readonly mountedKeys;
216
+ /**
217
+ * Create a reusable shared query object that can be used to auto de-duplicate
218
+ * and cache all data fetches, with auto-expiration and staleness checks.
219
+ *
220
+ * Each `queryName` must be unique, and can only be declared once, most often
221
+ * in the top level scope. The queryName is mainly used for logging and also
222
+ * used as the storage key when you use the top-level `persistTo`.
223
+ *
224
+ * Example:
225
+ * ```
226
+ * export const usersQuery = sharedQuery({
227
+ * queryName: "users",
228
+ * queryFn: listUsers,
229
+ * persistTo: "indexedDb",
230
+ * staleMs: MS_PER_DAY,
231
+ * });
232
+ * ```
233
+ */
234
+ declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQueryOptions<TArgs, TData>): {
224
235
  readonly queryName: string;
225
236
  readonly queryFn: QueryFn<TArgs, TData>;
226
237
  readonly refetchFn: QueryFn<TArgs, TData> | undefined;
@@ -231,9 +242,22 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
231
242
  readonly maxBytes: number;
232
243
  readonly keepLastNonEmptyData: boolean;
233
244
  readonly log: (...args: unknown[]) => void;
234
- constructor(options: SharedQueryOptions<TArgs, TData>);
245
+ readonly queryState: {
246
+ readonly readyPromise: Promise<void>;
247
+ readonly lazy: boolean;
248
+ readonly initStarted: false;
249
+ readonly initDone: false;
250
+ readonly subscribe: (subscriber: () => void) => () => void;
251
+ readonly hasStore: () => boolean;
252
+ readonly setInStore: (value: SharedQueryState<TData>) => Promise<void>;
253
+ readonly getFromStore: () => Promise<SharedQueryState<TData> | undefined>;
254
+ readonly getSnapshot: () => SharedQueryState<TData>;
255
+ readonly setValue: (next: SetStateAction<SharedQueryState<TData>>) => void;
256
+ readonly delete: () => void;
257
+ readonly initDefaultValueOnce: () => Promise<void>;
258
+ };
235
259
  /** Returns a key to identify requests based on the given args. */
236
- getQueryKey(args: TArgs): string;
260
+ readonly getQueryKey: (args: TArgs) => string;
237
261
  /**
238
262
  * Get the AbortController to abort the inflight query (if any).
239
263
  *
@@ -241,8 +265,8 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
241
265
  * using `controller.signal`. So if you need both the controller and the
242
266
  * signal, just use this function.
243
267
  */
244
- getAbortController(args: TArgs): AbortController | null;
245
- getAbortControllerByKey(queryKey: string): AbortController | null;
268
+ readonly getAbortController: (args: TArgs) => AbortController | null;
269
+ readonly getAbortControllerByKey: (queryKey: string) => AbortController | null;
246
270
  /**
247
271
  * Get the AbortSignal to check for query abortions.
248
272
  *
@@ -268,62 +292,41 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
268
292
  * });
269
293
  * ```
270
294
  */
271
- getAbortSignal(args: TArgs): AbortSignal | null;
272
- getAbortSignalByKey(queryKey: string): AbortSignal | null;
273
- private isStale;
274
- private isExpired;
295
+ readonly getAbortSignal: (args: TArgs) => AbortSignal | null;
296
+ readonly getAbortSignalByKey: (queryKey: string) => AbortSignal | null;
275
297
  /** For cached data, we need to return the correct timestamps as well. */
276
- getCachedOrFetch(...args: TArgs): Promise<QueryStateValue<TData>>;
277
- private dedupedFetch;
278
- private startFetching;
298
+ readonly getCachedOrFetch: (...args: TArgs) => Promise<QueryStateValue<TData>>;
279
299
  /** Get the entire stored entry for a query key. */
280
- getQueryValue(queryKey: string): QueryStateValue<TData> | undefined;
300
+ readonly getQueryValue: (queryKey: string) => QueryStateValue<TData> | undefined;
281
301
  /** Get the current stored data for a query key. */
282
- getData(queryKey: string): TData | undefined;
302
+ readonly getData: (queryKey: string) => TData | undefined;
283
303
  /** Set the data directly if the user obtained it from somewhere else. */
284
- setData(queryKey: string, data: TData, dataUpdatedMs?: number): void;
304
+ readonly setData: (queryKey: string, data: TData, dataUpdatedMs?: number) => void;
285
305
  /**
286
306
  * Do a new fetch even when the data is already cached, but don't fetch if
287
307
  * another fetch is already inflight.
288
308
  */
289
- updateFromSource(...args: TArgs): Promise<TData>;
309
+ readonly updateFromSource: (...args: TArgs) => Promise<TData>;
290
310
  /**
291
311
  * Perform an explicit refetch. If `options.refetchFn` was not specified,
292
- * then this would be identical to calling `this.updateFromSource()`.
312
+ * then this would be identical to calling `obj.updateFromSource()`.
293
313
  */
294
- refetch(...args: TArgs): Promise<TData>;
314
+ readonly refetch: (...args: TArgs) => Promise<TData>;
295
315
  /** Delete the cached data for one set of arguments. */
296
- deleteData(queryKey: string): void;
316
+ readonly deleteData: (queryKey: string) => void;
297
317
  /** Delete all currently cached data & all inflight promises. */
298
- clear(): void;
318
+ readonly clear: () => void;
299
319
  /** Keep track of mounted keys. */
300
- mount(queryKey: string): void;
320
+ readonly mount: (queryKey: string) => void;
301
321
  /** Clean up mounted keys. */
302
- unmount(queryKey: string): void;
322
+ readonly unmount: (queryKey: string) => void;
303
323
  /**
304
324
  * Discard the oldest entries if the size exceeds the limit. The last
305
325
  * remaining record cannot be deleted no matter what the limit is.
306
326
  */
307
- enforceSizeLimit(): void;
308
- }
309
- /**
310
- * Create a reusable shared query object that can be used to auto de-duplicate
311
- * and cache all data fetches, with auto-expiration and staleness checks.
312
- *
313
- * Each `queryName` must be unique, and can only be declared once, most often
314
- * in the top level scope. The queryName is used for logging only.
315
- *
316
- * Example:
317
- * ```
318
- * export const usersQuery = sharedQuery({
319
- * queryName: "users",
320
- * queryFn: listUsers,
321
- * persistTo: "indexedDb",
322
- * staleMs: MS_PER_DAY,
323
- * });
324
- * ```
325
- */
326
- declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQueryOptions<TArgs, TData>): SharedQuery<TArgs, TData>;
327
+ readonly enforceSizeLimit: () => void;
328
+ };
329
+ type SharedQuery<TArgs extends unknown[], TData> = ReturnType<typeof sharedQuery<TArgs, TData>>;
327
330
  /**
328
331
  * React hook to make use of a shared query inside any React component. The
329
332
  * args do not need to be specified if no args are needed, i.e. this would work
@@ -338,4 +341,4 @@ declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQuer
338
341
  */
339
342
  declare function useSharedQuery<TArgs extends unknown[], TData>(query: SharedQuery<TArgs, TData>, ...args: TArgs): UseQueryResult<TData>;
340
343
 
341
- export { type QueryFn, type QueryStateValue, SharedQuery, SharedQueryConfig, type SharedQueryOptions, type SharedQueryState, type UseQueryResult, configureSharedQuery, sharedQuery, useSharedQuery };
344
+ export { type QueryFn, type QueryStateValue, type SharedQuery, SharedQueryConfig, type SharedQueryOptions, type SharedQueryState, type UseQueryResult, configureSharedQuery, sharedQuery, useSharedQuery };
package/sharedQuery.d.ts CHANGED
@@ -11,9 +11,13 @@
11
11
  * records and the total byte size of data can be limited so as to ensure the
12
12
  * query does not take up too much memory.
13
13
  *
14
+ * Think of shared queries as like the open source npm package "react-query",
15
+ * but with strong type-checking and built-in support for persistence.
16
+ *
14
17
  * Example:
15
18
  * ```
16
19
  * import { sharedQuery, useSharedQuery } from "@choksheak/react-utils/sharedQuery";
20
+ * import { MS_PER_DAY } from "@choksheak/ts-utils/timeConstants";
17
21
  *
18
22
  * // Create a new shared query in the top level scope.
19
23
  * // The query function `queryFn` here does not take any arguments.
@@ -32,11 +36,6 @@
32
36
  * staleMs: MS_PER_DAY,
33
37
  * });
34
38
  *
35
- * // Note that the query will only start fetching on mount in React.
36
- * // But you can do `usersQuery.getCachedOrFetch()` here to prefetch the
37
- * // data if necessary.
38
- * usersQuery.getCachedOrFetch();
39
- *
40
39
  * // Example of using a query function with arguments.
41
40
  * export const getUserQuery = sharedQuery({
42
41
  * queryName: "getUser",
@@ -75,13 +74,16 @@
75
74
  * export const DisplayOneUser: React.FC<{userId: string}> = ({userId}) => {
76
75
  * // Example of using the query with an argument. Whenever the argument
77
76
  * // changes, the data will be fetched and updated automatically.
78
- * const user = useSharedQuery(getUserQuery, [userId]);
77
+ * const user = useSharedQuery(getUserQuery, userId);
78
+ *
79
+ * // You can check for user.loading and user.error if needed.
79
80
  *
80
81
  * return <>User: {user.data ? JSON.stringify(user.data) : "-"}</>;
81
82
  * };
82
83
  * ```
83
84
  */
84
- import { SharedState, SharedStateOptions } from "./sharedState";
85
+ import { SetStateAction } from "react";
86
+ import { SharedStateOptions } from "./sharedState";
85
87
  import { PersistTo } from "./storage";
86
88
  /** Type of the queryFn used to fetch the data from source. */
87
89
  export type QueryFn<TArgs extends unknown[], TData> = (...args: TArgs) => Promise<TData> | TData;
@@ -117,7 +119,7 @@ export type UseQueryResult<TData> = QueryStateValue<TData> & Readonly<{
117
119
  /**
118
120
  * Manually refresh the data by doing a new query.
119
121
  */
120
- refetch: () => void;
122
+ refetch: () => Promise<void>;
121
123
  /**
122
124
  * If you got the data from somewhere else (e.g. an in-memory data update),
123
125
  * just set it directly.
@@ -207,16 +209,25 @@ export declare const SharedQueryConfig: {
207
209
  export type SharedQueryConfig = typeof SharedQueryConfig;
208
210
  /** Convenience function to update global defaults. */
209
211
  export declare function configureSharedQuery(config: Partial<SharedQueryConfig>): void;
210
- /** Please use sharedQuery() instead. */
211
- export declare class SharedQuery<TArgs extends unknown[], TData> {
212
- private readonly inflightQueries;
213
- readonly queryState: SharedState<SharedQueryState<TData>>;
214
- /**
215
- * Keep track of the mounted query keys. This handles the case where an
216
- * earlier-started query returns later, and when it returns, it was already
217
- * unmounted, thus making it eligible for clean up right after fetch.
218
- */
219
- private readonly mountedKeys;
212
+ /**
213
+ * Create a reusable shared query object that can be used to auto de-duplicate
214
+ * and cache all data fetches, with auto-expiration and staleness checks.
215
+ *
216
+ * Each `queryName` must be unique, and can only be declared once, most often
217
+ * in the top level scope. The queryName is mainly used for logging and also
218
+ * used as the storage key when you use the top-level `persistTo`.
219
+ *
220
+ * Example:
221
+ * ```
222
+ * export const usersQuery = sharedQuery({
223
+ * queryName: "users",
224
+ * queryFn: listUsers,
225
+ * persistTo: "indexedDb",
226
+ * staleMs: MS_PER_DAY,
227
+ * });
228
+ * ```
229
+ */
230
+ export declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQueryOptions<TArgs, TData>): {
220
231
  readonly queryName: string;
221
232
  readonly queryFn: QueryFn<TArgs, TData>;
222
233
  readonly refetchFn: QueryFn<TArgs, TData> | undefined;
@@ -227,9 +238,22 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
227
238
  readonly maxBytes: number;
228
239
  readonly keepLastNonEmptyData: boolean;
229
240
  readonly log: (...args: unknown[]) => void;
230
- constructor(options: SharedQueryOptions<TArgs, TData>);
241
+ readonly queryState: {
242
+ readonly readyPromise: Promise<void>;
243
+ readonly lazy: boolean;
244
+ readonly initStarted: false;
245
+ readonly initDone: false;
246
+ readonly subscribe: (subscriber: () => void) => () => void;
247
+ readonly hasStore: () => boolean;
248
+ readonly setInStore: (value: SharedQueryState<TData>) => Promise<void>;
249
+ readonly getFromStore: () => Promise<SharedQueryState<TData> | undefined>;
250
+ readonly getSnapshot: () => SharedQueryState<TData>;
251
+ readonly setValue: (next: SetStateAction<SharedQueryState<TData>>) => void;
252
+ readonly delete: () => void;
253
+ readonly initDefaultValueOnce: () => Promise<void>;
254
+ };
231
255
  /** Returns a key to identify requests based on the given args. */
232
- getQueryKey(args: TArgs): string;
256
+ readonly getQueryKey: (args: TArgs) => string;
233
257
  /**
234
258
  * Get the AbortController to abort the inflight query (if any).
235
259
  *
@@ -237,8 +261,8 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
237
261
  * using `controller.signal`. So if you need both the controller and the
238
262
  * signal, just use this function.
239
263
  */
240
- getAbortController(args: TArgs): AbortController | null;
241
- getAbortControllerByKey(queryKey: string): AbortController | null;
264
+ readonly getAbortController: (args: TArgs) => AbortController | null;
265
+ readonly getAbortControllerByKey: (queryKey: string) => AbortController | null;
242
266
  /**
243
267
  * Get the AbortSignal to check for query abortions.
244
268
  *
@@ -264,62 +288,41 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
264
288
  * });
265
289
  * ```
266
290
  */
267
- getAbortSignal(args: TArgs): AbortSignal | null;
268
- getAbortSignalByKey(queryKey: string): AbortSignal | null;
269
- private isStale;
270
- private isExpired;
291
+ readonly getAbortSignal: (args: TArgs) => AbortSignal | null;
292
+ readonly getAbortSignalByKey: (queryKey: string) => AbortSignal | null;
271
293
  /** For cached data, we need to return the correct timestamps as well. */
272
- getCachedOrFetch(...args: TArgs): Promise<QueryStateValue<TData>>;
273
- private dedupedFetch;
274
- private startFetching;
294
+ readonly getCachedOrFetch: (...args: TArgs) => Promise<QueryStateValue<TData>>;
275
295
  /** Get the entire stored entry for a query key. */
276
- getQueryValue(queryKey: string): QueryStateValue<TData> | undefined;
296
+ readonly getQueryValue: (queryKey: string) => QueryStateValue<TData> | undefined;
277
297
  /** Get the current stored data for a query key. */
278
- getData(queryKey: string): TData | undefined;
298
+ readonly getData: (queryKey: string) => TData | undefined;
279
299
  /** Set the data directly if the user obtained it from somewhere else. */
280
- setData(queryKey: string, data: TData, dataUpdatedMs?: number): void;
300
+ readonly setData: (queryKey: string, data: TData, dataUpdatedMs?: number) => void;
281
301
  /**
282
302
  * Do a new fetch even when the data is already cached, but don't fetch if
283
303
  * another fetch is already inflight.
284
304
  */
285
- updateFromSource(...args: TArgs): Promise<TData>;
305
+ readonly updateFromSource: (...args: TArgs) => Promise<TData>;
286
306
  /**
287
307
  * Perform an explicit refetch. If `options.refetchFn` was not specified,
288
- * then this would be identical to calling `this.updateFromSource()`.
308
+ * then this would be identical to calling `obj.updateFromSource()`.
289
309
  */
290
- refetch(...args: TArgs): Promise<TData>;
310
+ readonly refetch: (...args: TArgs) => Promise<TData>;
291
311
  /** Delete the cached data for one set of arguments. */
292
- deleteData(queryKey: string): void;
312
+ readonly deleteData: (queryKey: string) => void;
293
313
  /** Delete all currently cached data & all inflight promises. */
294
- clear(): void;
314
+ readonly clear: () => void;
295
315
  /** Keep track of mounted keys. */
296
- mount(queryKey: string): void;
316
+ readonly mount: (queryKey: string) => void;
297
317
  /** Clean up mounted keys. */
298
- unmount(queryKey: string): void;
318
+ readonly unmount: (queryKey: string) => void;
299
319
  /**
300
320
  * Discard the oldest entries if the size exceeds the limit. The last
301
321
  * remaining record cannot be deleted no matter what the limit is.
302
322
  */
303
- enforceSizeLimit(): void;
304
- }
305
- /**
306
- * Create a reusable shared query object that can be used to auto de-duplicate
307
- * and cache all data fetches, with auto-expiration and staleness checks.
308
- *
309
- * Each `queryName` must be unique, and can only be declared once, most often
310
- * in the top level scope. The queryName is used for logging only.
311
- *
312
- * Example:
313
- * ```
314
- * export const usersQuery = sharedQuery({
315
- * queryName: "users",
316
- * queryFn: listUsers,
317
- * persistTo: "indexedDb",
318
- * staleMs: MS_PER_DAY,
319
- * });
320
- * ```
321
- */
322
- export declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQueryOptions<TArgs, TData>): SharedQuery<TArgs, TData>;
323
+ readonly enforceSizeLimit: () => void;
324
+ };
325
+ export type SharedQuery<TArgs extends unknown[], TData> = ReturnType<typeof sharedQuery<TArgs, TData>>;
323
326
  /**
324
327
  * React hook to make use of a shared query inside any React component. The
325
328
  * args do not need to be specified if no args are needed, i.e. this would work
@@ -1,2 +1,2 @@
1
- "use strict";var q=Object.create;var w=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var Y=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var J=(r,e)=>{for(var t in e)w(r,t,{get:e[t],enumerable:!0})},$=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of j(e))!I.call(r,s)&&s!==t&&w(r,s,{get:()=>e[s],enumerable:!(a=_(e,s))||a.enumerable});return r};var O=(r,e,t)=>(t=r!=null?q(Y(r)):{},$(e||!r||!r.__esModule?w(t,"default",{value:r,enumerable:!0}):t,r)),W=r=>$(w({},"__esModule",{value:!0}),r);var ee={};J(ee,{SharedQuery:()=>A,SharedQueryConfig:()=>g,configureSharedQuery:()=>H,sharedQuery:()=>X,useSharedQuery:()=>Z});module.exports=W(ee);var R=require("@choksheak/ts-utils/timeConstants"),D=O(require("object-sizeof")),y=require("react");var C=require("@choksheak/ts-utils/timeConstants"),V=require("react");var T=require("@choksheak/ts-utils/kvStore"),B=require("@choksheak/ts-utils/localStore"),S=typeof window>"u";function K(r,e){let{store:t}=r??{};if(!t)return null;if("persistTo"in t&&typeof t.persistTo=="string"&&"key"in t&&typeof t.key=="string"){let a=t.expiryMs||e,s=t.isValid;switch(t.persistTo){case"localStorage":{let n=new B.LocalStore(t.key,{defaultExpiryMs:a});return{set:(i,o)=>{S||n.set(i,o)},get:i=>{if(S)return;let o=n.get(i);if(s&&!s(o)){console.warn(`localStorage adapter: Auto-discard invalid value for ${i}: ${JSON.stringify(o)}`),n.delete(i);return}return o},delete:i=>{S||n.delete(i)},clear:()=>{S||n.clear()}}}case"indexedDb":{let n=t.key+":",i=t.isValid;return{set:async(o,c)=>{S||await T.kvStore.set(n+o,c,a)},get:async o=>{if(S)return;let c=n+o,h=await T.kvStore.get(c);if(i&&!i(h)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${o}: ${JSON.stringify(h)}`),await T.kvStore.delete(c);return}return h},delete:async o=>{S||await T.kvStore.delete(n+o)},clear:async()=>{S||await T.kvStore.clear()}}}default:throw t.persistTo,new Error(`Unknown store.adapter ${t.persistTo}`)}}return t}var N={storeExpiryMs:30*C.MS_PER_DAY,lazyLoad:!1};var Q=class{dataByKey=new Map;subscribersByKey=new Map;get(e){return this.dataByKey.get(e)}set(e,t){let a=this.dataByKey.get(e);a!==t&&(this.dataByKey.set(e,t),this.notify(e,t,a))}delete(e){this.dataByKey.delete(e)}setNoNotify(e,t){this.dataByKey.set(e,t)}subscribe(e,t){let a=this.subscribersByKey.get(e);return a||(a=new Set,this.subscribersByKey.set(e,a)),a.add(t),()=>{a.delete(t),a.size===0&&this.subscribersByKey.delete(e)}}notify(e,t,a){let s=this.subscribersByKey.get(e);if(!s)return;let n=Array.from(s.values());for(let i of n)try{i(t,a)}catch(o){console.error("Error invoking subscriber:",o)}}},b=new Q,M="state",G=0,v=class{constructor(e,t){this.defaultValue=e;let a=()=>{};this.readyPromise=new Promise(i=>{a=i}),this.resolveReadyPromise=a,this.pubSubKey=String(G++),this.storageAdapter=K(t,N.storeExpiryMs),this.setValueBounded=i=>{this.setValue(i)},b.setNoNotify(this.pubSubKey,e);let s=t?.lazyLoad;(s!==void 0?s:N.lazyLoad)||this.initDefaultValueOnce()}pubSubKey;storageAdapter;setValueBounded;initStarted=!1;initDone=!1;readyPromise;resolveReadyPromise;subscribe(e){return b.subscribe(this.pubSubKey,()=>e())}hasStore(){return!!this.storageAdapter}async setInStore(e){return await this.storageAdapter?.set(M,e)}async getFromStore(){return await this.storageAdapter?.get(M)}getSnapshot(){return b.get(this.pubSubKey)}setValue(e){if(typeof e=="function"){let t=b.get(this.pubSubKey);e=e(t)}b.set(this.pubSubKey,e),this.setInStore(e)}delete(){b.set(this.pubSubKey,this.defaultValue),this.storageAdapter?.set(M,this.defaultValue)}async initDefaultValueOnce(){if(this.initDone||this.initStarted)return;this.initStarted=!0;let e=await this.getFromStore(),t=e!==void 0?e:this.defaultValue;b.set(this.pubSubKey,t),this.initDone=!0,this.resolveReadyPromise()}};function z(r,e){return new v(r,e)}function F(r){return r.initDefaultValueOnce(),[(0,V.useSyncExternalStore)(t=>r.subscribe(t),()=>r.getSnapshot(),()=>r.getSnapshot()),r.setValueBounded]}function k(r){let e=new Set;return JSON.stringify(r,(t,a)=>{if(typeof a=="function")throw new Error("Functions should not be passed into query parameters");if(!a||typeof a!="object"||Array.isArray(a))return a;if(e.has(a))return"[Circular]";if(e.add(a),a!==r)try{JSON.stringify(a)}catch{return"[Unserializable]"}return Object.keys(a).sort().reduce((s,n)=>(s[n]=a[n],s),{})})}var E=O(require("lodash/isEqual")),x=require("react");function U(r){let[e,t]=(0,x.useState)(r);return(0,x.useMemo)(()=>e===r||(0,E.default)(e,r)?e:(t(r),r),[e,r])}var g={staleMs:0,expiryMs:30*R.MS_PER_DAY,refetchOnStale:!0,persistTo:void 0,maxSize:100,maxBytes:1e5,log:(...r)=>console.log("[sharedQuery]",...r)};function H(r){Object.assign(g,r)}var A=class{inflightQueries=new Map;queryState;mountedKeys=new Map;queryName;queryFn;refetchFn;expiryMs;staleMs;refetchOnStale;maxSize;maxBytes;keepLastNonEmptyData;log;constructor(e){if(this.queryName=e.queryName,this.queryFn=e.queryFn,this.refetchFn=e.refetchFn,this.staleMs=e?.staleMs??g.staleMs,this.expiryMs=e?.expiryMs??g.expiryMs,this.refetchOnStale=e?.refetchOnStale??g.refetchOnStale,!e.store){let t=e.persistTo??g.persistTo;t&&(e.store={persistTo:t,key:e.queryName,expiryMs:this.expiryMs})}this.maxSize=e?.maxSize??g.maxSize,this.maxBytes=e?.maxBytes??g.maxBytes,this.keepLastNonEmptyData=!!e?.keepLastNonEmptyData,this.log=e?.log??g.log,this.queryState=z({},e)}getQueryKey(e){return this.queryName+":"+k(e)}getAbortController(e){let t=this.getQueryKey(e);return this.getAbortControllerByKey(t)}getAbortControllerByKey(e){return this.inflightQueries.get(e)?.abortController??null}getAbortSignal(e){let t=this.getQueryKey(e);return this.getAbortSignalByKey(t)}getAbortSignalByKey(e){return this.getAbortControllerByKey(e)?.signal??null}isStale(e){return this.staleMs===0?!0:Date.now()-e>this.staleMs}isExpired(e){return this.expiryMs===0?!1:Date.now()-e>this.expiryMs}async getCachedOrFetch(...e){let t=Date.now();await this.queryState.readyPromise;let a=Date.now()-t,s=this.getQueryKey(e),n=this.queryState.getSnapshot()?.[s];if(a&&this.log(`${s}: Waited for ${a}ms before data is ready`),n?.data&&!this.isExpired(n.dataUpdatedMs??0))return this.isStale(n.dataUpdatedMs??0)?(this.refetchOnStale&&(this.log(`refetchOnStale for ${s}`),this.dedupedFetch(s,"query",...e)),this.log(`Returning stale data for ${s}`),n):(this.log(`Return fresh data ${s} from cache without fetching`),n);let i=await this.dedupedFetch(s,"query",...e),o=Date.now();return{lastUpdatedMs:o,loading:!1,data:i,dataUpdatedMs:o}}dedupedFetch(e,t,...a){let s=this.inflightQueries.get(e);if(s)return this.log(`Deduplicating inflight fetch for ${e}, queryType=${t}`),s.promise;let n=this.startFetching(e,t,a),i=new AbortController;return this.inflightQueries.set(e,{promise:n,abortController:i}),n}async startFetching(e,t,a){this.log(`Start fetching ${e}, queryType=${t}`);try{let s=await(t==="refetch"&&this.refetchFn?this.refetchFn(...a):this.queryFn(...a));return this.log(`Successfully fetched ${e}`),this.setData(e,s,Date.now()),s}catch(s){throw this.log(`Failed to fetch ${e} for queryType=${t}: ${s}`),s}finally{this.inflightQueries.delete(e)}}getQueryValue(e){return this.queryState.getSnapshot()?.[e]}getData(e){let t=this.queryState.getSnapshot()?.[e];if(t?.lastUpdatedMs&&this.isExpired(t.lastUpdatedMs)){this.deleteData(e);return}return t?.data}setData(e,t,a=Date.now()){let s={lastUpdatedMs:Date.now(),loading:!1,data:t,dataUpdatedMs:a};this.queryState.setValue(n=>({...n,[e]:s})),this.enforceSizeLimit()}async updateFromSource(...e){let t=this.getQueryKey(e);return await this.dedupedFetch(t,"query",...e)}async refetch(...e){let t=this.getQueryKey(e);return await this.dedupedFetch(t,"refetch",...e)}deleteData(e){let a={...this.queryState.getSnapshot()};delete a[e],this.queryState.setValue(a);let s=this.inflightQueries.get(e);s&&(this.inflightQueries.delete(e),s.abortController.abort("Deleted"))}clear(){this.queryState.delete();for(let{abortController:e}of Array.from(this.inflightQueries.values()))e.abort("Cleared");this.inflightQueries.clear()}mount(e){this.mountedKeys.set(e,(this.mountedKeys.get(e)??0)+1)}unmount(e){let t=this.mountedKeys.get(e);t===1?this.mountedKeys.delete(e):this.mountedKeys.set(e,(t??0)-1)}enforceSizeLimit(){if(!this.maxSize&&!this.maxBytes)return;let e=this.queryState.getSnapshot(),t=Object.keys(e).length;if(t<=1)return;let a=(0,D.default)(e),s=this.maxSize?t-this.maxSize:0,n=this.maxBytes?a-this.maxBytes:0;if(s<=0&&n<=0){this.log(`No need to trim data for ${this.queryName}: size=${t} (limit=${this.maxSize}), byteSize=${a.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`);return}this.log(`Need to trim ${this.queryName}: numToCut=${s}, bytesToCut=${n}`);let i={...e},o=!1,c=(u,f)=>{if(this.mountedKeys.has(u)){this.log(`Cannot clean up ${u} as it is mounted`);return}let l=(0,D.default)(u)+(0,D.default)(i[u]);this.log(`Cleaning up unmounted${f?", expired":""} ${u} (byteSize=${l.toLocaleString()})`),s--,n-=l,delete i[u],o=!0},h=Object.entries(i).sort((u,f)=>u[1].lastUpdatedMs-f[1].lastUpdatedMs);for(let[u]of h){if(!this.isExpired(i[u].lastUpdatedMs))break;c(u,!0)}if(s>0||n>0){o&&(h=Object.entries(i).sort((u,f)=>u[1].lastUpdatedMs-f[1].lastUpdatedMs));for(let[u]of h)if(c(u,!1),s<=0&&n<=0)break}if(!o){this.log(`No trimmable entries found for ${this.queryName}: size=${t} (limit=${this.maxSize}), byteSize=${a.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`);return}this.queryState.setValue(i),this.log(`Trimmed data for ${this.queryName}: size=[${t} -> ${Object.keys(i).length}] (limit=${this.maxSize}), byteSize=[${a.toLocaleString()} -> ${(0,D.default)(i).toLocaleString()}] (limit=${this.maxBytes.toLocaleString()})`)}},P=new Set;function X(r){if(P.has(r.queryName))throw new Error(`Duplicate shared query "${r.queryName}"`);return P.add(r.queryName),new A(r)}var L={lastUpdatedMs:0,loading:!0};function Z(r,...e){let t=U(e),[a,s]=F(r.queryState),n=(0,y.useRef)(!0),i=(0,y.useMemo)(()=>r.getQueryKey(t),[r,t]),o=a[i]??L,c=(0,y.useCallback)(l=>{s(d=>{let p={...d};return p[i]=typeof l=="function"?l(p[i]??L):l,p})},[i,s]),[h,u]=(0,y.useState)();(0,y.useEffect)(()=>{r.keepLastNonEmptyData&&o.data!==void 0&&u(o.data)},[r.keepLastNonEmptyData,o.data]);let f=(0,y.useCallback)(async l=>{if(r.log(`Begin executing shared query ${i}, isRefetch=${l}`),!!n.current){c(d=>({...d,lastUpdatedMs:Date.now(),loading:!0}));try{let d;if(l){let p=await r.refetch(...t),m=Date.now();d={lastUpdatedMs:m,loading:!1,data:p,dataUpdatedMs:m}}else d=await r.getCachedOrFetch(...t);if(!n.current)return;c({...d,loading:!1})}catch(d){if(!n.current)return;let p=Date.now();c(m=>({...m,lastUpdatedMs:p,loading:!1,error:d,errorUpdatedMs:p}))}}},[r,i,c,t]);return(0,y.useEffect)(()=>(n.current=!0,r.mount(i),f(!1),()=>{n.current=!1,r.unmount(i)}),[f,r,i]),(0,y.useMemo)(()=>({...o,lastNonEmptyData:h,abortCurrentQuery:l=>{let d=r.getAbortControllerByKey(i);return d?.abort(l),!!d},refetch:()=>{f(!0)},setData:(l,d)=>{let p=Date.now();c(m=>({...m,data:l,dataUpdatedMs:d??p,lastUpdatedMs:p,loading:!1}))},deleteData:()=>{s(l=>{let d={...l};return delete d[i],d})}}),[f,h,r,i,o,s,c])}0&&(module.exports={SharedQuery,SharedQueryConfig,configureSharedQuery,sharedQuery,useSharedQuery});
1
+ "use strict";var ae=Object.create;var P=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ie=Object.getPrototypeOf,ue=Object.prototype.hasOwnProperty;var de=(e,o)=>{for(var n in o)P(e,n,{get:o[n],enumerable:!0})},K=(e,o,n,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of se(o))!ue.call(e,a)&&a!==n&&P(e,a,{get:()=>o[a],enumerable:!(r=oe(o,a))||r.enumerable});return e};var j=(e,o,n)=>(n=e!=null?ae(ie(e)):{},K(o||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),ce=e=>K(P({},"__esModule",{value:!0}),e);var me={};de(me,{SharedQueryConfig:()=>M,configureSharedQuery:()=>pe,sharedQuery:()=>ye,useSharedQuery:()=>Te});module.exports=ce(me);var re=require("@choksheak/ts-utils/timeConstants"),U=j(require("object-sizeof")),b=require("react");var J=require("@choksheak/ts-utils/timeConstants"),W=require("react");var O=require("@choksheak/ts-utils/kvStore"),_=require("@choksheak/ts-utils/localStore"),x=typeof window>"u";function Y(e,o){let{store:n}=e??{};if(!n)return null;if("persistTo"in n&&typeof n.persistTo=="string"&&"key"in n&&typeof n.key=="string"){let r=n.expiryMs||o,a={...n,expiryMs:r};switch(n.persistTo){case"localStorage":return le(a);case"indexedDb":return fe(a);default:throw n.persistTo,new Error(`Unknown store.adapter ${n.persistTo}`)}}return n}function le({key:e,expiryMs:o,isValid:n}){let r=(0,_.createLocalStore)(e,{defaultExpiryMs:o});return{set:(a,s)=>{x||r.set(a,s)},get:a=>{if(x)return;let s=r.get(a);if(n&&!n(s)){console.warn(`localStorage adapter: Auto-discard invalid value for ${a}: ${JSON.stringify(s)}`),r.delete(a);return}return s},delete:a=>{x||r.delete(a)},clear:()=>{x||r.clear()}}}function fe({key:e,expiryMs:o,isValid:n}){let r=e+":";return{set:async(a,s)=>{x||await O.kvStore.set(r+a,s,o)},get:async a=>{if(x)return;let s=r+a,u=await O.kvStore.get(s);if(u!==void 0&&n&&!n(u)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${a}:`,u),await O.kvStore.delete(s);return}return u},delete:async a=>{x||await O.kvStore.delete(r+a)},clear:async()=>{x||await O.kvStore.clear()}}}var I={storeExpiryMs:30*J.MS_PER_DAY,lazyLoad:!1};function ge(){let e=new Map,o=new Map;function n(r,a,s){let u=o.get(r);if(!u)return;let T=Array.from(u.values());for(let h of T)try{h(a,s)}catch(S){console.error("Error invoking subscriber:",S)}}return{get(r){return e.get(r)},set(r,a){let s=e.get(r);s!==a&&(e.set(r,a),n(r,a,s))},delete(r){e.delete(r)},setNoNotify(r,a){e.set(r,a)},subscribe(r,a){let s=o.get(r);return s||(s=new Set,o.set(r,s)),s.add(a),()=>{s.delete(a),s.size===0&&o.delete(r)}}}}var Q=ge(),z="state",Se=0;function G(e,o){let n=()=>{},r=new Promise(f=>{n=f}),a=n,s=String(Se++),u=Y(o,I.storeExpiryMs);Q.setNoNotify(s,e);let T=o?.lazyLoad,h=T!==void 0?T:I.lazyLoad,S={readyPromise:r,lazy:h,initStarted:!1,initDone:!1,subscribe(f){return Q.subscribe(s,()=>f())},hasStore(){return!!u},async setInStore(f){return await u?.set(z,f)},async getFromStore(){return await u?.get(z)},getSnapshot(){return Q.get(s)},setValue(f){if(typeof f=="function"){let p=Q.get(s);f=f(p)}Q.set(s,f),S.setInStore(f)},delete(){Q.set(s,e),u?.set(z,e)},async initDefaultValueOnce(){if(S.initDone||S.initStarted)return;S.initStarted=!0;let f=await S.getFromStore(),p=f!==void 0?f:e;Q.set(s,p),S.initDone=!0,a()}};return h||S.initDefaultValueOnce(),S}function H(e){return e.initDefaultValueOnce(),[(0,W.useSyncExternalStore)(n=>e.subscribe(n),()=>e.getSnapshot(),()=>e.getSnapshot()),e.setValue]}function X(e){let o=new Set;return JSON.stringify(e,(n,r)=>{if(typeof r=="function")throw new Error("Functions should not be passed into query parameters");if(!r||typeof r!="object"||Array.isArray(r))return r;if(o.has(r))return"[Circular]";if(o.add(r),r!==e)try{JSON.stringify(r)}catch{return"[Unserializable]"}return Object.keys(r).sort().reduce((a,s)=>(a[s]=r[s],a),{})})}var Z=j(require("lodash/isEqual")),E=require("react");function q(e){let[o,n]=(0,E.useState)(e);return(0,E.useMemo)(()=>(0,Z.default)(o,e)?o:(n(e),e),[o,e])}var M={staleMs:0,expiryMs:30*re.MS_PER_DAY,refetchOnStale:!0,persistTo:void 0,maxSize:100,maxBytes:1e5,log:(...e)=>console.log("[sharedQuery]",...e)};function pe(e){Object.assign(M,e)}var ee=new Set;function ye(e){if(ee.has(e.queryName))throw new Error(`Duplicate shared query name "${e.queryName}"`);ee.add(e.queryName);let o=new Map,n=new Map,r=e.queryName,a=e.queryFn,s=e.refetchFn,u=e?.staleMs??M.staleMs,T=e?.expiryMs??M.expiryMs,h=e?.refetchOnStale??M.refetchOnStale,S=e.store;if(S){if("persistTo"in S&&S.isValid){let t=S.isValid;e={...e,store:{...S,isValid:i=>{if(!i||typeof i!="object")return!1;for(let l of Object.values(i))if(!l||typeof l!="object"||!("data"in l)||!("dataUpdatedMs"in l)||!("lastUpdatedMs"in l)||typeof l.dataUpdatedMs!="number"||typeof l.lastUpdatedMs!="number"||!t(l.data))return!1;return!0}}}}}else{let t=e.persistTo??M.persistTo;t&&(e={...e,store:{persistTo:t,key:r,expiryMs:T}})}let f=e?.maxSize??M.maxSize,p=e?.maxBytes??M.maxBytes,D=!!e?.keepLastNonEmptyData,d=e?.log??M.log,g=G({},e);function v(t){return u===0?!0:Date.now()-t>u}function N(t){return T===0?!1:Date.now()-t>T}function R(){if(!f&&!p)return;let t=g.getSnapshot(),i=Object.keys(t).length;if(i<=1)return;let l=(0,U.default)(t),c=f?i-f:0,y=p?l-p:0;if(c<=0&&y<=0){d(`No need to trim data for ${r}: size=${i} (limit=${f}), byteSize=${l.toLocaleString()} (limit=${p.toLocaleString()})`);return}d(`Need to trim ${r}: numToCut=${c}, bytesToCut=${y}`);let w={...t},$=!1,B=(m,C)=>{if(n.has(m)){d(`Cannot clean up ${m} as it is mounted`);return}let F=(0,U.default)(m)+(0,U.default)(w[m]);d(`Cleaning up unmounted${C?", expired":""} ${m} (byteSize=${F.toLocaleString()})`),c--,y-=F,delete w[m],$=!0},V=Object.entries(w).sort((m,C)=>m[1].lastUpdatedMs-C[1].lastUpdatedMs);for(let[m]of V){if(!N(w[m].lastUpdatedMs))break;B(m,!0)}if(c>0||y>0){$&&(V=Object.entries(w).sort((m,C)=>m[1].lastUpdatedMs-C[1].lastUpdatedMs));for(let[m]of V)if(B(m,!1),c<=0&&y<=0)break}if(!$){d(`No trimmable entries found for ${r}: size=${i} (limit=${f}), byteSize=${l.toLocaleString()} (limit=${p.toLocaleString()})`);return}g.setValue(w),d(`Trimmed data for ${r}: size=[${i} -> ${Object.keys(w).length}] (limit=${f}), byteSize=[${l.toLocaleString()} -> ${(0,U.default)(w).toLocaleString()}] (limit=${p.toLocaleString()})`)}function L(t,i,l=Date.now()){let c={lastUpdatedMs:Date.now(),loading:!1,data:i,dataUpdatedMs:l};g.setValue(y=>({...y,[t]:c})),R()}async function ne(t,i,l){d(`Start fetching ${t}, queryType=${i}`);try{let c=await(i==="refetch"&&s?s(...l):a(...l));return d(`Successfully fetched ${t}`),L(t,c,Date.now()),c}catch(c){throw d(`Failed to fetch ${t} for queryType=${i}: ${c}`),c}finally{o.delete(t)}}function k(t,i,...l){let c=o.get(t);if(c)return d(`Deduplicating inflight fetch for ${t}, queryType=${i}`),c.promise;let y=ne(t,i,l),w=new AbortController;return o.set(t,{promise:y,abortController:w}),y}let A={queryName:r,queryFn:a,refetchFn:s,expiryMs:T,staleMs:u,refetchOnStale:h,maxSize:f,maxBytes:p,keepLastNonEmptyData:D,log:d,queryState:g,getQueryKey(t){return r+":"+X(t)},getAbortController(t){let i=A.getQueryKey(t);return A.getAbortControllerByKey(i)},getAbortControllerByKey(t){return o.get(t)?.abortController??null},getAbortSignal(t){let i=A.getQueryKey(t);return A.getAbortSignalByKey(i)},getAbortSignalByKey(t){return A.getAbortControllerByKey(t)?.signal??null},async getCachedOrFetch(...t){let i=Date.now();await g.readyPromise;let l=Date.now()-i,c=A.getQueryKey(t),y=g.getSnapshot()?.[c];if(l&&d(`${c}: Waited for ${l}ms before data is ready`),y?.data&&!N(y.dataUpdatedMs??0))return v(y.dataUpdatedMs??0)?(h&&(d(`refetchOnStale for ${c}`),k(c,"query",...t)),d(`Returning stale data for ${c}`),y):(d(`Return fresh data ${c} from cache without fetching`),y);let w=await k(c,"query",...t),$=Date.now();return{lastUpdatedMs:$,loading:!1,data:w,dataUpdatedMs:$}},getQueryValue(t){return g.getSnapshot()?.[t]},getData(t){let i=g.getSnapshot()?.[t];if(i?.lastUpdatedMs&&N(i.lastUpdatedMs)){A.deleteData(t);return}return i?.data},setData:L,async updateFromSource(...t){let i=A.getQueryKey(t);return await k(i,"query",...t)},async refetch(...t){let i=A.getQueryKey(t);return await k(i,"refetch",...t)},deleteData(t){let l={...g.getSnapshot()};delete l[t],g.setValue(l);let c=o.get(t);c&&(o.delete(t),c.abortController.abort("Deleted"))},clear(){g.delete();for(let{abortController:t}of Array.from(o.values()))t.abort("Cleared");o.clear()},mount(t){n.set(t,(n.get(t)??0)+1)},unmount(t){let i=n.get(t);i===1?n.delete(t):n.set(t,(i??0)-1)},enforceSizeLimit:R};return A}var te={lastUpdatedMs:0,loading:!0};function Te(e,...o){let n=q(o),[r,a]=H(e.queryState),s=(0,b.useRef)(!0),u=(0,b.useMemo)(()=>e.getQueryKey(n),[e,n]),T=r[u]??te,h=(0,b.useCallback)(D=>{a(d=>{let g={...d};return g[u]=typeof D=="function"?D(g[u]??te):D,g})},[u,a]),[S,f]=(0,b.useState)();(0,b.useEffect)(()=>{e.keepLastNonEmptyData&&T.data!==void 0&&f(T.data)},[e.keepLastNonEmptyData,T.data]);let p=(0,b.useCallback)(async D=>{if(e.log(`Begin executing shared query ${u}, isRefetch=${D}`),!!s.current){h(d=>({...d,lastUpdatedMs:Date.now(),loading:!0}));try{let d;if(D){let g=await e.refetch(...n),v=Date.now();d={lastUpdatedMs:v,loading:!1,data:g,dataUpdatedMs:v}}else d=await e.getCachedOrFetch(...n);if(!s.current)return;h({...d,loading:!1})}catch(d){if(!s.current)return;let g=Date.now();h(v=>({...v,lastUpdatedMs:g,loading:!1,error:d,errorUpdatedMs:g}))}}},[e,u,h,n]);return(0,b.useEffect)(()=>(s.current=!0,e.mount(u),p(!1),()=>{s.current=!1,e.unmount(u)}),[p,e,u]),(0,b.useMemo)(()=>({...T,lastNonEmptyData:S,abortCurrentQuery:D=>{let d=e.getAbortControllerByKey(u);return d?.abort(D),!!d},refetch:()=>p(!0),setData:(D,d)=>{e.setData(u,D,d)},deleteData:()=>{e.deleteData(u)}}),[p,S,e,u,T])}0&&(module.exports={SharedQueryConfig,configureSharedQuery,sharedQuery,useSharedQuery});
2
2
  //# sourceMappingURL=sharedQuery.min.cjs.map