@choksheak/react-utils 0.2.7 → 0.2.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@choksheak/react-utils",
3
3
  "license": "The Unlicense",
4
- "version": "0.2.7",
4
+ "version": "0.2.8",
5
5
  "description": "Miscellaneous React+TypeScript utilities with support for full tree-shaking.",
6
6
  "private": false,
7
7
  "files": [
package/sharedQuery.cjs CHANGED
@@ -214,7 +214,9 @@ var SharedState = class {
214
214
  options,
215
215
  SharedStateDefaults.storeExpiryMs
216
216
  );
217
- this.setValueBounded = (arg) => this.setValue(arg);
217
+ this.setValueBounded = (next) => {
218
+ this.setValue(next);
219
+ };
218
220
  pubSubStore.setNoNotify(this.pubSubKey, defaultValue);
219
221
  const lazyLoad = options?.lazyLoad;
220
222
  const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateDefaults.lazyLoad;
@@ -319,19 +321,19 @@ function useDeepMemo(value) {
319
321
 
320
322
  // src/sharedQuery.ts
321
323
  var SharedQueryDefaults = {
322
- // Refetch on every page load.
324
+ /** Refetch on every page load. */
323
325
  staleMs: 0,
324
- // Keep in cache for a long time.
326
+ /** Keep in cache for a long time. */
325
327
  expiryMs: 30 * import_timeConstants2.MS_PER_DAY,
326
- // Always refetch automatically if the data is stale.
328
+ /** Always refetch automatically if the data is stale. */
327
329
  refetchOnStale: true,
328
- // No default persistence configured.
330
+ /** No default persistence configured. */
329
331
  persistTo: void 0,
330
- // 100 is not too large, but please tweak accordingly.
332
+ /** 100 is not too large, but please tweak accordingly. */
331
333
  maxSize: 100,
332
- // 100kb limit before discarding old records.
334
+ /** 100kb limit before discarding old records. */
333
335
  maxBytes: 1e5,
334
- // Default to log to console.
336
+ /** Default to log to console. */
335
337
  log: (...args) => console.log("[sharedQuery]", ...args)
336
338
  };
337
339
  var SharedQuery = class {
@@ -350,6 +352,7 @@ var SharedQuery = class {
350
352
  refetchOnStale;
351
353
  maxSize;
352
354
  maxBytes;
355
+ keepLastNonEmptyData;
353
356
  log;
354
357
  constructor(options) {
355
358
  this.queryName = options.queryName;
@@ -367,6 +370,7 @@ var SharedQuery = class {
367
370
  }
368
371
  this.maxSize = options?.maxSize ?? SharedQueryDefaults.maxSize;
369
372
  this.maxBytes = options?.maxBytes ?? SharedQueryDefaults.maxBytes;
373
+ this.keepLastNonEmptyData = Boolean(options?.keepLastNonEmptyData);
370
374
  this.log = options?.log ?? SharedQueryDefaults.log;
371
375
  this.queryState = sharedState(
372
376
  {},
@@ -556,70 +560,48 @@ var SharedQuery = class {
556
560
  return;
557
561
  }
558
562
  const oldByteSize = (0, import_object_sizeof.default)(oldState);
559
- let newState = oldState;
563
+ let numToCut = this.maxSize ? oldSize - this.maxSize : 0;
564
+ let bytesToCut = this.maxBytes ? oldByteSize - this.maxBytes : 0;
565
+ if (numToCut <= 0 && bytesToCut <= 0) {
566
+ this.log(
567
+ `No need to trim data for ${this.queryName}: size=${oldSize} (limit=${this.maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`
568
+ );
569
+ return;
570
+ }
571
+ this.log(
572
+ `Need to trim ${this.queryName}: numToCut=${numToCut}, bytesToCut=${bytesToCut}`
573
+ );
574
+ const newState = { ...oldState };
560
575
  let needUpdate = false;
561
- if (this.maxSize) {
562
- let numToCut = oldSize - this.maxSize;
563
- if (numToCut > 0) {
564
- this.log(
565
- `enforceSizeLimit for ${this.queryName} needed due to size ${oldSize} > ${this.maxSize}`
566
- );
567
- newState = { ...newState };
568
- needUpdate = true;
569
- const entriesByTimeAscending = Object.entries(newState).sort(
570
- (entry1, entry2) => (
571
- // Sort descending.
572
- entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
573
- )
574
- );
575
- for (let i = 0; i < entriesByTimeAscending.length && numToCut > 0; i++) {
576
- const key = entriesByTimeAscending[i][0];
577
- if (this.mountedKeys.has(key)) {
578
- this.log(`Cannot clean up ${key} as it is mounted`);
579
- } else {
580
- this.log(`Cleaning up unmounted ${key}`);
581
- delete newState[key];
582
- numToCut--;
583
- }
584
- }
576
+ const entriesByTimeAscending = Object.entries(newState).sort(
577
+ (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
578
+ );
579
+ for (const [key] of entriesByTimeAscending) {
580
+ if (this.mountedKeys.has(key)) {
581
+ this.log(`Cannot clean up ${key} as it is mounted`);
582
+ continue;
585
583
  }
586
- }
587
- if (this.maxBytes && Object.keys(newState).length > 1) {
588
- const currentByteSize = needUpdate ? (0, import_object_sizeof.default)(newState) : oldByteSize;
589
- let bytesToCut = currentByteSize - this.maxBytes;
590
- if (bytesToCut > 0) {
591
- this.log(
592
- `enforceSizeLimit for ${this.queryName} needed due to byte size ${currentByteSize.toLocaleString()} > ${this.maxBytes.toLocaleString()}`
593
- );
594
- if (!needUpdate) {
595
- newState = { ...newState };
596
- needUpdate = true;
597
- }
598
- const entriesByTimeAscending = Object.entries(newState).sort(
599
- (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
600
- );
601
- for (let i = 0; i < entriesByTimeAscending.length && bytesToCut > 0; i++) {
602
- const key = entriesByTimeAscending[i][0];
603
- if (this.mountedKeys.has(key)) {
604
- this.log(`Cannot clean up ${key} as it is mounted`);
605
- } else {
606
- this.log(`Cleaning up unmounted ${key}`);
607
- const thisSize = (0, import_object_sizeof.default)(key) + (0, import_object_sizeof.default)(newState[key]);
608
- delete newState[key];
609
- bytesToCut -= thisSize;
610
- }
611
- }
584
+ const byteSize = (0, import_object_sizeof.default)(key) + (0, import_object_sizeof.default)(newState[key]);
585
+ this.log(
586
+ `Cleaning up unmounted ${key} (byteSize=${byteSize.toLocaleString()})`
587
+ );
588
+ numToCut--;
589
+ bytesToCut -= byteSize;
590
+ delete newState[key];
591
+ needUpdate = true;
592
+ if (numToCut <= 0 && bytesToCut <= 0) {
593
+ break;
612
594
  }
613
595
  }
614
- if (needUpdate) {
615
- this.queryState.setValue(newState);
596
+ if (!needUpdate) {
616
597
  this.log(
617
- `Trimmed data for ${this.queryName}: size=(${oldSize} -> ${Object.keys(newState).length}) (limit=${this.maxSize}), byteSize=(${oldByteSize.toLocaleString()} -> ${(0, import_object_sizeof.default)(newState).toLocaleString()}) (limit=${this.maxBytes.toLocaleString()})`
598
+ `No trimmable entries found for ${this.queryName}: size=${oldSize} (limit=${this.maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`
618
599
  );
619
600
  return;
620
601
  }
602
+ this.queryState.setValue(newState);
621
603
  this.log(
622
- `No need to trim data for ${this.queryName}: size=${oldSize} (limit=${this.maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`
604
+ `Trimmed data for ${this.queryName}: size=[${oldSize} -> ${Object.keys(newState).length}] (limit=${this.maxSize}), byteSize=[${oldByteSize.toLocaleString()} -> ${(0, import_object_sizeof.default)(newState).toLocaleString()}] (limit=${this.maxBytes.toLocaleString()})`
623
605
  );
624
606
  }
625
607
  };
@@ -643,23 +625,29 @@ function useSharedQuery(query, args = []) {
643
625
  () => query.getQueryKey(stableArgs),
644
626
  [query, stableArgs]
645
627
  );
646
- const queryStateValue = queryState[queryKey];
628
+ const queryStateValue = queryState[queryKey] ?? DEFAULT_QUERY_STATE_ENTRY;
647
629
  const setQueryStateValue = (0, import_react3.useCallback)(
648
- (arg) => {
630
+ (next) => {
649
631
  setQueryState((prev) => {
650
632
  const clone = { ...prev };
651
- clone[queryKey] = typeof arg === "function" ? arg(clone[queryKey]) : arg;
633
+ clone[queryKey] = typeof next === "function" ? next(clone[queryKey] ?? DEFAULT_QUERY_STATE_ENTRY) : next;
652
634
  return clone;
653
635
  });
654
636
  },
655
637
  [queryKey, setQueryState]
656
638
  );
639
+ const [lastNonEmptyData, setLastNonEmptyData] = (0, import_react3.useState)();
640
+ (0, import_react3.useEffect)(() => {
641
+ if (query.keepLastNonEmptyData && queryStateValue.data !== void 0) {
642
+ setLastNonEmptyData(queryStateValue.data);
643
+ }
644
+ }, [query.keepLastNonEmptyData, queryStateValue.data]);
657
645
  const execute = (0, import_react3.useCallback)(
658
646
  async (forceRefresh) => {
659
647
  query.log(`Begin executing shared query ${queryKey}`);
660
648
  setQueryStateValue((prev) => ({
661
649
  // Keep old data and error.
662
- ...prev ?? {},
650
+ ...prev,
663
651
  lastUpdatedMs: Date.now(),
664
652
  loading: true
665
653
  }));
@@ -680,7 +668,7 @@ function useSharedQuery(query, args = []) {
680
668
  const now = Date.now();
681
669
  setQueryStateValue((prev) => ({
682
670
  // Keep old data.
683
- ...prev ?? {},
671
+ ...prev,
684
672
  lastUpdatedMs: now,
685
673
  loading: false,
686
674
  error: e,
@@ -701,9 +689,9 @@ function useSharedQuery(query, args = []) {
701
689
  };
702
690
  }, [execute, query, queryKey]);
703
691
  return (0, import_react3.useMemo)(() => {
704
- const state = queryStateValue ?? DEFAULT_QUERY_STATE_ENTRY;
705
692
  return {
706
- ...state,
693
+ ...queryStateValue,
694
+ lastNonEmptyData,
707
695
  // This works only if the user-given queryFn supports abort. If not,
708
696
  // this function doesn't do anything, since we don't have any means to
709
697
  // abort the running queryFn.
@@ -718,7 +706,7 @@ function useSharedQuery(query, args = []) {
718
706
  setData: (data, dataUpdatedMs) => {
719
707
  const now = Date.now();
720
708
  setQueryStateValue((prev) => ({
721
- ...prev ?? {},
709
+ ...prev,
722
710
  data,
723
711
  dataUpdatedMs: dataUpdatedMs ?? now,
724
712
  lastUpdatedMs: now,
@@ -735,6 +723,7 @@ function useSharedQuery(query, args = []) {
735
723
  };
736
724
  }, [
737
725
  execute,
726
+ lastNonEmptyData,
738
727
  query,
739
728
  queryKey,
740
729
  queryStateValue,
package/sharedQuery.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { SharedStateOptions, SharedState } from './sharedState.mjs';
2
+ import 'react';
2
3
  import './utils/storage.mjs';
3
4
 
4
5
  /**
@@ -88,7 +89,7 @@ import './utils/storage.mjs';
88
89
  /** Type of the queryFn used to fetch the data from source. */
89
90
  type QueryFn<TArgs extends unknown[], TData> = (...args: TArgs) => Promise<TData> | TData;
90
91
  /** An entry for a persisted state corresponding to one query key. */
91
- type QueryStateValue<TData> = {
92
+ type QueryStateValue<TData> = Readonly<{
92
93
  /**
93
94
  * When this record was last updated. Used for LRU determination. If you want
94
95
  * the data age, please use `dataUpdatedMs` instead.
@@ -104,9 +105,14 @@ type QueryStateValue<TData> = {
104
105
  */
105
106
  error?: unknown;
106
107
  errorUpdatedMs?: number;
107
- };
108
+ }>;
108
109
  /** Return type for useSharedQuery(). */
109
- type UseQueryResult<TData> = QueryStateValue<TData> & {
110
+ type UseQueryResult<TData> = QueryStateValue<TData> & Readonly<{
111
+ /**
112
+ * Return the last non-empty data if you want to display the last loaded data
113
+ * while waiting for the new data to load.
114
+ */
115
+ lastNonEmptyData: TData | undefined;
110
116
  /**
111
117
  * Cancels the inflight query (if any). Returns true if canceled.
112
118
  */
@@ -121,7 +127,7 @@ type UseQueryResult<TData> = QueryStateValue<TData> & {
121
127
  */
122
128
  setData: (data: TData, dataUpdatedMs?: number) => void;
123
129
  deleteData: () => void;
124
- };
130
+ }>;
125
131
  /** List of all available persistence options. */
126
132
  type PersistTo = "localStorage" | "indexedDb";
127
133
  /**
@@ -131,24 +137,71 @@ type PersistTo = "localStorage" | "indexedDb";
131
137
  type SharedQueryState<TData> = Record<string, QueryStateValue<TData>>;
132
138
  /** Options to configure a shared query. */
133
139
  type SharedQueryOptions<TArgs extends unknown[], TData> = {
140
+ /**
141
+ * The name could have been auto-generated, but we let the user give us a
142
+ * human-readable name that can be identified quickly in the logs.
143
+ * Note that the queryKey is a string formed by the queryName plus the query
144
+ * arguments.
145
+ */
134
146
  queryName: string;
147
+ /**
148
+ * Function to fetch data.
149
+ */
135
150
  queryFn: QueryFn<TArgs, TData>;
151
+ /**
152
+ * ms before data considered stale; 0 means always stale.
153
+ */
136
154
  staleMs?: number;
155
+ /**
156
+ * ms before data is removed from cache; 0 means never expire.
157
+ */
137
158
  expiryMs?: number;
159
+ /**
160
+ * Trigger background re-fetch if stale.
161
+ */
138
162
  refetchOnStale?: boolean;
163
+ /**
164
+ * Shortcut to set the localStorageKey or indexedDbKey automatically from
165
+ * queryName. This is important because it avoids requiring the user to
166
+ * specify the same queryName twice everytime.
167
+ */
139
168
  persistTo?: PersistTo;
169
+ /**
170
+ * Max number of entries to keep. The oldest entries will be discarded.
171
+ * The last record cannot be discarded. 0 means no limit.
172
+ */
140
173
  maxSize?: number;
174
+ /**
175
+ * Max number of bytes to keep. The oldest entries will be discarded.
176
+ * The last record cannot be discarded. 0 means no limit.
177
+ */
141
178
  maxBytes?: number;
179
+ /**
180
+ * Keep a copy of the last non-empty data so that when you change the
181
+ * query arguments, you can still display the old data while waiting for the
182
+ * new data to load.
183
+ */
184
+ keepLastNonEmptyData?: boolean;
185
+ /**
186
+ * Customize the logger.
187
+ */
142
188
  log?: (...args: unknown[]) => void;
143
189
  } & SharedStateOptions<SharedQueryState<TData>>;
144
190
  /** Users can override these values globally. */
145
191
  declare const SharedQueryDefaults: {
192
+ /** Refetch on every page load. */
146
193
  staleMs: number;
194
+ /** Keep in cache for a long time. */
147
195
  expiryMs: number;
196
+ /** Always refetch automatically if the data is stale. */
148
197
  refetchOnStale: boolean;
198
+ /** No default persistence configured. */
149
199
  persistTo: PersistTo | undefined;
200
+ /** 100 is not too large, but please tweak accordingly. */
150
201
  maxSize: number;
202
+ /** 100kb limit before discarding old records. */
151
203
  maxBytes: number;
204
+ /** Default to log to console. */
152
205
  log: (...args: unknown[]) => void;
153
206
  };
154
207
  /** Please use sharedQuery() instead. */
@@ -168,6 +221,7 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
168
221
  readonly refetchOnStale: boolean;
169
222
  readonly maxSize: number;
170
223
  readonly maxBytes: number;
224
+ readonly keepLastNonEmptyData: boolean;
171
225
  readonly log: (...args: unknown[]) => void;
172
226
  constructor(options: SharedQueryOptions<TArgs, TData>);
173
227
  /** Returns a key to identify requests based on the given args. */
package/sharedQuery.d.ts CHANGED
@@ -85,7 +85,7 @@ import { SharedState, SharedStateOptions } from "./sharedState";
85
85
  /** Type of the queryFn used to fetch the data from source. */
86
86
  export type QueryFn<TArgs extends unknown[], TData> = (...args: TArgs) => Promise<TData> | TData;
87
87
  /** An entry for a persisted state corresponding to one query key. */
88
- export type QueryStateValue<TData> = {
88
+ export type QueryStateValue<TData> = Readonly<{
89
89
  /**
90
90
  * When this record was last updated. Used for LRU determination. If you want
91
91
  * the data age, please use `dataUpdatedMs` instead.
@@ -101,9 +101,14 @@ export type QueryStateValue<TData> = {
101
101
  */
102
102
  error?: unknown;
103
103
  errorUpdatedMs?: number;
104
- };
104
+ }>;
105
105
  /** Return type for useSharedQuery(). */
106
- export type UseQueryResult<TData> = QueryStateValue<TData> & {
106
+ export type UseQueryResult<TData> = QueryStateValue<TData> & Readonly<{
107
+ /**
108
+ * Return the last non-empty data if you want to display the last loaded data
109
+ * while waiting for the new data to load.
110
+ */
111
+ lastNonEmptyData: TData | undefined;
107
112
  /**
108
113
  * Cancels the inflight query (if any). Returns true if canceled.
109
114
  */
@@ -118,7 +123,7 @@ export type UseQueryResult<TData> = QueryStateValue<TData> & {
118
123
  */
119
124
  setData: (data: TData, dataUpdatedMs?: number) => void;
120
125
  deleteData: () => void;
121
- };
126
+ }>;
122
127
  /** List of all available persistence options. */
123
128
  export type PersistTo = "localStorage" | "indexedDb";
124
129
  /**
@@ -128,24 +133,71 @@ export type PersistTo = "localStorage" | "indexedDb";
128
133
  export type SharedQueryState<TData> = Record<string, QueryStateValue<TData>>;
129
134
  /** Options to configure a shared query. */
130
135
  export type SharedQueryOptions<TArgs extends unknown[], TData> = {
136
+ /**
137
+ * The name could have been auto-generated, but we let the user give us a
138
+ * human-readable name that can be identified quickly in the logs.
139
+ * Note that the queryKey is a string formed by the queryName plus the query
140
+ * arguments.
141
+ */
131
142
  queryName: string;
143
+ /**
144
+ * Function to fetch data.
145
+ */
132
146
  queryFn: QueryFn<TArgs, TData>;
147
+ /**
148
+ * ms before data considered stale; 0 means always stale.
149
+ */
133
150
  staleMs?: number;
151
+ /**
152
+ * ms before data is removed from cache; 0 means never expire.
153
+ */
134
154
  expiryMs?: number;
155
+ /**
156
+ * Trigger background re-fetch if stale.
157
+ */
135
158
  refetchOnStale?: boolean;
159
+ /**
160
+ * Shortcut to set the localStorageKey or indexedDbKey automatically from
161
+ * queryName. This is important because it avoids requiring the user to
162
+ * specify the same queryName twice everytime.
163
+ */
136
164
  persistTo?: PersistTo;
165
+ /**
166
+ * Max number of entries to keep. The oldest entries will be discarded.
167
+ * The last record cannot be discarded. 0 means no limit.
168
+ */
137
169
  maxSize?: number;
170
+ /**
171
+ * Max number of bytes to keep. The oldest entries will be discarded.
172
+ * The last record cannot be discarded. 0 means no limit.
173
+ */
138
174
  maxBytes?: number;
175
+ /**
176
+ * Keep a copy of the last non-empty data so that when you change the
177
+ * query arguments, you can still display the old data while waiting for the
178
+ * new data to load.
179
+ */
180
+ keepLastNonEmptyData?: boolean;
181
+ /**
182
+ * Customize the logger.
183
+ */
139
184
  log?: (...args: unknown[]) => void;
140
185
  } & SharedStateOptions<SharedQueryState<TData>>;
141
186
  /** Users can override these values globally. */
142
187
  export declare const SharedQueryDefaults: {
188
+ /** Refetch on every page load. */
143
189
  staleMs: number;
190
+ /** Keep in cache for a long time. */
144
191
  expiryMs: number;
192
+ /** Always refetch automatically if the data is stale. */
145
193
  refetchOnStale: boolean;
194
+ /** No default persistence configured. */
146
195
  persistTo: PersistTo | undefined;
196
+ /** 100 is not too large, but please tweak accordingly. */
147
197
  maxSize: number;
198
+ /** 100kb limit before discarding old records. */
148
199
  maxBytes: number;
200
+ /** Default to log to console. */
149
201
  log: (...args: unknown[]) => void;
150
202
  };
151
203
  /** Please use sharedQuery() instead. */
@@ -165,6 +217,7 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
165
217
  readonly refetchOnStale: boolean;
166
218
  readonly maxSize: number;
167
219
  readonly maxBytes: number;
220
+ readonly keepLastNonEmptyData: boolean;
168
221
  readonly log: (...args: unknown[]) => void;
169
222
  constructor(options: SharedQueryOptions<TArgs, TData>);
170
223
  /** Returns a key to identify requests based on the given args. */
@@ -1,2 +1,2 @@
1
- "use strict";var q=Object.create;var m=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var J=(i,e)=>{for(var t in e)m(i,t,{get:e[t],enumerable:!0})},K=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of R(e))!j.call(i,s)&&s!==t&&m(i,s,{get:()=>e[s],enumerable:!(r=L(e,s))||r.enumerable});return i};var Q=(i,e,t)=>(t=i!=null?q(_(i)):{},K(e||!i||!i.__esModule?m(t,"default",{value:i,enumerable:!0}):t,i)),W=i=>K(m({},"__esModule",{value:!0}),i);var X={};J(X,{SharedQuery:()=>x,SharedQueryDefaults:()=>h,sharedQuery:()=>I,useSharedQuery:()=>H});module.exports=W(X);var U=require("@choksheak/ts-utils/timeConstants"),S=Q(require("object-sizeof")),p=require("react");var O=require("@choksheak/ts-utils/timeConstants"),z=require("react");var f=require("@choksheak/ts-utils/kvStore");function k(i,e){let{localStorageKey:t,indexedDbKey:r,storeExpiryMs:s,store:a}=i??{};if(a)return a;let n=s||e;return t?new w(t,n):r?new D(r,n):null}var w=class{constructor(e,t){this.keyPrefix=e;this.expiryMs=t}save(e,t){if(typeof window>"u")return;let r=this.keyPrefix+":"+e;window.localStorage.setItem(r,JSON.stringify({value:t,expiresAt:this.expiryMs?Date.now()+this.expiryMs:0}))}load(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e,r=window.localStorage.getItem(t);if(r)try{let s=JSON.parse(r);if(!s||s.expiresAt&&Date.now()>=s.expiresAt){window.localStorage.removeItem(t);return}return s.value}catch{window.localStorage.removeItem(t);return}}delete(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e;window.localStorage.removeItem(t)}clear(){if(!(typeof window>"u"))for(let e of Object.keys(window.localStorage))e.startsWith(this.keyPrefix)&&window.localStorage.removeItem(e)}},D=class{constructor(e,t){this.keyPrefix=e;this.expiryMs=t}async save(e,t){if(typeof window>"u")return;let r=this.keyPrefix+":"+e;await f.kvStore.set(r,JSON.stringify(t),this.expiryMs)}async load(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e,r=await f.kvStore.get(t);if(r!==void 0)try{return JSON.parse(r)}catch{await f.kvStore.delete(t);return}}async delete(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e;await f.kvStore.delete(t)}async clear(){typeof window>"u"||await f.kvStore.forEach(async e=>{e.startsWith(this.keyPrefix)&&await f.kvStore.delete(e)})}};var B={storeExpiryMs:30*O.MS_PER_DAY,lazyLoad:!1},A=class{dataByKey=new Map;subscribersByKey=new Map;get(e){return this.dataByKey.get(e)}set(e,t){let r=this.dataByKey.get(e);r!==t&&(this.dataByKey.set(e,t),this.notify(e,t,r))}delete(e){this.dataByKey.delete(e)}setNoNotify(e,t){this.dataByKey.set(e,t)}subscribe(e,t){let r=this.subscribersByKey.get(e);return r||(r=new Set,this.subscribersByKey.set(e,r)),r.add(t),()=>{r.delete(t),r.size===0&&this.subscribersByKey.delete(e)}}notify(e,t,r){let s=this.subscribersByKey.get(e);if(!s)return;let a=Array.from(s.values());for(let n of a)try{n(t,r)}catch(y){console.error("Error invoking subscriber:",y)}}},g=new A,v="state",Y=0,M=class{constructor(e,t){this.defaultValue=e;this.pubSubKey=String(Y++),this.storageAdapter=k(t,B.storeExpiryMs),this.setValueBounded=a=>this.setValue(a),g.setNoNotify(this.pubSubKey,e);let r=t?.lazyLoad;(r!==void 0?r:B.lazyLoad)||this.initDefaultValueOnce()}pubSubKey;storageAdapter;setValueBounded;initDone=!1;subscribe(e){return g.subscribe(this.pubSubKey,()=>e())}getSnapshot(){return g.get(this.pubSubKey)}setValue(e){if(typeof e=="function"){let t=g.get(this.pubSubKey);e=e(t)}g.set(this.pubSubKey,e),this.storageAdapter?.save(v,e)}delete(){g.set(this.pubSubKey,this.defaultValue),this.storageAdapter?.save(v,this.defaultValue)}async initDefaultValueOnce(){if(this.initDone)return;this.initDone=!0;let e=await this.storageAdapter?.load(v);g.set(this.pubSubKey,e!==void 0?e:this.defaultValue)}};function V(i,e){return new M(i,e)}function $(i){return i.initDefaultValueOnce(),[(0,z.useSyncExternalStore)(t=>i.subscribe(t),()=>i.getSnapshot(),()=>i.getSnapshot()),i.setValueBounded]}function P(i){let e=new Set;return JSON.stringify(i,(t,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(e.has(r))return"[Circular]";if(e.add(r),r!==i)try{JSON.stringify(r)}catch{return"[Unserializable]"}return Object.keys(r).sort().reduce((s,a)=>(s[a]=r[a],s),{})})}var C=Q(require("lodash/isEqual")),T=require("react");function E(i){let[e,t]=(0,T.useState)(i);return(0,T.useMemo)(()=>e===i||(0,C.default)(e,i)?e:(t(i),i),[e,i])}var h={staleMs:0,expiryMs:30*U.MS_PER_DAY,refetchOnStale:!0,persistTo:void 0,maxSize:100,maxBytes:1e5,log:(...i)=>console.log("[sharedQuery]",...i)},x=class{inflightQueries=new Map;queryState;mountedKeys=new Map;queryName;queryFn;expiryMs;staleMs;refetchOnStale;maxSize;maxBytes;log;constructor(e){if(this.queryName=e.queryName,this.queryFn=e.queryFn,this.staleMs=e?.staleMs??h.staleMs,this.expiryMs=e?.expiryMs??h.expiryMs,this.refetchOnStale=e?.refetchOnStale??h.refetchOnStale,!e.localStorageKey&&!e.indexedDbKey){let t=e.persistTo??h.persistTo;t==="localStorage"?e.localStorageKey=e.queryName:t==="indexedDb"&&(e.indexedDbKey=e.queryName)}this.maxSize=e?.maxSize??h.maxSize,this.maxBytes=e?.maxBytes??h.maxBytes,this.log=e?.log??h.log,this.queryState=V({},{...e,storeExpiryMs:e?.storeExpiryMs||this.expiryMs})}getQueryKey(e){return this.queryName+":"+P(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=this.getQueryKey(e),r=this.queryState.getSnapshot()?.[t];return r?.data&&!this.isExpired(r.dataUpdatedMs??0)?this.isStale(r.dataUpdatedMs??0)?(this.refetchOnStale&&(this.log(`refetchOnStale for ${t}`),this.dedupedFetch(t,...e)),this.log(`Returning stale data for ${t}`),r.data):(this.log(`Return fresh data ${t} from cache without fetching`),r.data):await this.dedupedFetch(t,...e)}dedupedFetch(e,...t){let r=this.inflightQueries.get(e);if(r)return this.log(`Deduplicating inflight fetch for ${e}`),r.promise;let s=this.startFetching(e,t),a=new AbortController;return this.inflightQueries.set(e,{promise:s,abortController:a}),s}async startFetching(e,t){this.log(`Start fetching ${e}`);try{let r=await this.queryFn(...t);return this.log(`Successfully fetched ${e}`),this.setData(e,r,Date.now()),r}catch(r){throw this.log(`Failed to fetch ${e}: ${r}`),r}finally{this.inflightQueries.delete(e)}}getQueryValue(e){return this.queryState.getSnapshot()?.[e]}getData(e){return this.queryState.getSnapshot()?.[e]?.data}setData(e,t,r=Date.now()){let s={lastUpdatedMs:Date.now(),loading:!1,data:t,dataUpdatedMs:r};this.queryState.setValue(a=>({...a,[e]:s})),this.enforceSizeLimit()}async updateFromSource(...e){let t=this.getQueryKey(e);return await this.dedupedFetch(t,...e)}deleteData(e){let r={...this.queryState.getSnapshot()};delete r[e],this.queryState.setValue(r);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 r=(0,S.default)(e),s=e,a=!1;if(this.maxSize){let n=t-this.maxSize;if(n>0){this.log(`enforceSizeLimit for ${this.queryName} needed due to size ${t} > ${this.maxSize}`),s={...s},a=!0;let y=Object.entries(s).sort((l,o)=>l[1].lastUpdatedMs-o[1].lastUpdatedMs);for(let l=0;l<y.length&&n>0;l++){let o=y[l][0];this.mountedKeys.has(o)?this.log(`Cannot clean up ${o} as it is mounted`):(this.log(`Cleaning up unmounted ${o}`),delete s[o],n--)}}}if(this.maxBytes&&Object.keys(s).length>1){let n=a?(0,S.default)(s):r,y=n-this.maxBytes;if(y>0){this.log(`enforceSizeLimit for ${this.queryName} needed due to byte size ${n.toLocaleString()} > ${this.maxBytes.toLocaleString()}`),a||(s={...s},a=!0);let l=Object.entries(s).sort((o,d)=>o[1].lastUpdatedMs-d[1].lastUpdatedMs);for(let o=0;o<l.length&&y>0;o++){let d=l[o][0];if(this.mountedKeys.has(d))this.log(`Cannot clean up ${d} as it is mounted`);else{this.log(`Cleaning up unmounted ${d}`);let c=(0,S.default)(d)+(0,S.default)(s[d]);delete s[d],y-=c}}}}if(a){this.queryState.setValue(s),this.log(`Trimmed data for ${this.queryName}: size=(${t} -> ${Object.keys(s).length}) (limit=${this.maxSize}), byteSize=(${r.toLocaleString()} -> ${(0,S.default)(s).toLocaleString()}) (limit=${this.maxBytes.toLocaleString()})`);return}this.log(`No need to trim data for ${this.queryName}: size=${t} (limit=${this.maxSize}), byteSize=${r.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`)}},N=new Set;function I(i){if(N.has(i.queryName))throw new Error(`Duplicate shared query "${i.queryName}"`);return N.add(i.queryName),new x(i)}var G={lastUpdatedMs:0,loading:!0};function H(i,e=[]){let t=E(e),[r,s]=$(i.queryState),a=(0,p.useRef)(!0),n=(0,p.useMemo)(()=>i.getQueryKey(t),[i,t]),y=r[n],l=(0,p.useCallback)(d=>{s(c=>{let u={...c};return u[n]=typeof d=="function"?d(u[n]):d,u})},[n,s]),o=(0,p.useCallback)(async d=>{i.log(`Begin executing shared query ${n}`),l(c=>({...c??{},lastUpdatedMs:Date.now(),loading:!0}));try{let c=await(d?i.updateFromSource(...t):i.getCachedOrFetch(...t));if(a.current){let u=Date.now();l({lastUpdatedMs:u,loading:!1,data:c,dataUpdatedMs:u})}}catch(c){if(a.current){let u=Date.now();l(b=>({...b??{},lastUpdatedMs:u,loading:!1,error:c,errorUpdatedMs:u}))}}},[i,n,l,t]);return(0,p.useEffect)(()=>(a.current=!0,i.mount(n),o(!1),()=>{a.current=!1,i.unmount(n)}),[o,i,n]),(0,p.useMemo)(()=>({...y??G,abortCurrentQuery:c=>{let u=i.getAbortControllerByKey(n);return u?.abort(c),!!u},refetch:()=>{o(!0)},setData:(c,u)=>{let b=Date.now();l(F=>({...F??{},data:c,dataUpdatedMs:u??b,lastUpdatedMs:b,loading:!1}))},deleteData:()=>{s(c=>{let u={...c};return delete u[n],u})}}),[o,i,n,y,s,l])}0&&(module.exports={SharedQuery,SharedQueryDefaults,sharedQuery,useSharedQuery});
1
+ "use strict";var q=Object.create;var T=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,W=Object.prototype.hasOwnProperty;var Y=(i,e)=>{for(var t in e)T(i,t,{get:e[t],enumerable:!0})},k=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of j(e))!W.call(i,a)&&a!==t&&T(i,a,{get:()=>e[a],enumerable:!(r=_(e,a))||r.enumerable});return i};var B=(i,e,t)=>(t=i!=null?q(J(i)):{},k(e||!i||!i.__esModule?T(t,"default",{value:i,enumerable:!0}):t,i)),I=i=>k(T({},"__esModule",{value:!0}),i);var Z={};Y(Z,{SharedQuery:()=>w,SharedQueryDefaults:()=>h,sharedQuery:()=>H,useSharedQuery:()=>X});module.exports=I(Z);var R=require("@choksheak/ts-utils/timeConstants"),b=B(require("object-sizeof")),u=require("react");var E=require("@choksheak/ts-utils/timeConstants"),z=require("react");var f=require("@choksheak/ts-utils/kvStore");function N(i,e){let{localStorageKey:t,indexedDbKey:r,storeExpiryMs:a,store:n}=i??{};if(n)return n;let s=a||e;return t?new A(t,s):r?new M(r,s):null}var A=class{constructor(e,t){this.keyPrefix=e;this.expiryMs=t}save(e,t){if(typeof window>"u")return;let r=this.keyPrefix+":"+e;window.localStorage.setItem(r,JSON.stringify({value:t,expiresAt:this.expiryMs?Date.now()+this.expiryMs:0}))}load(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e,r=window.localStorage.getItem(t);if(r)try{let a=JSON.parse(r);if(!a||a.expiresAt&&Date.now()>=a.expiresAt){window.localStorage.removeItem(t);return}return a.value}catch{window.localStorage.removeItem(t);return}}delete(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e;window.localStorage.removeItem(t)}clear(){if(!(typeof window>"u"))for(let e of Object.keys(window.localStorage))e.startsWith(this.keyPrefix)&&window.localStorage.removeItem(e)}},M=class{constructor(e,t){this.keyPrefix=e;this.expiryMs=t}async save(e,t){if(typeof window>"u")return;let r=this.keyPrefix+":"+e;await f.kvStore.set(r,JSON.stringify(t),this.expiryMs)}async load(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e,r=await f.kvStore.get(t);if(r!==void 0)try{return JSON.parse(r)}catch{await f.kvStore.delete(t);return}}async delete(e){if(typeof window>"u")return;let t=this.keyPrefix+":"+e;await f.kvStore.delete(t)}async clear(){typeof window>"u"||await f.kvStore.forEach(async e=>{e.startsWith(this.keyPrefix)&&await f.kvStore.delete(e)})}};var O={storeExpiryMs:30*E.MS_PER_DAY,lazyLoad:!1},K=class{dataByKey=new Map;subscribersByKey=new Map;get(e){return this.dataByKey.get(e)}set(e,t){let r=this.dataByKey.get(e);r!==t&&(this.dataByKey.set(e,t),this.notify(e,t,r))}delete(e){this.dataByKey.delete(e)}setNoNotify(e,t){this.dataByKey.set(e,t)}subscribe(e,t){let r=this.subscribersByKey.get(e);return r||(r=new Set,this.subscribersByKey.set(e,r)),r.add(t),()=>{r.delete(t),r.size===0&&this.subscribersByKey.delete(e)}}notify(e,t,r){let a=this.subscribersByKey.get(e);if(!a)return;let n=Array.from(a.values());for(let s of n)try{s(t,r)}catch(y){console.error("Error invoking subscriber:",y)}}},g=new K,v="state",G=0,Q=class{constructor(e,t){this.defaultValue=e;this.pubSubKey=String(G++),this.storageAdapter=N(t,O.storeExpiryMs),this.setValueBounded=n=>{this.setValue(n)},g.setNoNotify(this.pubSubKey,e);let r=t?.lazyLoad;(r!==void 0?r:O.lazyLoad)||this.initDefaultValueOnce()}pubSubKey;storageAdapter;setValueBounded;initDone=!1;subscribe(e){return g.subscribe(this.pubSubKey,()=>e())}getSnapshot(){return g.get(this.pubSubKey)}setValue(e){if(typeof e=="function"){let t=g.get(this.pubSubKey);e=e(t)}g.set(this.pubSubKey,e),this.storageAdapter?.save(v,e)}delete(){g.set(this.pubSubKey,this.defaultValue),this.storageAdapter?.save(v,this.defaultValue)}async initDefaultValueOnce(){if(this.initDone)return;this.initDone=!0;let e=await this.storageAdapter?.load(v);g.set(this.pubSubKey,e!==void 0?e:this.defaultValue)}};function $(i,e){return new Q(i,e)}function P(i){return i.initDefaultValueOnce(),[(0,z.useSyncExternalStore)(t=>i.subscribe(t),()=>i.getSnapshot(),()=>i.getSnapshot()),i.setValueBounded]}function V(i){let e=new Set;return JSON.stringify(i,(t,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(e.has(r))return"[Circular]";if(e.add(r),r!==i)try{JSON.stringify(r)}catch{return"[Unserializable]"}return Object.keys(r).sort().reduce((a,n)=>(a[n]=r[n],a),{})})}var C=B(require("lodash/isEqual")),x=require("react");function U(i){let[e,t]=(0,x.useState)(i);return(0,x.useMemo)(()=>e===i||(0,C.default)(e,i)?e:(t(i),i),[e,i])}var h={staleMs:0,expiryMs:30*R.MS_PER_DAY,refetchOnStale:!0,persistTo:void 0,maxSize:100,maxBytes:1e5,log:(...i)=>console.log("[sharedQuery]",...i)},w=class{inflightQueries=new Map;queryState;mountedKeys=new Map;queryName;queryFn;expiryMs;staleMs;refetchOnStale;maxSize;maxBytes;keepLastNonEmptyData;log;constructor(e){if(this.queryName=e.queryName,this.queryFn=e.queryFn,this.staleMs=e?.staleMs??h.staleMs,this.expiryMs=e?.expiryMs??h.expiryMs,this.refetchOnStale=e?.refetchOnStale??h.refetchOnStale,!e.localStorageKey&&!e.indexedDbKey){let t=e.persistTo??h.persistTo;t==="localStorage"?e.localStorageKey=e.queryName:t==="indexedDb"&&(e.indexedDbKey=e.queryName)}this.maxSize=e?.maxSize??h.maxSize,this.maxBytes=e?.maxBytes??h.maxBytes,this.keepLastNonEmptyData=!!e?.keepLastNonEmptyData,this.log=e?.log??h.log,this.queryState=$({},{...e,storeExpiryMs:e?.storeExpiryMs||this.expiryMs})}getQueryKey(e){return this.queryName+":"+V(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=this.getQueryKey(e),r=this.queryState.getSnapshot()?.[t];return r?.data&&!this.isExpired(r.dataUpdatedMs??0)?this.isStale(r.dataUpdatedMs??0)?(this.refetchOnStale&&(this.log(`refetchOnStale for ${t}`),this.dedupedFetch(t,...e)),this.log(`Returning stale data for ${t}`),r.data):(this.log(`Return fresh data ${t} from cache without fetching`),r.data):await this.dedupedFetch(t,...e)}dedupedFetch(e,...t){let r=this.inflightQueries.get(e);if(r)return this.log(`Deduplicating inflight fetch for ${e}`),r.promise;let a=this.startFetching(e,t),n=new AbortController;return this.inflightQueries.set(e,{promise:a,abortController:n}),a}async startFetching(e,t){this.log(`Start fetching ${e}`);try{let r=await this.queryFn(...t);return this.log(`Successfully fetched ${e}`),this.setData(e,r,Date.now()),r}catch(r){throw this.log(`Failed to fetch ${e}: ${r}`),r}finally{this.inflightQueries.delete(e)}}getQueryValue(e){return this.queryState.getSnapshot()?.[e]}getData(e){return this.queryState.getSnapshot()?.[e]?.data}setData(e,t,r=Date.now()){let a={lastUpdatedMs:Date.now(),loading:!1,data:t,dataUpdatedMs:r};this.queryState.setValue(n=>({...n,[e]:a})),this.enforceSizeLimit()}async updateFromSource(...e){let t=this.getQueryKey(e);return await this.dedupedFetch(t,...e)}deleteData(e){let r={...this.queryState.getSnapshot()};delete r[e],this.queryState.setValue(r);let a=this.inflightQueries.get(e);a&&(this.inflightQueries.delete(e),a.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 r=(0,b.default)(e),a=this.maxSize?t-this.maxSize:0,n=this.maxBytes?r-this.maxBytes:0;if(a<=0&&n<=0){this.log(`No need to trim data for ${this.queryName}: size=${t} (limit=${this.maxSize}), byteSize=${r.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`);return}this.log(`Need to trim ${this.queryName}: numToCut=${a}, bytesToCut=${n}`);let s={...e},y=!1,p=Object.entries(s).sort((d,S)=>d[1].lastUpdatedMs-S[1].lastUpdatedMs);for(let[d]of p){if(this.mountedKeys.has(d)){this.log(`Cannot clean up ${d} as it is mounted`);continue}let S=(0,b.default)(d)+(0,b.default)(s[d]);if(this.log(`Cleaning up unmounted ${d} (byteSize=${S.toLocaleString()})`),a--,n-=S,delete s[d],y=!0,a<=0&&n<=0)break}if(!y){this.log(`No trimmable entries found for ${this.queryName}: size=${t} (limit=${this.maxSize}), byteSize=${r.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`);return}this.queryState.setValue(s),this.log(`Trimmed data for ${this.queryName}: size=[${t} -> ${Object.keys(s).length}] (limit=${this.maxSize}), byteSize=[${r.toLocaleString()} -> ${(0,b.default)(s).toLocaleString()}] (limit=${this.maxBytes.toLocaleString()})`)}},F=new Set;function H(i){if(F.has(i.queryName))throw new Error(`Duplicate shared query "${i.queryName}"`);return F.add(i.queryName),new w(i)}var L={lastUpdatedMs:0,loading:!0};function X(i,e=[]){let t=U(e),[r,a]=P(i.queryState),n=(0,u.useRef)(!0),s=(0,u.useMemo)(()=>i.getQueryKey(t),[i,t]),y=r[s]??L,p=(0,u.useCallback)(c=>{a(o=>{let l={...o};return l[s]=typeof c=="function"?c(l[s]??L):c,l})},[s,a]),[d,S]=(0,u.useState)();(0,u.useEffect)(()=>{i.keepLastNonEmptyData&&y.data!==void 0&&S(y.data)},[i.keepLastNonEmptyData,y.data]);let m=(0,u.useCallback)(async c=>{i.log(`Begin executing shared query ${s}`),p(o=>({...o,lastUpdatedMs:Date.now(),loading:!0}));try{let o=await(c?i.updateFromSource(...t):i.getCachedOrFetch(...t));if(n.current){let l=Date.now();p({lastUpdatedMs:l,loading:!1,data:o,dataUpdatedMs:l})}}catch(o){if(n.current){let l=Date.now();p(D=>({...D,lastUpdatedMs:l,loading:!1,error:o,errorUpdatedMs:l}))}}},[i,s,p,t]);return(0,u.useEffect)(()=>(n.current=!0,i.mount(s),m(!1),()=>{n.current=!1,i.unmount(s)}),[m,i,s]),(0,u.useMemo)(()=>({...y,lastNonEmptyData:d,abortCurrentQuery:c=>{let o=i.getAbortControllerByKey(s);return o?.abort(c),!!o},refetch:()=>{m(!0)},setData:(c,o)=>{let l=Date.now();p(D=>({...D,data:c,dataUpdatedMs:o??l,lastUpdatedMs:l,loading:!1}))},deleteData:()=>{a(c=>{let o={...c};return delete o[s],o})}}),[m,d,i,s,y,a,p])}0&&(module.exports={SharedQuery,SharedQueryDefaults,sharedQuery,useSharedQuery});
2
2
  //# sourceMappingURL=sharedQuery.min.cjs.map