@choksheak/react-utils 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
- var _chunkKXFV42DPcjs = require('./chunk-KXFV42DP.cjs');
4
+ var _chunkYMQDZV47cjs = require('./chunk-YMQDZV47.cjs');
5
5
 
6
6
 
7
7
  var _chunkCYTO5EZEcjs = require('./chunk-CYTO5EZE.cjs');
@@ -11,14 +11,7 @@ var _chunkWXLUEDBOcjs = require('./chunk-WXLUEDBO.cjs');
11
11
 
12
12
  // src/sharedQuery.ts
13
13
  var _http = require('@choksheak/ts-utils/http');
14
- var _nonNil = require('@choksheak/ts-utils/nonNil');
15
14
  var _objectsizeof = require('object-sizeof'); var _objectsizeof2 = _interopRequireDefault(_objectsizeof);
16
-
17
-
18
-
19
-
20
-
21
-
22
15
  var _react = require('react');
23
16
  var _xxhashjs = require('xxhashjs'); var _xxhashjs2 = _interopRequireDefault(_xxhashjs);
24
17
  var hasWindow = typeof window !== "undefined";
@@ -27,8 +20,6 @@ var SharedQueryConfig = {
27
20
  staleMs: 0,
28
21
  /** Keep in cache for a long time. */
29
22
  expiryMs: 30 * 864e5,
30
- /** Always refetch automatically if the data is stale. */
31
- refetchOnStale: true,
32
23
  /** No default persistence configured. */
33
24
  persistTo: void 0,
34
25
  /** 100 is not too large, but please tweak accordingly. */
@@ -114,7 +105,6 @@ function sharedQuery2(options) {
114
105
  const refetchFn = options.refetchFn;
115
106
  const staleMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.staleMs]), () => ( SharedQueryConfig.staleMs));
116
107
  const expiryMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.expiryMs]), () => ( SharedQueryConfig.expiryMs));
117
- const refetchOnStale = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.refetchOnStale]), () => ( SharedQueryConfig.refetchOnStale));
118
108
  const store = options.store;
119
109
  if (store) {
120
110
  if ("persistTo" in store && store.isValid) {
@@ -150,16 +140,37 @@ function sharedQuery2(options) {
150
140
  };
151
141
  }
152
142
  }
153
- const maxSize = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.maxSize]), () => ( SharedQueryConfig.maxSize));
154
- const maxBytes = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _6 => _6.maxBytes]), () => ( SharedQueryConfig.maxBytes));
155
- const keepLastNonEmptyData = Boolean(_optionalChain([options, 'optionalAccess', _7 => _7.keepLastNonEmptyData]));
156
- const log = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _8 => _8.log]), () => ( SharedQueryConfig.log));
143
+ const maxSize = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.maxSize]), () => ( SharedQueryConfig.maxSize));
144
+ const maxBytes = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.maxBytes]), () => ( SharedQueryConfig.maxBytes));
145
+ const keepLastNonEmptyData = Boolean(_optionalChain([options, 'optionalAccess', _6 => _6.keepLastNonEmptyData]));
146
+ const log = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _7 => _7.log]), () => ( SharedQueryConfig.log));
157
147
  options.name = queryName;
158
- const queryState = _chunkKXFV42DPcjs.sharedState.call(void 0,
148
+ const queryState = _chunkYMQDZV47cjs.sharedState.call(void 0,
159
149
  {},
160
150
  // defaultValue
161
151
  options
162
152
  );
153
+ function getQueryKey(args) {
154
+ let s = _chunkCYTO5EZEcjs.stringifyDeterministicForKeys.call(void 0, args);
155
+ if (s.length > 30) {
156
+ s = _xxhashjs2.default.h32(s, 39406).toString(16).slice(2);
157
+ }
158
+ return queryName + ":" + s;
159
+ }
160
+ function getAbortControllerByKey(queryKey) {
161
+ return _nullishCoalesce(_optionalChain([inflightQueries, 'access', _8 => _8.get, 'call', _9 => _9(queryKey), 'optionalAccess', _10 => _10.abortController]), () => ( null));
162
+ }
163
+ function getAbortController(args) {
164
+ const queryKey = getQueryKey(args);
165
+ return getAbortControllerByKey(queryKey);
166
+ }
167
+ function getAbortSignal(args) {
168
+ const queryKey = getQueryKey(args);
169
+ return getAbortSignalByKey(queryKey);
170
+ }
171
+ function getAbortSignalByKey(queryKey) {
172
+ return _nullishCoalesce(_optionalChain([getAbortControllerByKey, 'call', _11 => _11(queryKey), 'optionalAccess', _12 => _12.signal]), () => ( null));
173
+ }
163
174
  function isStale(dataUpdatedMs) {
164
175
  if (staleMs === 0) return true;
165
176
  const ageMs = Date.now() - dataUpdatedMs;
@@ -196,7 +207,7 @@ function sharedQuery2(options) {
196
207
  const deleteKeyIfNotMounted = (key, expired) => {
197
208
  if (mountedKeys.has(key)) {
198
209
  log(`Cannot clean up ${key} as it is mounted`);
199
- return;
210
+ return false;
200
211
  }
201
212
  const byteSize = _objectsizeof2.default.call(void 0, key) + _objectsizeof2.default.call(void 0, newState[key]);
202
213
  log(
@@ -206,23 +217,31 @@ function sharedQuery2(options) {
206
217
  bytesToCut -= byteSize;
207
218
  delete newState[key];
208
219
  needUpdate = true;
220
+ return true;
209
221
  };
210
- let entriesByTimeAscending = Object.entries(newState).sort(
211
- (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
222
+ const entriesByLastUpdatedMsAsc = Object.fromEntries(
223
+ Object.entries(newState).sort(
224
+ (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
225
+ )
212
226
  );
213
- for (const [key] of entriesByTimeAscending) {
214
- if (!isExpired(newState[key].lastUpdatedMs)) {
227
+ for (const key of Object.keys(entriesByLastUpdatedMsAsc)) {
228
+ const state = newState[key];
229
+ if (!_optionalChain([state, 'optionalAccess', _13 => _13.lastUpdatedMs]) || _optionalChain([state, 'optionalAccess', _14 => _14.loading])) {
230
+ continue;
231
+ }
232
+ if (_optionalChain([state, 'optionalAccess', _15 => _15.lastUpdatedMs]) && !isExpired(state.lastUpdatedMs)) {
215
233
  break;
216
234
  }
217
- deleteKeyIfNotMounted(key, true);
235
+ if (deleteKeyIfNotMounted(key, true)) {
236
+ delete entriesByLastUpdatedMsAsc[key];
237
+ }
218
238
  }
219
239
  if (numToCut > 0 || bytesToCut > 0) {
220
- if (needUpdate) {
221
- entriesByTimeAscending = Object.entries(newState).sort(
222
- (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
223
- );
224
- }
225
- for (const [key] of entriesByTimeAscending) {
240
+ for (const key of Object.keys(entriesByLastUpdatedMsAsc)) {
241
+ const state = newState[key];
242
+ if (!_optionalChain([state, 'optionalAccess', _16 => _16.lastUpdatedMs]) || _optionalChain([state, 'optionalAccess', _17 => _17.loading])) {
243
+ continue;
244
+ }
226
245
  deleteKeyIfNotMounted(key, false);
227
246
  if (numToCut <= 0 && bytesToCut <= 0) {
228
247
  break;
@@ -240,15 +259,120 @@ function sharedQuery2(options) {
240
259
  `Trimmed data for ${queryName}: size=[${oldSize} -> ${Object.keys(newState).length}] (limit=${maxSize}), byteSize=[${oldByteSize.toLocaleString()} -> ${_objectsizeof2.default.call(void 0, newState).toLocaleString()}] (limit=${maxBytes.toLocaleString()})`
241
260
  );
242
261
  }
262
+ function getQueryValue(queryKey) {
263
+ return _optionalChain([queryState, 'access', _18 => _18.getSnapshot, 'call', _19 => _19(), 'optionalAccess', _20 => _20[queryKey]]);
264
+ }
265
+ function setQueryValue(queryKey, next) {
266
+ queryState.setValue((prev) => {
267
+ const value = typeof next === "function" ? next(_nullishCoalesce(prev[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY))) : next;
268
+ return { ...prev, [queryKey]: value };
269
+ });
270
+ enforceSizeLimit();
271
+ }
272
+ function getData(queryKey) {
273
+ const stateValue = getQueryValue(queryKey);
274
+ if (_optionalChain([stateValue, 'optionalAccess', _21 => _21.dataUpdatedMs])) {
275
+ if (isExpired(stateValue.dataUpdatedMs)) {
276
+ deleteData(queryKey);
277
+ return void 0;
278
+ }
279
+ }
280
+ return _optionalChain([stateValue, 'optionalAccess', _22 => _22.data]);
281
+ }
243
282
  function setData(queryKey, data, dataUpdatedMs = Date.now()) {
244
- const entry = {
283
+ setQueryValue(queryKey, {
245
284
  lastUpdatedMs: Date.now(),
246
285
  loading: false,
247
286
  data,
248
287
  dataUpdatedMs
249
- };
250
- queryState.setValue((prev) => ({ ...prev, [queryKey]: entry }));
251
- enforceSizeLimit();
288
+ });
289
+ }
290
+ function deleteData(queryKey) {
291
+ const record = queryState.getSnapshot();
292
+ const clone = { ...record };
293
+ delete clone[queryKey];
294
+ queryState.setValue(clone);
295
+ const inflight = inflightQueries.get(queryKey);
296
+ if (inflight) {
297
+ inflightQueries.delete(queryKey);
298
+ inflight.abortController.abort("Deleted");
299
+ }
300
+ }
301
+ async function wrapLoading(queryKey, fetchData) {
302
+ setQueryValue(queryKey, DEFAULT_QUERY_STATE_ENTRY);
303
+ try {
304
+ const data = await fetchData();
305
+ if (_optionalChain([getQueryValue, 'call', _23 => _23(queryKey), 'optionalAccess', _24 => _24.loading])) {
306
+ const now = Date.now();
307
+ setQueryValue(queryKey, {
308
+ data,
309
+ loading: false,
310
+ lastUpdatedMs: now,
311
+ dataUpdatedMs: now
312
+ });
313
+ }
314
+ return data;
315
+ } catch (e) {
316
+ if (_optionalChain([getQueryValue, 'call', _25 => _25(queryKey), 'optionalAccess', _26 => _26.loading])) {
317
+ const now = Date.now();
318
+ setQueryValue(queryKey, {
319
+ loading: false,
320
+ lastUpdatedMs: now,
321
+ error: e,
322
+ errorUpdatedMs: now
323
+ });
324
+ }
325
+ throw e;
326
+ }
327
+ }
328
+ async function waitForStateInit(queryKey) {
329
+ const startMs = Date.now();
330
+ await queryState.readyPromise;
331
+ const waitedMs = Date.now() - startMs;
332
+ if (waitedMs) {
333
+ log(`${queryKey}: Waited for ${waitedMs}ms before data is ready`);
334
+ }
335
+ }
336
+ async function getCachedOrFetch(queryKey, ...args) {
337
+ await waitForStateInit(queryKey);
338
+ const cached = getQueryValue(queryKey);
339
+ if (_optionalChain([cached, 'optionalAccess', _27 => _27.data]) !== void 0 && cached.dataUpdatedMs && !isExpired(cached.dataUpdatedMs)) {
340
+ if (!isStale(cached.dataUpdatedMs)) {
341
+ log(`Return fresh data ${queryKey} from cache without fetching`);
342
+ return cached.data;
343
+ }
344
+ void dedupedFetch(queryKey, "query", ...args);
345
+ log(`Returning stale data for ${queryKey}`);
346
+ return cached.data;
347
+ }
348
+ return await dedupedFetch(queryKey, "query", ...args);
349
+ }
350
+ async function getCachedStateOrFetch(queryKey, ...args) {
351
+ await waitForStateInit(queryKey);
352
+ const cached = getQueryValue(queryKey);
353
+ if (_optionalChain([cached, 'optionalAccess', _28 => _28.data]) !== void 0 && cached.dataUpdatedMs && !isExpired(cached.dataUpdatedMs)) {
354
+ if (!isStale(cached.dataUpdatedMs)) {
355
+ log(`Return fresh data ${queryKey} from cache without fetching`);
356
+ return cached;
357
+ }
358
+ void dedupedFetch(queryKey, "query", ...args);
359
+ log(`Returning stale data for ${queryKey}`);
360
+ return cached;
361
+ }
362
+ if (_optionalChain([cached, 'optionalAccess', _29 => _29.error]) !== void 0 && cached.errorUpdatedMs && !isExpired(cached.errorUpdatedMs)) {
363
+ if (!isStale(cached.errorUpdatedMs)) {
364
+ log(`Return fresh error ${queryKey} from cache without fetching`);
365
+ return cached;
366
+ }
367
+ void dedupedFetch(queryKey, "query", ...args);
368
+ log(`Returning stale error for ${queryKey}`);
369
+ return cached;
370
+ }
371
+ try {
372
+ await dedupedFetch(queryKey, "query", ...args);
373
+ } catch (e2) {
374
+ }
375
+ return _nullishCoalesce(getQueryValue(queryKey), () => ( DEFAULT_QUERY_STATE_ENTRY));
252
376
  }
253
377
  async function startFetching(queryKey, queryType, args) {
254
378
  log(`Start fetching ${queryKey}, queryType=${queryType}`);
@@ -272,197 +396,69 @@ function sharedQuery2(options) {
272
396
  );
273
397
  return inflightQuery.promise;
274
398
  }
275
- const promise = startFetching(queryKey, queryType, args);
276
- const abortController = new AbortController();
277
- inflightQueries.set(queryKey, { promise, abortController });
278
- return promise;
399
+ return wrapLoading(queryKey, () => {
400
+ const promise = startFetching(queryKey, queryType, args);
401
+ const abortController = new AbortController();
402
+ inflightQueries.set(queryKey, { promise, abortController });
403
+ return promise;
404
+ });
405
+ }
406
+ async function fetch(queryKey, ...args) {
407
+ return await dedupedFetch(queryKey, "query", ...args);
408
+ }
409
+ async function refetch(queryKey, ...args) {
410
+ return await dedupedFetch(queryKey, "refetch", ...args);
411
+ }
412
+ function clear() {
413
+ queryState.delete();
414
+ for (const { abortController } of Array.from(inflightQueries.values())) {
415
+ abortController.abort("Cleared");
416
+ }
417
+ inflightQueries.clear();
418
+ }
419
+ function mount(queryKey) {
420
+ mountedKeys.set(queryKey, (_nullishCoalesce(mountedKeys.get(queryKey), () => ( 0))) + 1);
421
+ }
422
+ function unmount(queryKey) {
423
+ const count = mountedKeys.get(queryKey);
424
+ if (count === 1) {
425
+ mountedKeys.delete(queryKey);
426
+ } else {
427
+ mountedKeys.set(queryKey, (_nullishCoalesce(count, () => ( 0))) - 1);
428
+ }
279
429
  }
280
- const obj = {
430
+ return {
281
431
  queryName,
282
432
  queryFn,
283
433
  refetchFn,
284
434
  expiryMs,
285
435
  staleMs,
286
- refetchOnStale,
287
436
  maxSize,
288
437
  maxBytes,
289
438
  keepLastNonEmptyData,
290
439
  log,
291
440
  queryState,
292
- /** Returns a key to identify requests based on the given args. */
293
- getQueryKey(args) {
294
- let s = _chunkCYTO5EZEcjs.stringifyDeterministicForKeys.call(void 0, args);
295
- if (s.length > 30) {
296
- s = _xxhashjs2.default.h32(s, 39406).toString(16).slice(2);
297
- }
298
- return queryName + ":" + s;
299
- },
300
- /**
301
- * Get the AbortController to abort the inflight query (if any).
302
- *
303
- * Note that once you get the controller, you can also get the signal easily
304
- * using `controller.signal`. So if you need both the controller and the
305
- * signal, just use this function.
306
- */
307
- getAbortController(args) {
308
- const queryKey = obj.getQueryKey(args);
309
- return obj.getAbortControllerByKey(queryKey);
310
- },
311
- getAbortControllerByKey(queryKey) {
312
- return _nullishCoalesce(_optionalChain([inflightQueries, 'access', _9 => _9.get, 'call', _10 => _10(queryKey), 'optionalAccess', _11 => _11.abortController]), () => ( null));
313
- },
314
- /**
315
- * Get the AbortSignal to check for query abortions.
316
- *
317
- * Example using fetch:
318
- * ```
319
- * const getUserQuery = sharedQuery({
320
- * queryName: "getUser",
321
- * queryFn: (userId: string) => {
322
- * // Get the signal for this current execution.
323
- * const signal = getUserQuery.getAbortSignal([userId]);
324
- *
325
- * // Pass the signal to fetch so that it can be aborted.
326
- * const response = await fetch(`/users/${userId}`, { signal });
327
- *
328
- * // Check for errors.
329
- * if (!response.ok) {
330
- * throw new Error(response.statusText);
331
- * }
332
- *
333
- * // Return the data.
334
- * return await response.json();
335
- * },
336
- * });
337
- * ```
338
- *
339
- * Example using `http.ts`:
340
- * ```
341
- * const getUserQuery = sharedQuery({
342
- * queryName: "getUser",
343
- * queryFn: (userId: string) => {
344
- * // Get the signal for this current execution.
345
- * const signal = getUserQuery.getAbortSignal([userId]);
346
- *
347
- * // Pass the signal to fetch so that it can be aborted.
348
- * const response = await http.get(`/users/${userId}`, { signal });
349
- * return await response.json();
350
- * },
351
- * });
352
- * ```
353
- */
354
- getAbortSignal(args) {
355
- const queryKey = obj.getQueryKey(args);
356
- return obj.getAbortSignalByKey(queryKey);
357
- },
358
- getAbortSignalByKey(queryKey) {
359
- return _nullishCoalesce(_optionalChain([obj, 'access', _12 => _12.getAbortControllerByKey, 'call', _13 => _13(queryKey), 'optionalAccess', _14 => _14.signal]), () => ( null));
360
- },
361
- /** For cached data, we need to return the correct timestamps as well. */
362
- async getCachedOrFetch(...args) {
363
- const startMs = Date.now();
364
- await queryState.readyPromise;
365
- const waitedMs = Date.now() - startMs;
366
- const queryKey = obj.getQueryKey(args);
367
- const cached = _optionalChain([queryState, 'access', _15 => _15.getSnapshot, 'call', _16 => _16(), 'optionalAccess', _17 => _17[queryKey]]);
368
- if (waitedMs) {
369
- log(`${queryKey}: Waited for ${waitedMs}ms before data is ready`);
370
- }
371
- if (_optionalChain([cached, 'optionalAccess', _18 => _18.data]) && !isExpired(_nullishCoalesce(cached.dataUpdatedMs, () => ( 0)))) {
372
- if (!isStale(_nullishCoalesce(cached.dataUpdatedMs, () => ( 0)))) {
373
- log(`Return fresh data ${queryKey} from cache without fetching`);
374
- return cached;
375
- }
376
- if (refetchOnStale) {
377
- log(`refetchOnStale for ${queryKey}`);
378
- void dedupedFetch(queryKey, "query", ...args);
379
- }
380
- log(`Returning stale data for ${queryKey}`);
381
- return cached;
382
- }
383
- const data = await dedupedFetch(queryKey, "query", ...args);
384
- const now = Date.now();
385
- return {
386
- // Don't keep old error.
387
- lastUpdatedMs: now,
388
- loading: false,
389
- data,
390
- dataUpdatedMs: now
391
- };
392
- },
393
- /** Get the entire stored entry for a query key. */
394
- getQueryValue(queryKey) {
395
- return _optionalChain([queryState, 'access', _19 => _19.getSnapshot, 'call', _20 => _20(), 'optionalAccess', _21 => _21[queryKey]]);
396
- },
397
- /** Get the current stored data for a query key. */
398
- getData(queryKey) {
399
- const stateValue = _optionalChain([queryState, 'access', _22 => _22.getSnapshot, 'call', _23 => _23(), 'optionalAccess', _24 => _24[queryKey]]);
400
- if (_optionalChain([stateValue, 'optionalAccess', _25 => _25.lastUpdatedMs])) {
401
- if (isExpired(stateValue.lastUpdatedMs)) {
402
- obj.deleteData(queryKey);
403
- return void 0;
404
- }
405
- }
406
- return _optionalChain([stateValue, 'optionalAccess', _26 => _26.data]);
407
- },
408
- /** Set the data directly if the user obtained it from somewhere else. */
441
+ getQueryKey,
442
+ getAbortController,
443
+ getAbortControllerByKey,
444
+ getAbortSignal,
445
+ getAbortSignalByKey,
446
+ isStale,
447
+ isExpired,
448
+ enforceSizeLimit,
449
+ getQueryValue,
450
+ setQueryValue,
451
+ getData,
409
452
  setData,
410
- /**
411
- * Do a new fetch even when the data is already cached, but don't fetch if
412
- * another fetch is already inflight.
413
- */
414
- async updateFromSource(...args) {
415
- const key = obj.getQueryKey(args);
416
- return await dedupedFetch(key, "query", ...args);
417
- },
418
- /**
419
- * Perform an explicit refetch. If `options.refetchFn` was not specified,
420
- * then this would be identical to calling `obj.updateFromSource()`.
421
- */
422
- async refetch(...args) {
423
- const key = obj.getQueryKey(args);
424
- return await dedupedFetch(key, "refetch", ...args);
425
- },
426
- /** Delete the cached data for one set of arguments. */
427
- deleteData(queryKey) {
428
- const record = queryState.getSnapshot();
429
- const clone = { ...record };
430
- delete clone[queryKey];
431
- queryState.setValue(clone);
432
- const inflight = inflightQueries.get(queryKey);
433
- if (inflight) {
434
- inflightQueries.delete(queryKey);
435
- inflight.abortController.abort("Deleted");
436
- }
437
- },
438
- /** Delete all currently cached data & all inflight promises. */
439
- clear() {
440
- queryState.delete();
441
- for (const { abortController } of Array.from(inflightQueries.values())) {
442
- abortController.abort("Cleared");
443
- }
444
- inflightQueries.clear();
445
- },
446
- /** Keep track of mounted keys. */
447
- mount(queryKey) {
448
- mountedKeys.set(queryKey, (_nullishCoalesce(mountedKeys.get(queryKey), () => ( 0))) + 1);
449
- },
450
- /** Clean up mounted keys. */
451
- unmount(queryKey) {
452
- const count = mountedKeys.get(queryKey);
453
- if (count === 1) {
454
- mountedKeys.delete(queryKey);
455
- } else {
456
- mountedKeys.set(queryKey, (_nullishCoalesce(count, () => ( 0))) - 1);
457
- }
458
- },
459
- /**
460
- * Discard the oldest entries if the size exceeds the limit. The last
461
- * remaining record cannot be deleted no matter what the limit is.
462
- */
463
- enforceSizeLimit
453
+ deleteData,
454
+ getCachedOrFetch,
455
+ getCachedStateOrFetch,
456
+ fetch,
457
+ refetch,
458
+ clear,
459
+ mount,
460
+ unmount
464
461
  };
465
- return obj;
466
462
  }
467
463
  function sharedQuery(options) {
468
464
  return sharedQuery1(options);
@@ -473,7 +469,7 @@ var DEFAULT_QUERY_STATE_ENTRY = {
473
469
  };
474
470
  function useSharedQuery(query, ...args) {
475
471
  const stableArgs = _chunkWXLUEDBOcjs.useDeepMemo.call(void 0, args);
476
- const [queryState, setQueryState] = _chunkKXFV42DPcjs.useSharedState.call(void 0, query.queryState);
472
+ const [queryState] = _chunkYMQDZV47cjs.useSharedState.call(void 0, query.queryState);
477
473
  const isMounted = _react.useRef.call(void 0, true);
478
474
  const initQueryKeyDone = _react.useRef.call(void 0, "");
479
475
  const queryKey = _react.useMemo.call(void 0,
@@ -481,75 +477,12 @@ function useSharedQuery(query, ...args) {
481
477
  [query, stableArgs]
482
478
  );
483
479
  const queryStateValue = _nullishCoalesce(queryState[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY));
484
- const setQueryStateValue = _react.useCallback.call(void 0,
485
- (next) => {
486
- setQueryState((prev) => {
487
- const clone = { ...prev };
488
- clone[queryKey] = typeof next === "function" ? next(_nullishCoalesce(clone[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY))) : next;
489
- return clone;
490
- });
491
- },
492
- [queryKey, setQueryState]
493
- );
494
480
  const [lastNonEmptyData, setLastNonEmptyData] = _react.useState.call(void 0, );
495
481
  _react.useEffect.call(void 0, () => {
496
482
  if (query.keepLastNonEmptyData && queryStateValue.data !== void 0) {
497
483
  setLastNonEmptyData(queryStateValue.data);
498
484
  }
499
485
  }, [query.keepLastNonEmptyData, queryStateValue.data]);
500
- const executeQuery = _react.useCallback.call(void 0,
501
- async (isRefetch) => {
502
- query.log(
503
- `Begin executing shared query ${queryKey}, isRefetch=${isRefetch}`
504
- );
505
- if (!isMounted.current) return;
506
- setQueryStateValue((prev) => ({
507
- // Keep old data and error.
508
- ...prev,
509
- lastUpdatedMs: Date.now(),
510
- loading: true
511
- }));
512
- try {
513
- let state;
514
- if (isRefetch) {
515
- const data = await query.refetch(...stableArgs);
516
- const now = Date.now();
517
- state = {
518
- // Don't keep old error.
519
- lastUpdatedMs: now,
520
- loading: false,
521
- data,
522
- dataUpdatedMs: now
523
- };
524
- } else {
525
- state = await query.getCachedOrFetch(...stableArgs);
526
- }
527
- if (!isMounted.current) return;
528
- setQueryStateValue({ ...state, loading: false });
529
- return state.data;
530
- } catch (e) {
531
- if (!isMounted.current) return;
532
- const now = Date.now();
533
- setQueryStateValue((prev) => ({
534
- // Keep old data.
535
- ...prev,
536
- lastUpdatedMs: now,
537
- loading: false,
538
- error: e,
539
- errorUpdatedMs: now
540
- }));
541
- }
542
- },
543
- [query, queryKey, setQueryStateValue, stableArgs]
544
- );
545
- _react.useEffect.call(void 0, () => {
546
- if (initQueryKeyDone.current === queryKey) return;
547
- initQueryKeyDone.current = queryKey;
548
- if (queryStateValue.data !== void 0) {
549
- return;
550
- }
551
- void executeQuery(false);
552
- }, [executeQuery, queryKey, queryStateValue.data]);
553
486
  _react.useEffect.call(void 0, () => {
554
487
  isMounted.current = true;
555
488
  query.mount(queryKey);
@@ -558,6 +491,11 @@ function useSharedQuery(query, ...args) {
558
491
  query.unmount(queryKey);
559
492
  };
560
493
  }, [query, queryKey]);
494
+ _react.useEffect.call(void 0, () => {
495
+ if (initQueryKeyDone.current === queryKey) return;
496
+ initQueryKeyDone.current = queryKey;
497
+ void query.getCachedStateOrFetch(queryKey, ...stableArgs);
498
+ }, [query, queryKey, stableArgs]);
561
499
  return _react.useMemo.call(void 0, () => {
562
500
  return {
563
501
  ...queryStateValue,
@@ -569,18 +507,17 @@ function useSharedQuery(query, ...args) {
569
507
  // abort the running queryFn.
570
508
  abortCurrentQuery: (reason) => {
571
509
  const controller = query.getAbortControllerByKey(queryKey);
572
- _optionalChain([controller, 'optionalAccess', _27 => _27.abort, 'call', _28 => _28(reason)]);
510
+ _optionalChain([controller, 'optionalAccess', _30 => _30.abort, 'call', _31 => _31(reason)]);
573
511
  return Boolean(controller);
574
512
  },
575
513
  getCachedOrFetch: async () => {
576
- const data = await query.getCachedOrFetch(...stableArgs);
577
- return _nonNil.nonNil.call(void 0,
578
- data.data,
579
- typeof data.error === "string" ? data.error : JSON.stringify(data.error)
580
- );
514
+ return await query.getCachedOrFetch(queryKey, ...stableArgs);
515
+ },
516
+ getCachedStateOrFetch: async () => {
517
+ return await query.getCachedStateOrFetch(queryKey, ...stableArgs);
581
518
  },
582
519
  refetch: () => {
583
- return executeQuery(true);
520
+ return query.refetch(queryKey, ...stableArgs);
584
521
  },
585
522
  setData: (data, dataUpdatedMs) => {
586
523
  query.setData(queryKey, data, dataUpdatedMs);
@@ -589,14 +526,7 @@ function useSharedQuery(query, ...args) {
589
526
  query.deleteData(queryKey);
590
527
  }
591
528
  };
592
- }, [
593
- executeQuery,
594
- lastNonEmptyData,
595
- query,
596
- queryKey,
597
- queryStateValue,
598
- stableArgs
599
- ]);
529
+ }, [lastNonEmptyData, query, queryKey, queryStateValue, stableArgs]);
600
530
  }
601
531
 
602
532
 
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunk2WE3FDDWmincjs = require('./chunk-2WE3FDDW.min.cjs');var _chunkKGN4HQPPmincjs = require('./chunk-KGN4HQPP.min.cjs');var _chunkJOHZV3FDmincjs = require('./chunk-JOHZV3FD.min.cjs');var _http = require('@choksheak/ts-utils/http');var _objectsizeof = require('object-sizeof'); var _objectsizeof2 = _interopRequireDefault(_objectsizeof);var _react = require('react');var _xxhashjs = require('xxhashjs'); var _xxhashjs2 = _interopRequireDefault(_xxhashjs);var H=typeof window<"u",A= exports.a ={staleMs:0,expiryMs:30*864e5,persistTo:void 0,maxSize:100,maxBytes:1e5,log:(...r)=>{H&&console.log("[sharedQuery]",...r)}};function At(r){Object.assign(A,r)}var ft=new Map;function gt(){if(H){let r=window.globalThis;return r.reactUtilsQueryRegistry??=new Map}return ft}function Tt(r){let m=gt(),s=r.queryName||r.url,c=m.get(s);if(c)return c;let l=pt(r);return m.set(s,l),l}function pt(r){let m=r.url||"",s=r.queryName||m;if(!s)throw new Error("Either queryName or url must be specified.");let c=new Map,l=new Map,D;if(r.queryFn)D=r.queryFn;else if(m){let t=_http.http.use(_http.retries.call(void 0, ));D=async(...a)=>{let e="",n=_optionalChain([a, 'optionalAccess', _2 => _2[0]]);if(n){if(typeof n=="string")e=n;else if(typeof n=="object"){let d=[];for(let[C,M]of Object.entries(n))if(M!==void 0)if(Array.isArray(M))for(let x of M)x!==void 0&&d.push([C,String(x)]);else d.push([C,String(M)]);e=new URLSearchParams(d).toString()}e&&(m.includes("?")?e="&"+e:e="?"+e)}return await(await t.get(m+e)).json()}}else throw new Error("Either queryFn or url must be specified");let o=r.refetchFn,f=_nullishCoalesce(_optionalChain([r, 'optionalAccess', _3 => _3.staleMs]), () => (A.staleMs)),S=_nullishCoalesce(_optionalChain([r, 'optionalAccess', _4 => _4.expiryMs]), () => (A.expiryMs)),b=r.store;if(b){if("persistTo"in b&&b.isValid){let t=b.isValid;r={...r,store:{...b,isValid:a=>{if(!a||typeof a!="object")return!1;for(let e of Object.values(a))if(!e||typeof e!="object"||!("data"in e)||!("dataUpdatedMs"in e)||!("lastUpdatedMs"in e)||typeof e.dataUpdatedMs!="number"||typeof e.lastUpdatedMs!="number"||!t(e.data))return!1;return!0}}}}}else{let t=_nullishCoalesce(r.persistTo, () => (A.persistTo));t&&(r={...r,store:{persistTo:t,key:s,expiryMs:S}})}let T=_nullishCoalesce(_optionalChain([r, 'optionalAccess', _5 => _5.maxSize]), () => (A.maxSize)),g=_nullishCoalesce(_optionalChain([r, 'optionalAccess', _6 => _6.maxBytes]), () => (A.maxBytes)),G=!!_optionalChain([r, 'optionalAccess', _7 => _7.keepLastNonEmptyData]),i=_nullishCoalesce(_optionalChain([r, 'optionalAccess', _8 => _8.log]), () => (A.log));r.name=s;let h=_chunk2WE3FDDWmincjs.c.call(void 0, {},r);function P(t){let a=_chunkKGN4HQPPmincjs.a.call(void 0, t);return a.length>30&&(a=_xxhashjs2.default.h32(a,39406).toString(16).slice(2)),s+":"+a}function R(t){return _nullishCoalesce(_optionalChain([c, 'access', _9 => _9.get, 'call', _10 => _10(t), 'optionalAccess', _11 => _11.abortController]), () => (null))}function J(t){let a=P(t);return R(a)}function Z(t){let a=P(t);return v(a)}function v(t){return _nullishCoalesce(_optionalChain([R, 'call', _12 => _12(t), 'optionalAccess', _13 => _13.signal]), () => (null))}function F(t){return f===0?!0:Date.now()-t>f}function U(t){return S===0?!1:Date.now()-t>S}function L(){if(!T&&!g)return;let t=h.getSnapshot(),a=Object.keys(t).length;if(a<=1)return;let e=_objectsizeof2.default.call(void 0, t),n=T?a-T:0,y=g?e-g:0;if(n<=0&&y<=0){i(`No need to trim data for ${s}: size=${a} (limit=${T}), byteSize=${e.toLocaleString()} (limit=${g.toLocaleString()})`);return}i(`Need to trim ${s}: numToCut=${n}, bytesToCut=${y}`);let d={...t},C=!1,M=(u,p)=>{if(l.has(u))return i(`Cannot clean up ${u} as it is mounted`),!1;let j=_objectsizeof2.default.call(void 0, u)+_objectsizeof2.default.call(void 0, d[u]);return i(`Cleaning up unmounted${p?", expired":""} ${u} (byteSize=${j.toLocaleString()})`),n--,y-=j,delete d[u],C=!0,!0},x=Object.fromEntries(Object.entries(d).sort((u,p)=>u[1].lastUpdatedMs-p[1].lastUpdatedMs));for(let u of Object.keys(x)){let p=d[u];if(!(!_optionalChain([p, 'optionalAccess', _14 => _14.lastUpdatedMs])||_optionalChain([p, 'optionalAccess', _15 => _15.loading]))){if(_optionalChain([p, 'optionalAccess', _16 => _16.lastUpdatedMs])&&!U(p.lastUpdatedMs))break;M(u,!0)&&delete x[u]}}if(n>0||y>0)for(let u of Object.keys(x)){let p=d[u];if(!(!_optionalChain([p, 'optionalAccess', _17 => _17.lastUpdatedMs])||_optionalChain([p, 'optionalAccess', _18 => _18.loading]))&&(M(u,!1),n<=0&&y<=0))break}if(!C){i(`No trimmable entries found for ${s}: size=${a} (limit=${T}), byteSize=${e.toLocaleString()} (limit=${g.toLocaleString()})`);return}h.setValue(d),i(`Trimmed data for ${s}: size=[${a} -> ${Object.keys(d).length}] (limit=${T}), byteSize=[${e.toLocaleString()} -> ${_objectsizeof2.default.call(void 0, d).toLocaleString()}] (limit=${g.toLocaleString()})`)}function w(t){return _optionalChain([h, 'access', _19 => _19.getSnapshot, 'call', _20 => _20(), 'optionalAccess', _21 => _21[t]])}function $(t,a){h.setValue(e=>{let n=typeof a=="function"?a(_nullishCoalesce(e[t], () => (O))):a;return{...e,[t]:n}}),L()}function K(t){let a=w(t);if(_optionalChain([a, 'optionalAccess', _22 => _22.dataUpdatedMs])&&U(a.dataUpdatedMs)){N(t);return}return _optionalChain([a, 'optionalAccess', _23 => _23.data])}function E(t,a,e=Date.now()){$(t,{lastUpdatedMs:Date.now(),loading:!1,data:a,dataUpdatedMs:e})}function N(t){let e={...h.getSnapshot()};delete e[t],h.setValue(e);let n=c.get(t);n&&(c.delete(t),n.abortController.abort("Deleted"))}async function q(t,a){$(t,O);try{let e=await a();if(_optionalChain([w, 'call', _24 => _24(t), 'optionalAccess', _25 => _25.loading])){let n=Date.now();$(t,{data:e,loading:!1,lastUpdatedMs:n,dataUpdatedMs:n})}return e}catch(e){if(_optionalChain([w, 'call', _26 => _26(t), 'optionalAccess', _27 => _27.loading])){let n=Date.now();$(t,{loading:!1,lastUpdatedMs:n,error:e,errorUpdatedMs:n})}throw e}}async function z(t){let a=Date.now();await h.readyPromise;let e=Date.now()-a;e&&i(`${t}: Waited for ${e}ms before data is ready`)}async function tt(t,...a){await z(t);let e=w(t);return _optionalChain([e, 'optionalAccess', _28 => _28.data])!==void 0&&e.dataUpdatedMs&&!U(e.dataUpdatedMs)?F(e.dataUpdatedMs)?(Q(t,"query",...a),i(`Returning stale data for ${t}`),e.data):(i(`Return fresh data ${t} from cache without fetching`),e.data):await Q(t,"query",...a)}async function et(t,...a){await z(t);let e=w(t);if(_optionalChain([e, 'optionalAccess', _29 => _29.data])!==void 0&&e.dataUpdatedMs&&!U(e.dataUpdatedMs))return F(e.dataUpdatedMs)?(Q(t,"query",...a),i(`Returning stale data for ${t}`),e):(i(`Return fresh data ${t} from cache without fetching`),e);if(_optionalChain([e, 'optionalAccess', _30 => _30.error])!==void 0&&e.errorUpdatedMs&&!U(e.errorUpdatedMs))return F(e.errorUpdatedMs)?(Q(t,"query",...a),i(`Returning stale error for ${t}`),e):(i(`Return fresh error ${t} from cache without fetching`),e);try{await Q(t,"query",...a)}catch (e2){}return _nullishCoalesce(w(t), () => (O))}async function at(t,a,e){i(`Start fetching ${t}, queryType=${a}`);try{let n=await(a==="refetch"&&o?o(...e):D(...e));return i(`Successfully fetched ${t}`),E(t,n,Date.now()),n}catch(n){throw i(`Failed to fetch ${t} for queryType=${a}: ${n}`),n}finally{c.delete(t)}}function Q(t,a,...e){let n=c.get(t);return n?(i(`Deduplicating inflight fetch for ${t}, queryType=${a}`),n.promise):q(t,()=>{let y=at(t,a,e),d=new AbortController;return c.set(t,{promise:y,abortController:d}),y})}async function rt(t,...a){return await Q(t,"query",...a)}async function nt(t,...a){return await Q(t,"refetch",...a)}function st(){h.delete();for(let{abortController:t}of Array.from(c.values()))t.abort("Cleared");c.clear()}function ot(t){l.set(t,(_nullishCoalesce(l.get(t), () => (0)))+1)}function it(t){let a=l.get(t);a===1?l.delete(t):l.set(t,(_nullishCoalesce(a, () => (0)))-1)}return{queryName:s,queryFn:D,refetchFn:o,expiryMs:S,staleMs:f,maxSize:T,maxBytes:g,keepLastNonEmptyData:G,log:i,queryState:h,getQueryKey:P,getAbortController:J,getAbortControllerByKey:R,getAbortSignal:Z,getAbortSignalByKey:v,isStale:F,isExpired:U,enforceSizeLimit:L,getQueryValue:w,setQueryValue:$,getData:K,setData:E,deleteData:N,getCachedOrFetch:tt,getCachedStateOrFetch:et,fetch:rt,refetch:nt,clear:st,mount:ot,unmount:it}}function Ut(r){return Tt(r)}var O={lastUpdatedMs:0,loading:!0};function xt(r,...m){let s=_chunkJOHZV3FDmincjs.a.call(void 0, m),[c]=_chunk2WE3FDDWmincjs.d.call(void 0, r.queryState),l=_react.useRef.call(void 0, !0),D=_react.useRef.call(void 0, ""),o=_react.useMemo.call(void 0, ()=>r.getQueryKey(s),[r,s]),f=_nullishCoalesce(c[o], () => (O)),[S,b]=_react.useState.call(void 0, );return _react.useEffect.call(void 0, ()=>{r.keepLastNonEmptyData&&f.data!==void 0&&b(f.data)},[r.keepLastNonEmptyData,f.data]),_react.useEffect.call(void 0, ()=>(l.current=!0,r.mount(o),()=>{l.current=!1,r.unmount(o)}),[r,o]),_react.useEffect.call(void 0, ()=>{D.current!==o&&(D.current=o,r.getCachedStateOrFetch(o,...s))},[r,o,s]),_react.useMemo.call(void 0, ()=>({...f,data:f.data!==void 0?f.data:S,latestData:f.data,abortCurrentQuery:T=>{let g=r.getAbortControllerByKey(o);return _optionalChain([g, 'optionalAccess', _31 => _31.abort, 'call', _32 => _32(T)]),!!g},getCachedOrFetch:async()=>await r.getCachedOrFetch(o,...s),getCachedStateOrFetch:async()=>await r.getCachedStateOrFetch(o,...s),refetch:()=>r.refetch(o,...s),setData:(T,g)=>{r.setData(o,T,g)},deleteData:()=>{r.deleteData(o)}}),[S,r,o,f,s])}exports.a = A; exports.b = At; exports.c = Ut; exports.d = xt;
2
+ //# sourceMappingURL=chunk-AX6NADU2.min.cjs.map