@choksheak/react-utils 0.4.3 → 0.4.5

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 (97) hide show
  1. package/NoSSR.cjs +30 -7
  2. package/NoSSR.min.cjs +1 -1
  3. package/NoSSR.min.cjs.map +1 -1
  4. package/NoSSR.min.mjs +1 -1
  5. package/NoSSR.min.mjs.map +1 -1
  6. package/NoSSR.mjs +0 -2
  7. package/index.cjs +979 -43
  8. package/index.d.cts +2 -2
  9. package/index.d.ts +2 -2
  10. package/index.min.cjs +1 -1
  11. package/index.min.cjs.map +1 -1
  12. package/index.min.mjs +1 -1
  13. package/index.min.mjs.map +1 -1
  14. package/index.mjs +916 -25
  15. package/package.json +1 -74
  16. package/sharedQuery.cjs +938 -10
  17. package/sharedQuery.d.cts +27 -21
  18. package/sharedQuery.d.ts +27 -21
  19. package/sharedQuery.min.cjs +1 -1
  20. package/sharedQuery.min.cjs.map +1 -1
  21. package/sharedQuery.min.mjs +1 -1
  22. package/sharedQuery.min.mjs.map +1 -1
  23. package/sharedQuery.mjs +906 -10
  24. package/sharedState.cjs +326 -15
  25. package/sharedState.d.cts +1 -0
  26. package/sharedState.d.ts +1 -0
  27. package/sharedState.min.cjs +1 -1
  28. package/sharedState.min.cjs.map +1 -1
  29. package/sharedState.min.mjs +1 -1
  30. package/sharedState.min.mjs.map +1 -1
  31. package/sharedState.mjs +291 -10
  32. package/storage.cjs +129 -10
  33. package/storage.min.cjs +1 -1
  34. package/storage.min.cjs.map +1 -1
  35. package/storage.min.mjs +1 -1
  36. package/storage.min.mjs.map +1 -1
  37. package/storage.mjs +98 -6
  38. package/stringify.cjs +57 -6
  39. package/stringify.min.cjs +1 -1
  40. package/stringify.min.cjs.map +1 -1
  41. package/stringify.min.mjs +1 -1
  42. package/stringify.min.mjs.map +1 -1
  43. package/stringify.mjs +30 -4
  44. package/useDeepMemo.cjs +40 -6
  45. package/useDeepMemo.min.cjs +1 -1
  46. package/useDeepMemo.min.cjs.map +1 -1
  47. package/useDeepMemo.min.mjs +1 -1
  48. package/useDeepMemo.min.mjs.map +1 -1
  49. package/useDeepMemo.mjs +13 -4
  50. package/chunk-3FLUS3WL.mjs +0 -561
  51. package/chunk-3X25NN6X.cjs +0 -195
  52. package/chunk-4235I4VO.mjs +0 -34
  53. package/chunk-4J7TN5JN.mjs +0 -17
  54. package/chunk-5PDGU37E.cjs +0 -104
  55. package/chunk-CYTO5EZE.cjs +0 -34
  56. package/chunk-HRE7YPUJ.min.mjs +0 -2
  57. package/chunk-HRE7YPUJ.min.mjs.map +0 -1
  58. package/chunk-IS3BZTWE.cjs +0 -35
  59. package/chunk-JOHZV3FD.min.cjs +0 -2
  60. package/chunk-JOHZV3FD.min.cjs.map +0 -1
  61. package/chunk-KGN4HQPP.min.cjs +0 -2
  62. package/chunk-KGN4HQPP.min.cjs.map +0 -1
  63. package/chunk-KILGR7YA.min.mjs +0 -2
  64. package/chunk-KILGR7YA.min.mjs.map +0 -1
  65. package/chunk-KRXENFK3.mjs +0 -195
  66. package/chunk-MUWTNWAX.min.cjs +0 -2
  67. package/chunk-MUWTNWAX.min.cjs.map +0 -1
  68. package/chunk-NL4FU2MJ.min.mjs +0 -2
  69. package/chunk-NL4FU2MJ.min.mjs.map +0 -1
  70. package/chunk-NTFFK7ZH.min.cjs +0 -2
  71. package/chunk-NTFFK7ZH.min.cjs.map +0 -1
  72. package/chunk-PHLY3LR4.mjs +0 -104
  73. package/chunk-PPJZAXJA.min.mjs +0 -2
  74. package/chunk-PPJZAXJA.min.mjs.map +0 -1
  75. package/chunk-PWDJNCGJ.cjs +0 -561
  76. package/chunk-R7POPVJR.mjs +0 -35
  77. package/chunk-TI3FMEYP.min.mjs +0 -2
  78. package/chunk-TI3FMEYP.min.mjs.map +0 -1
  79. package/chunk-UFJQLQFI.min.cjs +0 -2
  80. package/chunk-UFJQLQFI.min.cjs.map +0 -1
  81. package/chunk-VHMO75EY.min.mjs +0 -2
  82. package/chunk-VHMO75EY.min.mjs.map +0 -1
  83. package/chunk-WXLUEDBO.cjs +0 -17
  84. package/chunk-ZCDXPV3A.min.cjs +0 -2
  85. package/chunk-ZCDXPV3A.min.cjs.map +0 -1
  86. package/dist-O6NNX4Y3.min.mjs +0 -2
  87. package/dist-O6NNX4Y3.min.mjs.map +0 -1
  88. package/dist-SEGTJ72R.min.cjs +0 -2
  89. package/dist-SEGTJ72R.min.cjs.map +0 -1
  90. package/dist-UKP7SPWZ.cjs +0 -545
  91. package/dist-YXYQDOH5.mjs +0 -545
  92. package/magic-string.es-5QZEPJXJ.min.mjs +0 -14
  93. package/magic-string.es-5QZEPJXJ.min.mjs.map +0 -1
  94. package/magic-string.es-EREYSDLL.mjs +0 -1308
  95. package/magic-string.es-FXUUD55Y.min.cjs +0 -14
  96. package/magic-string.es-FXUUD55Y.min.cjs.map +0 -1
  97. package/magic-string.es-HC5PDAU3.cjs +0 -1308
@@ -1,561 +0,0 @@
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
-
3
-
4
- var _chunk3X25NN6Xcjs = require('./chunk-3X25NN6X.cjs');
5
-
6
-
7
- var _chunkCYTO5EZEcjs = require('./chunk-CYTO5EZE.cjs');
8
-
9
-
10
- var _chunkWXLUEDBOcjs = require('./chunk-WXLUEDBO.cjs');
11
-
12
- // src/sharedQuery.ts
13
- var _http = require('@choksheak/ts-utils/http');
14
- var _objectsizeof = require('object-sizeof'); var _objectsizeof2 = _interopRequireDefault(_objectsizeof);
15
-
16
-
17
-
18
-
19
-
20
-
21
- var _react = require('react');
22
- var _xxhashjs = require('xxhashjs'); var _xxhashjs2 = _interopRequireDefault(_xxhashjs);
23
- var SharedQueryConfig = {
24
- /** Refetch on every page load. */
25
- staleMs: 0,
26
- /** Keep in cache for a long time. */
27
- expiryMs: 30 * 864e5,
28
- /** Always refetch automatically if the data is stale. */
29
- refetchOnStale: true,
30
- /** No default persistence configured. */
31
- persistTo: void 0,
32
- /** 100 is not too large, but please tweak accordingly. */
33
- maxSize: 100,
34
- /** 100kb limit before discarding old records. */
35
- maxBytes: 1e5,
36
- /** Default to log to console. */
37
- log: (...args) => console.log("[sharedQuery]", ...args)
38
- };
39
- function configureSharedQuery(config) {
40
- Object.assign(SharedQueryConfig, config);
41
- }
42
- var seenQueryNames = /* @__PURE__ */ new Set();
43
- function sharedQuery(options) {
44
- const url = options.url || "";
45
- const queryName = options.queryName || url;
46
- if (!queryName) {
47
- throw new Error(`Either queryName or url must be specified.`);
48
- }
49
- if (seenQueryNames.has(queryName)) {
50
- console.warn(`Duplicate shared query name "${queryName}"`);
51
- }
52
- seenQueryNames.add(queryName);
53
- const inflightQueries = /* @__PURE__ */ new Map();
54
- const mountedKeys = /* @__PURE__ */ new Map();
55
- let queryFn;
56
- if (options.queryFn) {
57
- queryFn = options.queryFn;
58
- } else if (url) {
59
- const fetcher = _http.http.use(_http.retries.call(void 0, ));
60
- queryFn = async (...args) => {
61
- let params = "";
62
- const firstArg = _optionalChain([args, 'optionalAccess', _ => _[0]]);
63
- if (firstArg) {
64
- if (typeof firstArg === "string") {
65
- params = firstArg;
66
- } else if (typeof firstArg === "object") {
67
- const entries = [];
68
- for (const [k, v] of Object.entries(firstArg)) {
69
- if (v === void 0) continue;
70
- if (Array.isArray(v)) {
71
- for (const item of v) {
72
- if (item === void 0) continue;
73
- entries.push([k, String(item)]);
74
- }
75
- } else {
76
- entries.push([k, String(v)]);
77
- }
78
- }
79
- params = new URLSearchParams(entries).toString();
80
- }
81
- if (params) {
82
- if (url.includes("?")) {
83
- params = "&" + params;
84
- } else {
85
- params = "?" + params;
86
- }
87
- }
88
- }
89
- const response = await fetcher.get(url + params);
90
- return await response.json();
91
- };
92
- } else {
93
- throw new Error(`Either queryFn or url must be specified`);
94
- }
95
- const refetchFn = options.refetchFn;
96
- const staleMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.staleMs]), () => ( SharedQueryConfig.staleMs));
97
- const expiryMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.expiryMs]), () => ( SharedQueryConfig.expiryMs));
98
- const refetchOnStale = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.refetchOnStale]), () => ( SharedQueryConfig.refetchOnStale));
99
- const store = options.store;
100
- if (store) {
101
- if ("persistTo" in store && store.isValid) {
102
- const isValid = store.isValid;
103
- options = {
104
- ...options,
105
- store: {
106
- ...store,
107
- isValid: (u) => {
108
- if (!u || typeof u !== "object") {
109
- return false;
110
- }
111
- for (const v of Object.values(u)) {
112
- if (!v || typeof v !== "object" || !("data" in v) || !("dataUpdatedMs" in v) || !("lastUpdatedMs" in v) || typeof v.dataUpdatedMs !== "number" || typeof v.lastUpdatedMs !== "number" || !isValid(v.data)) {
113
- return false;
114
- }
115
- }
116
- return true;
117
- }
118
- }
119
- };
120
- }
121
- } else {
122
- const persistTo = _nullishCoalesce(options.persistTo, () => ( SharedQueryConfig.persistTo));
123
- if (persistTo) {
124
- options = {
125
- ...options,
126
- store: {
127
- persistTo,
128
- key: queryName,
129
- expiryMs
130
- }
131
- };
132
- }
133
- }
134
- const maxSize = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.maxSize]), () => ( SharedQueryConfig.maxSize));
135
- const maxBytes = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _6 => _6.maxBytes]), () => ( SharedQueryConfig.maxBytes));
136
- const keepLastNonEmptyData = Boolean(_optionalChain([options, 'optionalAccess', _7 => _7.keepLastNonEmptyData]));
137
- const log = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _8 => _8.log]), () => ( SharedQueryConfig.log));
138
- const queryState = _chunk3X25NN6Xcjs.sharedState.call(void 0,
139
- {},
140
- // defaultValue
141
- options
142
- );
143
- function isStale(dataUpdatedMs) {
144
- if (staleMs === 0) return true;
145
- const ageMs = Date.now() - dataUpdatedMs;
146
- return ageMs > staleMs;
147
- }
148
- function isExpired(dataUpdatedMs) {
149
- if (expiryMs === 0) return false;
150
- const ageMs = Date.now() - dataUpdatedMs;
151
- return ageMs > expiryMs;
152
- }
153
- function enforceSizeLimit() {
154
- if (!maxSize && !maxBytes) {
155
- return;
156
- }
157
- const oldState = queryState.getSnapshot();
158
- const oldSize = Object.keys(oldState).length;
159
- if (oldSize <= 1) {
160
- return;
161
- }
162
- const oldByteSize = _objectsizeof2.default.call(void 0, oldState);
163
- let numToCut = maxSize ? oldSize - maxSize : 0;
164
- let bytesToCut = maxBytes ? oldByteSize - maxBytes : 0;
165
- if (numToCut <= 0 && bytesToCut <= 0) {
166
- log(
167
- `No need to trim data for ${queryName}: size=${oldSize} (limit=${maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${maxBytes.toLocaleString()})`
168
- );
169
- return;
170
- }
171
- log(
172
- `Need to trim ${queryName}: numToCut=${numToCut}, bytesToCut=${bytesToCut}`
173
- );
174
- const newState = { ...oldState };
175
- let needUpdate = false;
176
- const deleteKeyIfNotMounted = (key, expired) => {
177
- if (mountedKeys.has(key)) {
178
- log(`Cannot clean up ${key} as it is mounted`);
179
- return;
180
- }
181
- const byteSize = _objectsizeof2.default.call(void 0, key) + _objectsizeof2.default.call(void 0, newState[key]);
182
- log(
183
- `Cleaning up unmounted${expired ? ", expired" : ""} ${key} (byteSize=${byteSize.toLocaleString()})`
184
- );
185
- numToCut--;
186
- bytesToCut -= byteSize;
187
- delete newState[key];
188
- needUpdate = true;
189
- };
190
- let entriesByTimeAscending = Object.entries(newState).sort(
191
- (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
192
- );
193
- for (const [key] of entriesByTimeAscending) {
194
- if (!isExpired(newState[key].lastUpdatedMs)) {
195
- break;
196
- }
197
- deleteKeyIfNotMounted(key, true);
198
- }
199
- if (numToCut > 0 || bytesToCut > 0) {
200
- if (needUpdate) {
201
- entriesByTimeAscending = Object.entries(newState).sort(
202
- (entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
203
- );
204
- }
205
- for (const [key] of entriesByTimeAscending) {
206
- deleteKeyIfNotMounted(key, false);
207
- if (numToCut <= 0 && bytesToCut <= 0) {
208
- break;
209
- }
210
- }
211
- }
212
- if (!needUpdate) {
213
- log(
214
- `No trimmable entries found for ${queryName}: size=${oldSize} (limit=${maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${maxBytes.toLocaleString()})`
215
- );
216
- return;
217
- }
218
- queryState.setValue(newState);
219
- log(
220
- `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()})`
221
- );
222
- }
223
- function setData(queryKey, data, dataUpdatedMs = Date.now()) {
224
- const entry = {
225
- lastUpdatedMs: Date.now(),
226
- loading: false,
227
- data,
228
- dataUpdatedMs
229
- };
230
- queryState.setValue((prev) => ({ ...prev, [queryKey]: entry }));
231
- enforceSizeLimit();
232
- }
233
- async function startFetching(queryKey, queryType, args) {
234
- log(`Start fetching ${queryKey}, queryType=${queryType}`);
235
- try {
236
- const data = await (queryType === "refetch" && refetchFn ? refetchFn(...args) : queryFn(...args));
237
- log(`Successfully fetched ${queryKey}`);
238
- setData(queryKey, data, Date.now());
239
- return data;
240
- } catch (e) {
241
- log(`Failed to fetch ${queryKey} for queryType=${queryType}: ${e}`);
242
- throw e;
243
- } finally {
244
- inflightQueries.delete(queryKey);
245
- }
246
- }
247
- function dedupedFetch(queryKey, queryType, ...args) {
248
- const inflightQuery = inflightQueries.get(queryKey);
249
- if (inflightQuery) {
250
- log(
251
- `Deduplicating inflight fetch for ${queryKey}, queryType=${queryType}`
252
- );
253
- return inflightQuery.promise;
254
- }
255
- const promise = startFetching(queryKey, queryType, args);
256
- const abortController = new AbortController();
257
- inflightQueries.set(queryKey, { promise, abortController });
258
- return promise;
259
- }
260
- const obj = {
261
- queryName,
262
- queryFn,
263
- refetchFn,
264
- expiryMs,
265
- staleMs,
266
- refetchOnStale,
267
- maxSize,
268
- maxBytes,
269
- keepLastNonEmptyData,
270
- log,
271
- queryState,
272
- /** Returns a key to identify requests based on the given args. */
273
- getQueryKey(args) {
274
- let s = _chunkCYTO5EZEcjs.stringifyDeterministicForKeys.call(void 0, args);
275
- if (s.length > 30) {
276
- s = _xxhashjs2.default.h32(s, 39406).toString(16).slice(2);
277
- }
278
- return queryName + ":" + s;
279
- },
280
- /**
281
- * Get the AbortController to abort the inflight query (if any).
282
- *
283
- * Note that once you get the controller, you can also get the signal easily
284
- * using `controller.signal`. So if you need both the controller and the
285
- * signal, just use this function.
286
- */
287
- getAbortController(args) {
288
- const queryKey = obj.getQueryKey(args);
289
- return obj.getAbortControllerByKey(queryKey);
290
- },
291
- getAbortControllerByKey(queryKey) {
292
- return _nullishCoalesce(_optionalChain([inflightQueries, 'access', _9 => _9.get, 'call', _10 => _10(queryKey), 'optionalAccess', _11 => _11.abortController]), () => ( null));
293
- },
294
- /**
295
- * Get the AbortSignal to check for query abortions.
296
- *
297
- * Example using fetch:
298
- * ```
299
- * const getUserQuery = sharedQuery({
300
- * queryName: "getUser",
301
- * queryFn: (userId: string) => {
302
- * // Get the signal for this current execution.
303
- * const signal = getUserQuery.getAbortSignal([userId]);
304
- *
305
- * // Pass the signal to fetch so that it can be aborted.
306
- * const response = await fetch(`/users/${userId}`, { signal });
307
- *
308
- * // Check for errors.
309
- * if (!response.ok) {
310
- * throw new Error(response.statusText);
311
- * }
312
- *
313
- * // Return the data.
314
- * return await response.json();
315
- * },
316
- * });
317
- * ```
318
- *
319
- * Example using `http.ts`:
320
- * ```
321
- * const getUserQuery = sharedQuery({
322
- * queryName: "getUser",
323
- * queryFn: (userId: string) => {
324
- * // Get the signal for this current execution.
325
- * const signal = getUserQuery.getAbortSignal([userId]);
326
- *
327
- * // Pass the signal to fetch so that it can be aborted.
328
- * const response = await http.get(`/users/${userId}`, { signal });
329
- * return await response.json();
330
- * },
331
- * });
332
- * ```
333
- */
334
- getAbortSignal(args) {
335
- const queryKey = obj.getQueryKey(args);
336
- return obj.getAbortSignalByKey(queryKey);
337
- },
338
- getAbortSignalByKey(queryKey) {
339
- return _nullishCoalesce(_optionalChain([obj, 'access', _12 => _12.getAbortControllerByKey, 'call', _13 => _13(queryKey), 'optionalAccess', _14 => _14.signal]), () => ( null));
340
- },
341
- /** For cached data, we need to return the correct timestamps as well. */
342
- async getCachedOrFetch(...args) {
343
- const startMs = Date.now();
344
- await queryState.readyPromise;
345
- const waitedMs = Date.now() - startMs;
346
- const queryKey = obj.getQueryKey(args);
347
- const cached = _optionalChain([queryState, 'access', _15 => _15.getSnapshot, 'call', _16 => _16(), 'optionalAccess', _17 => _17[queryKey]]);
348
- if (waitedMs) {
349
- log(`${queryKey}: Waited for ${waitedMs}ms before data is ready`);
350
- }
351
- if (_optionalChain([cached, 'optionalAccess', _18 => _18.data]) && !isExpired(_nullishCoalesce(cached.dataUpdatedMs, () => ( 0)))) {
352
- if (!isStale(_nullishCoalesce(cached.dataUpdatedMs, () => ( 0)))) {
353
- log(`Return fresh data ${queryKey} from cache without fetching`);
354
- return cached;
355
- }
356
- if (refetchOnStale) {
357
- log(`refetchOnStale for ${queryKey}`);
358
- void dedupedFetch(queryKey, "query", ...args);
359
- }
360
- log(`Returning stale data for ${queryKey}`);
361
- return cached;
362
- }
363
- const data = await dedupedFetch(queryKey, "query", ...args);
364
- const now = Date.now();
365
- return {
366
- // Don't keep old error.
367
- lastUpdatedMs: now,
368
- loading: false,
369
- data,
370
- dataUpdatedMs: now
371
- };
372
- },
373
- /** Get the entire stored entry for a query key. */
374
- getQueryValue(queryKey) {
375
- return _optionalChain([queryState, 'access', _19 => _19.getSnapshot, 'call', _20 => _20(), 'optionalAccess', _21 => _21[queryKey]]);
376
- },
377
- /** Get the current stored data for a query key. */
378
- getData(queryKey) {
379
- const stateValue = _optionalChain([queryState, 'access', _22 => _22.getSnapshot, 'call', _23 => _23(), 'optionalAccess', _24 => _24[queryKey]]);
380
- if (_optionalChain([stateValue, 'optionalAccess', _25 => _25.lastUpdatedMs])) {
381
- if (isExpired(stateValue.lastUpdatedMs)) {
382
- obj.deleteData(queryKey);
383
- return void 0;
384
- }
385
- }
386
- return _optionalChain([stateValue, 'optionalAccess', _26 => _26.data]);
387
- },
388
- /** Set the data directly if the user obtained it from somewhere else. */
389
- setData,
390
- /**
391
- * Do a new fetch even when the data is already cached, but don't fetch if
392
- * another fetch is already inflight.
393
- */
394
- async updateFromSource(...args) {
395
- const key = obj.getQueryKey(args);
396
- return await dedupedFetch(key, "query", ...args);
397
- },
398
- /**
399
- * Perform an explicit refetch. If `options.refetchFn` was not specified,
400
- * then this would be identical to calling `obj.updateFromSource()`.
401
- */
402
- async refetch(...args) {
403
- const key = obj.getQueryKey(args);
404
- return await dedupedFetch(key, "refetch", ...args);
405
- },
406
- /** Delete the cached data for one set of arguments. */
407
- deleteData(queryKey) {
408
- const record = queryState.getSnapshot();
409
- const clone = { ...record };
410
- delete clone[queryKey];
411
- queryState.setValue(clone);
412
- const inflight = inflightQueries.get(queryKey);
413
- if (inflight) {
414
- inflightQueries.delete(queryKey);
415
- inflight.abortController.abort("Deleted");
416
- }
417
- },
418
- /** Delete all currently cached data & all inflight promises. */
419
- clear() {
420
- queryState.delete();
421
- for (const { abortController } of Array.from(inflightQueries.values())) {
422
- abortController.abort("Cleared");
423
- }
424
- inflightQueries.clear();
425
- },
426
- /** Keep track of mounted keys. */
427
- mount(queryKey) {
428
- mountedKeys.set(queryKey, (_nullishCoalesce(mountedKeys.get(queryKey), () => ( 0))) + 1);
429
- },
430
- /** Clean up mounted keys. */
431
- unmount(queryKey) {
432
- const count = mountedKeys.get(queryKey);
433
- if (count === 1) {
434
- mountedKeys.delete(queryKey);
435
- } else {
436
- mountedKeys.set(queryKey, (_nullishCoalesce(count, () => ( 0))) - 1);
437
- }
438
- },
439
- /**
440
- * Discard the oldest entries if the size exceeds the limit. The last
441
- * remaining record cannot be deleted no matter what the limit is.
442
- */
443
- enforceSizeLimit
444
- };
445
- return obj;
446
- }
447
- var DEFAULT_QUERY_STATE_ENTRY = {
448
- lastUpdatedMs: 0,
449
- loading: true
450
- };
451
- function useSharedQuery(query, ...args) {
452
- const stableArgs = _chunkWXLUEDBOcjs.useDeepMemo.call(void 0, args);
453
- const [queryState, setQueryState] = _chunk3X25NN6Xcjs.useSharedState.call(void 0, query.queryState);
454
- const isMounted = _react.useRef.call(void 0, true);
455
- const queryKey = _react.useMemo.call(void 0,
456
- () => query.getQueryKey(stableArgs),
457
- [query, stableArgs]
458
- );
459
- const queryStateValue = _nullishCoalesce(queryState[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY));
460
- const setQueryStateValue = _react.useCallback.call(void 0,
461
- (next) => {
462
- setQueryState((prev) => {
463
- const clone = { ...prev };
464
- clone[queryKey] = typeof next === "function" ? next(_nullishCoalesce(clone[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY))) : next;
465
- return clone;
466
- });
467
- },
468
- [queryKey, setQueryState]
469
- );
470
- const [lastNonEmptyData, setLastNonEmptyData] = _react.useState.call(void 0, );
471
- _react.useEffect.call(void 0, () => {
472
- if (query.keepLastNonEmptyData && queryStateValue.data !== void 0) {
473
- setLastNonEmptyData(queryStateValue.data);
474
- }
475
- }, [query.keepLastNonEmptyData, queryStateValue.data]);
476
- const execute = _react.useCallback.call(void 0,
477
- async (isRefetch) => {
478
- query.log(
479
- `Begin executing shared query ${queryKey}, isRefetch=${isRefetch}`
480
- );
481
- if (!isMounted.current) return;
482
- setQueryStateValue((prev) => ({
483
- // Keep old data and error.
484
- ...prev,
485
- lastUpdatedMs: Date.now(),
486
- loading: true
487
- }));
488
- try {
489
- let state;
490
- if (isRefetch) {
491
- const data = await query.refetch(...stableArgs);
492
- const now = Date.now();
493
- state = {
494
- // Don't keep old error.
495
- lastUpdatedMs: now,
496
- loading: false,
497
- data,
498
- dataUpdatedMs: now
499
- };
500
- } else {
501
- state = await query.getCachedOrFetch(...stableArgs);
502
- }
503
- if (!isMounted.current) return;
504
- setQueryStateValue({ ...state, loading: false });
505
- } catch (e) {
506
- if (!isMounted.current) return;
507
- const now = Date.now();
508
- setQueryStateValue((prev) => ({
509
- // Keep old data.
510
- ...prev,
511
- lastUpdatedMs: now,
512
- loading: false,
513
- error: e,
514
- errorUpdatedMs: now
515
- }));
516
- }
517
- },
518
- [query, queryKey, setQueryStateValue, stableArgs]
519
- );
520
- _react.useEffect.call(void 0, () => {
521
- isMounted.current = true;
522
- query.mount(queryKey);
523
- void execute(false);
524
- return () => {
525
- isMounted.current = false;
526
- query.unmount(queryKey);
527
- };
528
- }, [execute, query, queryKey]);
529
- return _react.useMemo.call(void 0, () => {
530
- return {
531
- ...queryStateValue,
532
- // Fill with lastNonEmptyData when data is undefined.
533
- data: queryStateValue.data !== void 0 ? queryStateValue.data : lastNonEmptyData,
534
- latestData: queryStateValue.data,
535
- // This works only if the user-given queryFn supports abort. If not,
536
- // this function doesn't do anything, since we don't have any means to
537
- // abort the running queryFn.
538
- abortCurrentQuery: (reason) => {
539
- const controller = query.getAbortControllerByKey(queryKey);
540
- _optionalChain([controller, 'optionalAccess', _27 => _27.abort, 'call', _28 => _28(reason)]);
541
- return Boolean(controller);
542
- },
543
- refetch: () => {
544
- return execute(true);
545
- },
546
- setData: (data, dataUpdatedMs) => {
547
- query.setData(queryKey, data, dataUpdatedMs);
548
- },
549
- deleteData: () => {
550
- query.deleteData(queryKey);
551
- }
552
- };
553
- }, [execute, lastNonEmptyData, query, queryKey, queryStateValue]);
554
- }
555
-
556
-
557
-
558
-
559
-
560
-
561
- exports.SharedQueryConfig = SharedQueryConfig; exports.configureSharedQuery = configureSharedQuery; exports.sharedQuery = sharedQuery; exports.useSharedQuery = useSharedQuery;
@@ -1,35 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all) => {
11
- for (var name in all)
12
- __defProp(target, name, { get: all[name], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
30
-
31
- export {
32
- __commonJS,
33
- __export,
34
- __toESM
35
- };
@@ -1,2 +0,0 @@
1
- function e(n){let t=new Set;return JSON.stringify(n,(s,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(t.has(r))return"[Circular]";if(t.add(r),r!==n)try{JSON.stringify(r)}catch{return"[Unserializable]"}return Object.keys(r).sort().reduce((i,o)=>(i[o]=r[o],i),{})})}export{e as a};
2
- //# sourceMappingURL=chunk-TI3FMEYP.min.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/stringify.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Implements special stringify for use in the shared queries. This will likely\n * not be reusable for your own use cases.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\n/**\n * JSON stringify a value of any type, and returns an unsafe string. The string\n * is \"unsafe\" because you might not be able to restore the original object\n * using the serialized JSON. This is specifically used for query key generation\n * and is not suitable for more general uses.\n *\n * Note: The given value should not contain any functions because functions\n * cannot be serialized and deserialized properly.\n */\nexport function stringifyDeterministicForKeys(params: unknown): string {\n const cache = new Set();\n\n return JSON.stringify(params, (_, value) => {\n if (typeof value === \"function\") {\n throw new Error(`Functions should not be passed into query parameters`);\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n\n if (cache.has(value)) {\n // Circular reference detected! Return a placeholder string.\n return \"[Circular]\";\n }\n\n cache.add(value);\n\n // Don't crash on circular references, but don't mark the top level object\n // as circular because we want to return as much string as possible.\n if (value !== params) {\n try {\n JSON.stringify(value);\n } catch {\n return \"[Unserializable]\";\n }\n }\n\n return Object.keys(value)\n .sort()\n .reduce(\n (result: Record<string, unknown>, key: string) => {\n result[key] = value[key];\n return result;\n },\n {} as Record<string, unknown>,\n );\n });\n}\n"],"mappings":"AAmBO,SAASA,EAA8BC,EAAyB,CACrE,IAAMC,EAAQ,IAAI,IAElB,OAAO,KAAK,UAAUD,EAAQ,CAACE,EAAGC,IAAU,CAC1C,GAAI,OAAOA,GAAU,WACnB,MAAM,IAAI,MAAM,sDAAsD,EAGxE,GAAI,CAACA,GAAS,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAC5D,OAAOA,EAGT,GAAIF,EAAM,IAAIE,CAAK,EAEjB,MAAO,aAOT,GAJAF,EAAM,IAAIE,CAAK,EAIXA,IAAUH,EACZ,GAAI,CACF,KAAK,UAAUG,CAAK,CACtB,MAAQ,CACN,MAAO,kBACT,CAGF,OAAO,OAAO,KAAKA,CAAK,EACrB,KAAK,EACL,OACC,CAACC,EAAiCC,KAChCD,EAAOC,CAAG,EAAIF,EAAME,CAAG,EAChBD,GAET,CAAC,CACH,CACJ,CAAC,CACH","names":["stringifyDeterministicForKeys","params","cache","_","value","result","key"]}
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _kvStore = require('@choksheak/ts-utils/kvStore');var _localStore = require('@choksheak/ts-utils/localStore');var n=typeof window>"u";function S(s,a){let{store:e}=_nullishCoalesce(s, () => ({}));if(!e)return null;if("persistTo"in e&&typeof e.persistTo=="string"&&"key"in e&&typeof e.key=="string"){let i=e.expiryMs||a,t={...e,expiryMs:i};switch(e.persistTo){case"localStorage":return c(t);case"indexedDb":return l(t);default:throw e.persistTo,new Error(`Unknown store.adapter ${e.persistTo}`)}}return e}function c({key:s,expiryMs:a,isValid:e}){let t=_localStore.createLocalStore.call(void 0, "react-utils",{defaultExpiryMs:a}),o=s+":";return{set:(r,d)=>{n||t.set(o+r,d)},get:r=>{if(n)return;let d=o+r,p=t.get(d);if(p!==void 0&&e&&!e(p)){console.warn(`localStorage adapter: Auto-discard invalid value for ${d}: ${JSON.stringify(p)}`),t.delete(d);return}return p},delete:r=>{n||t.delete(o+r)},clear:()=>{n||t.clear()}}}function l({key:s,expiryMs:a,isValid:e}){let i=s+":";return{set:async(t,o)=>{n||await _kvStore.kvStore.set(i+t,o,a)},get:async t=>{if(n)return;let o=i+t,r=await _kvStore.kvStore.get(o);if(r!==void 0&&e&&!e(r)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${t}:`,r),await _kvStore.kvStore.delete(o);return}return r},delete:async t=>{n||await _kvStore.kvStore.delete(i+t)},clear:async()=>{n||await _kvStore.kvStore.clear()}}}exports.a = S; exports.b = c; exports.c = l;
2
- //# sourceMappingURL=chunk-UFJQLQFI.min.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage.ts"],"names":["IS_NOT_BROWSER","getStorageAdapter","options","defaultStoreExpiryMs","store","expiryMs","config","localStoreAdapter","kvStoreAdapter"],"mappings":"AAYA,mOAAwB,4DACS,IAkC3BA,CAAAA,CAAiB,OAAO,MAAA,CAAW,GAAA,CAMlC,SAASC,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CAC0B,CAC1B,GAAM,CAAE,KAAA,CAAAC,CAAM,CAAA,kBAAIF,CAAAA,SAAW,CAAC,GAAA,CAE9B,EAAA,CAAI,CAACE,CAAAA,CACH,OAAO,IAAA,CAGT,EAAA,CACE,WAAA,GAAeA,CAAAA,EACf,OAAOA,CAAAA,CAAM,SAAA,EAAc,QAAA,EAC3B,KAAA,GAASA,CAAAA,EACT,OAAOA,CAAAA,CAAM,GAAA,EAAQ,QAAA,CACrB,CACA,IAAMC,CAAAA,CAAWD,CAAAA,CAAM,QAAA,EAAYD,CAAAA,CAC7BG,CAAAA,CAAS,CAAE,GAAGF,CAAAA,CAAO,QAAA,CAAAC,CAAS,CAAA,CAEpC,MAAA,CAAQD,CAAAA,CAAM,SAAA,CAAW,CACvB,IAAK,cAAA,CACH,OAAOG,CAAAA,CAAqBD,CAAM,CAAA,CAEpC,IAAK,WAAA,CACH,OAAOE,CAAAA,CAAkBF,CAAM,CAAA,CAEjC,OAAA,CACE,MAAAF,CAAAA,CAAM,SAAA,CACA,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyBA,CAAAA,CAAM,SAAS,CAAA,CAAA","file":"/Users/choksheaklau/src/react-utils/dist/chunk-UFJQLQFI.min.cjs","sourcesContent":["/**\n * @packageDocumentation\n *\n * Backing storage implementation for the shared state. Note that this uses the\n * LocalStore and KvStore from package \"@choksheak/ts-utils\", but is customized\n * to be used for shared states.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\nimport { Duration } from \"@choksheak/ts-utils/duration\";\nimport { kvStore } from \"@choksheak/ts-utils/kvStore\";\nimport { createLocalStore } from \"@choksheak/ts-utils/localStore\";\nimport { StorageAdapter } from \"@choksheak/ts-utils/storageAdapter\";\n\n/** List of all available pre-built persistence options. */\nexport type PersistTo = \"localStorage\" | \"indexedDb\";\n\n/** Options to configure a pre-built store adapter. */\nexport type StoreOptions = {\n /** Choose which pre-built store adapter to use. */\n persistTo: PersistTo;\n\n /** Storage key to act as a namespace to store the data. */\n key: string;\n\n /** How long to wait before the value is considered expired. */\n expiryMs?: number | Duration;\n\n /** Returns true if the given value supposed to be of type T is valid. */\n isValid?: (u: unknown) => boolean;\n};\n\nexport type StoreConstructorArgs = Omit<StoreOptions, \"persistTo\">;\n\n/** Either use a pre-built store, or a custom one you provide. */\nexport type StorageOptions<T> = {\n /**\n * You can either specify the storage adapter directly to use a custom\n * store, or specify the properties to use the pre-built ones.\n */\n store?: StorageAdapter<T> | StoreOptions;\n};\n\n// In SSR (Server-Side Rendering) mode, we never want to use our storage\n// adapters for anything.\nconst IS_NOT_BROWSER = typeof window === \"undefined\";\n\n/**\n * Convert a StorageOptions<T> config object into an actual storage adapter, or\n * returns null if a storage adapter is not configured.\n */\nexport function getStorageAdapter<T>(\n options: StorageOptions<T> | undefined,\n defaultStoreExpiryMs: number,\n): StorageAdapter<T> | null {\n const { store } = options ?? {};\n\n if (!store) {\n return null;\n }\n\n if (\n \"persistTo\" in store &&\n typeof store.persistTo === \"string\" &&\n \"key\" in store &&\n typeof store.key === \"string\"\n ) {\n const expiryMs = store.expiryMs || defaultStoreExpiryMs;\n const config = { ...store, expiryMs };\n\n switch (store.persistTo) {\n case \"localStorage\":\n return localStoreAdapter<T>(config);\n\n case \"indexedDb\":\n return kvStoreAdapter<T>(config);\n\n default:\n store.persistTo satisfies never;\n throw new Error(`Unknown store.adapter ${store.persistTo}`);\n }\n }\n\n return store as StorageAdapter<T>;\n}\n\n/**\n * Create a new SSR-safe local store adapter, which allows users to reuse the\n * same adapter in multiple shared states or shared queries.\n */\nexport function localStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n // Put everything in the same store so that we can GC properly.\n const STORE_NAME = \"react-utils\";\n\n const adapter = createLocalStore(STORE_NAME, {\n defaultExpiryMs: expiryMs,\n });\n\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = key + \":\";\n\n return {\n set: (key: string, value: T): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n adapter.set(keyPrefix + key, value);\n },\n\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = adapter.get<T>(fullKey);\n\n // If there is no value, don't try to check for validatity.\n if (value !== undefined && isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${fullKey}: ${JSON.stringify(value)}`,\n );\n adapter.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n\n delete: (key: string): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.delete(keyPrefix + key);\n },\n\n /** Note that this will clear all keys in all shared states. */\n clear: (): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.clear();\n },\n };\n}\n\n/**\n * Create a new SSR-safe indexed DB KV store adapter, which allows users to\n * reuse the same adapter in multiple shared states or shared queries.\n */\nexport function kvStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = key + \":\";\n\n // Prefix all keys using `keyPrefix` so that we can keep all data in\n // the same store in the same DB. If we keep the data in different\n // DB stores, then GC will not be able to clean up abandoned stores.\n return {\n set: async (key: string, value: T): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n await kvStore.set(keyPrefix + key, value, expiryMs);\n },\n get: async (key: string): Promise<T | undefined> => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = await kvStore.get<T>(fullKey);\n\n // If there is no value, don't try to check for validatity.\n if (value !== undefined && isValid && !isValid(value)) {\n console.warn(\n `indexedDb adapter: Auto-discard invalid value for ${key}:`,\n value,\n );\n await kvStore.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n delete: async (key: string): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.delete(keyPrefix + key);\n },\n clear: async (): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.clear();\n },\n };\n}\n"]}
@@ -1,2 +0,0 @@
1
- import{kvStore as u}from"@choksheak/ts-utils/kvStore";import{createLocalStore as f}from"@choksheak/ts-utils/localStore";var n=typeof window>"u";function S(s,a){let{store:e}=s??{};if(!e)return null;if("persistTo"in e&&typeof e.persistTo=="string"&&"key"in e&&typeof e.key=="string"){let i=e.expiryMs||a,t={...e,expiryMs:i};switch(e.persistTo){case"localStorage":return c(t);case"indexedDb":return l(t);default:throw e.persistTo,new Error(`Unknown store.adapter ${e.persistTo}`)}}return e}function c({key:s,expiryMs:a,isValid:e}){let t=f("react-utils",{defaultExpiryMs:a}),o=s+":";return{set:(r,d)=>{n||t.set(o+r,d)},get:r=>{if(n)return;let d=o+r,p=t.get(d);if(p!==void 0&&e&&!e(p)){console.warn(`localStorage adapter: Auto-discard invalid value for ${d}: ${JSON.stringify(p)}`),t.delete(d);return}return p},delete:r=>{n||t.delete(o+r)},clear:()=>{n||t.clear()}}}function l({key:s,expiryMs:a,isValid:e}){let i=s+":";return{set:async(t,o)=>{n||await u.set(i+t,o,a)},get:async t=>{if(n)return;let o=i+t,r=await u.get(o);if(r!==void 0&&e&&!e(r)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${t}:`,r),await u.delete(o);return}return r},delete:async t=>{n||await u.delete(i+t)},clear:async()=>{n||await u.clear()}}}export{S as a,c as b,l as c};
2
- //# sourceMappingURL=chunk-VHMO75EY.min.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Backing storage implementation for the shared state. Note that this uses the\n * LocalStore and KvStore from package \"@choksheak/ts-utils\", but is customized\n * to be used for shared states.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\nimport { Duration } from \"@choksheak/ts-utils/duration\";\nimport { kvStore } from \"@choksheak/ts-utils/kvStore\";\nimport { createLocalStore } from \"@choksheak/ts-utils/localStore\";\nimport { StorageAdapter } from \"@choksheak/ts-utils/storageAdapter\";\n\n/** List of all available pre-built persistence options. */\nexport type PersistTo = \"localStorage\" | \"indexedDb\";\n\n/** Options to configure a pre-built store adapter. */\nexport type StoreOptions = {\n /** Choose which pre-built store adapter to use. */\n persistTo: PersistTo;\n\n /** Storage key to act as a namespace to store the data. */\n key: string;\n\n /** How long to wait before the value is considered expired. */\n expiryMs?: number | Duration;\n\n /** Returns true if the given value supposed to be of type T is valid. */\n isValid?: (u: unknown) => boolean;\n};\n\nexport type StoreConstructorArgs = Omit<StoreOptions, \"persistTo\">;\n\n/** Either use a pre-built store, or a custom one you provide. */\nexport type StorageOptions<T> = {\n /**\n * You can either specify the storage adapter directly to use a custom\n * store, or specify the properties to use the pre-built ones.\n */\n store?: StorageAdapter<T> | StoreOptions;\n};\n\n// In SSR (Server-Side Rendering) mode, we never want to use our storage\n// adapters for anything.\nconst IS_NOT_BROWSER = typeof window === \"undefined\";\n\n/**\n * Convert a StorageOptions<T> config object into an actual storage adapter, or\n * returns null if a storage adapter is not configured.\n */\nexport function getStorageAdapter<T>(\n options: StorageOptions<T> | undefined,\n defaultStoreExpiryMs: number,\n): StorageAdapter<T> | null {\n const { store } = options ?? {};\n\n if (!store) {\n return null;\n }\n\n if (\n \"persistTo\" in store &&\n typeof store.persistTo === \"string\" &&\n \"key\" in store &&\n typeof store.key === \"string\"\n ) {\n const expiryMs = store.expiryMs || defaultStoreExpiryMs;\n const config = { ...store, expiryMs };\n\n switch (store.persistTo) {\n case \"localStorage\":\n return localStoreAdapter<T>(config);\n\n case \"indexedDb\":\n return kvStoreAdapter<T>(config);\n\n default:\n store.persistTo satisfies never;\n throw new Error(`Unknown store.adapter ${store.persistTo}`);\n }\n }\n\n return store as StorageAdapter<T>;\n}\n\n/**\n * Create a new SSR-safe local store adapter, which allows users to reuse the\n * same adapter in multiple shared states or shared queries.\n */\nexport function localStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n // Put everything in the same store so that we can GC properly.\n const STORE_NAME = \"react-utils\";\n\n const adapter = createLocalStore(STORE_NAME, {\n defaultExpiryMs: expiryMs,\n });\n\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = key + \":\";\n\n return {\n set: (key: string, value: T): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n adapter.set(keyPrefix + key, value);\n },\n\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = adapter.get<T>(fullKey);\n\n // If there is no value, don't try to check for validatity.\n if (value !== undefined && isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${fullKey}: ${JSON.stringify(value)}`,\n );\n adapter.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n\n delete: (key: string): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.delete(keyPrefix + key);\n },\n\n /** Note that this will clear all keys in all shared states. */\n clear: (): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.clear();\n },\n };\n}\n\n/**\n * Create a new SSR-safe indexed DB KV store adapter, which allows users to\n * reuse the same adapter in multiple shared states or shared queries.\n */\nexport function kvStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = key + \":\";\n\n // Prefix all keys using `keyPrefix` so that we can keep all data in\n // the same store in the same DB. If we keep the data in different\n // DB stores, then GC will not be able to clean up abandoned stores.\n return {\n set: async (key: string, value: T): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n await kvStore.set(keyPrefix + key, value, expiryMs);\n },\n get: async (key: string): Promise<T | undefined> => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = await kvStore.get<T>(fullKey);\n\n // If there is no value, don't try to check for validatity.\n if (value !== undefined && isValid && !isValid(value)) {\n console.warn(\n `indexedDb adapter: Auto-discard invalid value for ${key}:`,\n value,\n );\n await kvStore.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n delete: async (key: string): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.delete(keyPrefix + key);\n },\n clear: async (): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.clear();\n },\n };\n}\n"],"mappings":"AAYA,OAAS,WAAAA,MAAe,8BACxB,OAAS,oBAAAC,MAAwB,iCAkCjC,IAAMC,EAAiB,OAAO,OAAW,IAMlC,SAASC,EACdC,EACAC,EAC0B,CAC1B,GAAM,CAAE,MAAAC,CAAM,EAAIF,GAAW,CAAC,EAE9B,GAAI,CAACE,EACH,OAAO,KAGT,GACE,cAAeA,GACf,OAAOA,EAAM,WAAc,UAC3B,QAASA,GACT,OAAOA,EAAM,KAAQ,SACrB,CACA,IAAMC,EAAWD,EAAM,UAAYD,EAC7BG,EAAS,CAAE,GAAGF,EAAO,SAAAC,CAAS,EAEpC,OAAQD,EAAM,UAAW,CACvB,IAAK,eACH,OAAOG,EAAqBD,CAAM,EAEpC,IAAK,YACH,OAAOE,EAAkBF,CAAM,EAEjC,QACE,MAAAF,EAAM,UACA,IAAI,MAAM,yBAAyBA,EAAM,SAAS,EAAE,CAC9D,CACF,CAEA,OAAOA,CACT,CAMO,SAASG,EAAqB,CACnC,IAAAE,EACA,SAAAJ,EACA,QAAAK,CACF,EAAyB,CAIvB,IAAMC,EAAUZ,EAFG,cAE0B,CAC3C,gBAAiBM,CACnB,CAAC,EAGKO,EAAYH,EAAM,IAExB,MAAO,CACL,IAAK,CAACA,EAAaI,IAAmB,CAChCb,GAGJW,EAAQ,IAAIC,EAAYH,EAAKI,CAAK,CACpC,EAEA,IAAMJ,GAA+B,CACnC,GAAIT,EAAgB,OAEpB,IAAMc,EAAUF,EAAYH,EACtBI,EAAQF,EAAQ,IAAOG,CAAO,EAGpC,GAAID,IAAU,QAAaH,GAAW,CAACA,EAAQG,CAAK,EAAG,CACrD,QAAQ,KACN,wDAAwDC,CAAO,KAAK,KAAK,UAAUD,CAAK,CAAC,EAC3F,EACAF,EAAQ,OAAOG,CAAO,EACtB,MACF,CAEA,OAAOD,CACT,EAEA,OAASJ,GAAsB,CACzBT,GAEJW,EAAQ,OAAOC,EAAYH,CAAG,CAChC,EAGA,MAAO,IAAY,CACbT,GAEJW,EAAQ,MAAM,CAChB,CACF,CACF,CAMO,SAASH,EAAkB,CAChC,IAAAC,EACA,SAAAJ,EACA,QAAAK,CACF,EAAyB,CAEvB,IAAME,EAAYH,EAAM,IAKxB,MAAO,CACL,IAAK,MAAOA,EAAaI,IAA4B,CAC/Cb,GAGJ,MAAMF,EAAQ,IAAIc,EAAYH,EAAKI,EAAOR,CAAQ,CACpD,EACA,IAAK,MAAOI,GAAwC,CAClD,GAAIT,EAAgB,OAEpB,IAAMc,EAAUF,EAAYH,EACtBI,EAAQ,MAAMf,EAAQ,IAAOgB,CAAO,EAG1C,GAAID,IAAU,QAAaH,GAAW,CAACA,EAAQG,CAAK,EAAG,CACrD,QAAQ,KACN,qDAAqDJ,CAAG,IACxDI,CACF,EACA,MAAMf,EAAQ,OAAOgB,CAAO,EAC5B,MACF,CAEA,OAAOD,CACT,EACA,OAAQ,MAAOJ,GAA+B,CACxCT,GAEJ,MAAMF,EAAQ,OAAOc,EAAYH,CAAG,CACtC,EACA,MAAO,SAA2B,CAC5BT,GAEJ,MAAMF,EAAQ,MAAM,CACtB,CACF,CACF","names":["kvStore","createLocalStore","IS_NOT_BROWSER","getStorageAdapter","options","defaultStoreExpiryMs","store","expiryMs","config","localStoreAdapter","kvStoreAdapter","key","isValid","adapter","keyPrefix","value","fullKey"]}
@@ -1,17 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/useDeepMemo.ts
2
- var _lodashes = require('lodash-es');
3
- var _react = require('react');
4
- function useDeepMemo(value) {
5
- const [state, setState] = _react.useState.call(void 0, value);
6
- return _react.useMemo.call(void 0, () => {
7
- if (_lodashes.isEqual.call(void 0, state, value)) {
8
- return state;
9
- }
10
- setState(value);
11
- return value;
12
- }, [state, value]);
13
- }
14
-
15
-
16
-
17
- exports.useDeepMemo = useDeepMemo;