@choksheak/react-utils 0.2.8 → 0.3.0
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 +50 -2
- package/sharedQuery.cjs +119 -130
- package/sharedQuery.d.mts +14 -8
- package/sharedQuery.d.ts +12 -6
- package/sharedQuery.min.cjs +1 -1
- package/sharedQuery.min.cjs.map +1 -1
- package/sharedQuery.min.mjs +1 -1
- package/sharedQuery.min.mjs.map +1 -1
- package/sharedQuery.mjs +117 -129
- package/sharedState.cjs +69 -101
- package/sharedState.d.mts +7 -3
- package/sharedState.d.ts +5 -2
- package/sharedState.min.cjs +1 -1
- package/sharedState.min.cjs.map +1 -1
- package/sharedState.min.mjs +1 -1
- package/sharedState.min.mjs.map +1 -1
- package/sharedState.mjs +67 -100
- package/storage.cjs +90 -0
- package/storage.d.mts +19 -0
- package/storage.d.ts +16 -0
- package/storage.min.cjs +2 -0
- package/storage.min.cjs.map +1 -0
- package/storage.min.mjs +2 -0
- package/storage.min.mjs.map +1 -0
- package/storage.mjs +65 -0
- package/{utils/stringify.cjs → stringify.cjs} +1 -1
- package/stringify.min.cjs.map +1 -0
- package/stringify.min.mjs.map +1 -0
- package/{utils/stringify.mjs → stringify.mjs} +1 -1
- package/{utils/useDeepMemo.cjs → useDeepMemo.cjs} +1 -1
- package/useDeepMemo.d.mts +7 -0
- package/useDeepMemo.d.ts +5 -0
- package/useDeepMemo.min.cjs.map +1 -0
- package/useDeepMemo.min.mjs.map +1 -0
- package/{utils/useDeepMemo.mjs → useDeepMemo.mjs} +1 -1
- package/utils/storage.cjs +0 -162
- package/utils/storage.d.mts +0 -46
- package/utils/storage.d.ts +0 -44
- package/utils/storage.min.cjs +0 -2
- package/utils/storage.min.cjs.map +0 -1
- package/utils/storage.min.mjs +0 -2
- package/utils/storage.min.mjs.map +0 -1
- package/utils/storage.mjs +0 -134
- package/utils/stringify.min.cjs.map +0 -1
- package/utils/stringify.min.mjs.map +0 -1
- package/utils/useDeepMemo.d.mts +0 -4
- package/utils/useDeepMemo.d.ts +0 -2
- package/utils/useDeepMemo.min.cjs.map +0 -1
- package/utils/useDeepMemo.min.mjs.map +0 -1
- /package/{utils/stringify.d.mts → stringify.d.mts} +0 -0
- /package/{utils/stringify.d.ts → stringify.d.ts} +0 -0
- /package/{utils/stringify.min.cjs → stringify.min.cjs} +0 -0
- /package/{utils/stringify.min.mjs → stringify.min.mjs} +0 -0
- /package/{utils/useDeepMemo.min.cjs → useDeepMemo.min.cjs} +0 -0
- /package/{utils/useDeepMemo.min.mjs → useDeepMemo.min.mjs} +0 -0
package/sharedQuery.mjs
CHANGED
|
@@ -13,108 +13,71 @@ import {
|
|
|
13
13
|
import { MS_PER_DAY } from "@choksheak/ts-utils/timeConstants";
|
|
14
14
|
import { useSyncExternalStore } from "react";
|
|
15
15
|
|
|
16
|
-
// src/
|
|
16
|
+
// src/storage.ts
|
|
17
17
|
import { kvStore } from "@choksheak/ts-utils/kvStore";
|
|
18
|
+
import { LocalStore } from "@choksheak/ts-utils/localStore";
|
|
18
19
|
function getStorageAdapter(options, defaultStoreExpiryMs) {
|
|
19
|
-
const {
|
|
20
|
-
if (store) {
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
load(key) {
|
|
49
|
-
if (typeof window === "undefined") return void 0;
|
|
50
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
51
|
-
const raw = window.localStorage.getItem(fullKey);
|
|
52
|
-
if (!raw) return void 0;
|
|
53
|
-
try {
|
|
54
|
-
const box = JSON.parse(raw);
|
|
55
|
-
if (!box || box.expiresAt && Date.now() >= box.expiresAt) {
|
|
56
|
-
window.localStorage.removeItem(fullKey);
|
|
57
|
-
return void 0;
|
|
20
|
+
const { store } = options ?? {};
|
|
21
|
+
if (!store) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if ("persistTo" in store && typeof store.persistTo === "string" && "key" in store && typeof store.key === "string") {
|
|
25
|
+
const expiryMs = store.expiryMs || defaultStoreExpiryMs;
|
|
26
|
+
switch (store.persistTo) {
|
|
27
|
+
case "localStorage": {
|
|
28
|
+
const adapter = new LocalStore(store.key, {
|
|
29
|
+
defaultExpiryMs: expiryMs
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
set: (key, value) => {
|
|
33
|
+
if (typeof window === "undefined") return;
|
|
34
|
+
adapter.set(key, value);
|
|
35
|
+
},
|
|
36
|
+
get: (key) => {
|
|
37
|
+
if (typeof window === "undefined") return void 0;
|
|
38
|
+
return adapter.get(key);
|
|
39
|
+
},
|
|
40
|
+
delete: (key) => {
|
|
41
|
+
if (typeof window === "undefined") return;
|
|
42
|
+
adapter.delete(key);
|
|
43
|
+
},
|
|
44
|
+
clear: () => {
|
|
45
|
+
if (typeof window === "undefined") return;
|
|
46
|
+
adapter.clear();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
58
49
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
case "indexedDb": {
|
|
51
|
+
const keyPrefix = store.key + ":";
|
|
52
|
+
return {
|
|
53
|
+
set: async (key, value) => {
|
|
54
|
+
if (typeof window === "undefined") return;
|
|
55
|
+
await kvStore.set(keyPrefix + key, value, expiryMs);
|
|
56
|
+
},
|
|
57
|
+
get: async (key) => {
|
|
58
|
+
if (typeof window === "undefined") return void 0;
|
|
59
|
+
return await kvStore.get(keyPrefix + key);
|
|
60
|
+
},
|
|
61
|
+
delete: async (key) => {
|
|
62
|
+
if (typeof window === "undefined") return;
|
|
63
|
+
await kvStore.delete(keyPrefix + key);
|
|
64
|
+
},
|
|
65
|
+
clear: async () => {
|
|
66
|
+
if (typeof window === "undefined") return;
|
|
67
|
+
await kvStore.clear();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
75
70
|
}
|
|
71
|
+
default:
|
|
72
|
+
store.persistTo;
|
|
73
|
+
throw new Error(`Unknown store.adapter ${store.persistTo}`);
|
|
76
74
|
}
|
|
77
75
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
constructor(keyPrefix, expiryMs) {
|
|
81
|
-
this.keyPrefix = keyPrefix;
|
|
82
|
-
this.expiryMs = expiryMs;
|
|
83
|
-
}
|
|
84
|
-
async save(key, value) {
|
|
85
|
-
if (typeof window === "undefined") return;
|
|
86
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
87
|
-
await kvStore.set(fullKey, JSON.stringify(value), this.expiryMs);
|
|
88
|
-
}
|
|
89
|
-
async load(key) {
|
|
90
|
-
if (typeof window === "undefined") return void 0;
|
|
91
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
92
|
-
const raw = await kvStore.get(fullKey);
|
|
93
|
-
if (raw === void 0) return void 0;
|
|
94
|
-
try {
|
|
95
|
-
return JSON.parse(raw);
|
|
96
|
-
} catch {
|
|
97
|
-
await kvStore.delete(fullKey);
|
|
98
|
-
return void 0;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
async delete(key) {
|
|
102
|
-
if (typeof window === "undefined") return;
|
|
103
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
104
|
-
await kvStore.delete(fullKey);
|
|
105
|
-
}
|
|
106
|
-
async clear() {
|
|
107
|
-
if (typeof window === "undefined") return;
|
|
108
|
-
await kvStore.forEach(async (k) => {
|
|
109
|
-
if (k.startsWith(this.keyPrefix)) {
|
|
110
|
-
await kvStore.delete(k);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
};
|
|
76
|
+
return store;
|
|
77
|
+
}
|
|
115
78
|
|
|
116
79
|
// src/sharedState.ts
|
|
117
|
-
var
|
|
80
|
+
var SharedStateConfig = {
|
|
118
81
|
/**
|
|
119
82
|
* Default duration for storage expiration in milliseconds. Initial value
|
|
120
83
|
* is 30 days, but can be changed to anything.
|
|
@@ -181,14 +144,14 @@ var SharedState = class {
|
|
|
181
144
|
this.pubSubKey = String(stateKey++);
|
|
182
145
|
this.storageAdapter = getStorageAdapter(
|
|
183
146
|
options,
|
|
184
|
-
|
|
147
|
+
SharedStateConfig.storeExpiryMs
|
|
185
148
|
);
|
|
186
149
|
this.setValueBounded = (next) => {
|
|
187
150
|
this.setValue(next);
|
|
188
151
|
};
|
|
189
152
|
pubSubStore.setNoNotify(this.pubSubKey, defaultValue);
|
|
190
153
|
const lazyLoad = options?.lazyLoad;
|
|
191
|
-
const lazy = lazyLoad !== void 0 ? lazyLoad :
|
|
154
|
+
const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateConfig.lazyLoad;
|
|
192
155
|
if (!lazy) {
|
|
193
156
|
void this.initDefaultValueOnce();
|
|
194
157
|
}
|
|
@@ -213,19 +176,19 @@ var SharedState = class {
|
|
|
213
176
|
next = next(prev);
|
|
214
177
|
}
|
|
215
178
|
pubSubStore.set(this.pubSubKey, next);
|
|
216
|
-
void this.storageAdapter?.
|
|
179
|
+
void this.storageAdapter?.set(STORAGE_KEY, next);
|
|
217
180
|
}
|
|
218
181
|
// Remove the value of the shared state. Actually this just sets the value
|
|
219
182
|
// back to the given default value.
|
|
220
183
|
delete() {
|
|
221
184
|
pubSubStore.set(this.pubSubKey, this.defaultValue);
|
|
222
|
-
void this.storageAdapter?.
|
|
185
|
+
void this.storageAdapter?.set(STORAGE_KEY, this.defaultValue);
|
|
223
186
|
}
|
|
224
187
|
// Initial default handling
|
|
225
188
|
async initDefaultValueOnce() {
|
|
226
189
|
if (this.initDone) return;
|
|
227
190
|
this.initDone = true;
|
|
228
|
-
const v = await this.storageAdapter?.
|
|
191
|
+
const v = await this.storageAdapter?.get(STORAGE_KEY);
|
|
229
192
|
pubSubStore.set(this.pubSubKey, v !== void 0 ? v : this.defaultValue);
|
|
230
193
|
}
|
|
231
194
|
};
|
|
@@ -243,7 +206,7 @@ function useSharedState(state) {
|
|
|
243
206
|
return [value, state.setValueBounded];
|
|
244
207
|
}
|
|
245
208
|
|
|
246
|
-
// src/
|
|
209
|
+
// src/stringify.ts
|
|
247
210
|
function stringifyDeterministicForKeys(params) {
|
|
248
211
|
const cache = /* @__PURE__ */ new Set();
|
|
249
212
|
return JSON.stringify(params, (_, value) => {
|
|
@@ -274,7 +237,7 @@ function stringifyDeterministicForKeys(params) {
|
|
|
274
237
|
});
|
|
275
238
|
}
|
|
276
239
|
|
|
277
|
-
// src/
|
|
240
|
+
// src/useDeepMemo.ts
|
|
278
241
|
import isEqual from "lodash/isEqual";
|
|
279
242
|
import { useMemo, useState } from "react";
|
|
280
243
|
function useDeepMemo(value) {
|
|
@@ -289,7 +252,7 @@ function useDeepMemo(value) {
|
|
|
289
252
|
}
|
|
290
253
|
|
|
291
254
|
// src/sharedQuery.ts
|
|
292
|
-
var
|
|
255
|
+
var SharedQueryConfig = {
|
|
293
256
|
/** Refetch on every page load. */
|
|
294
257
|
staleMs: 0,
|
|
295
258
|
/** Keep in cache for a long time. */
|
|
@@ -305,6 +268,9 @@ var SharedQueryDefaults = {
|
|
|
305
268
|
/** Default to log to console. */
|
|
306
269
|
log: (...args) => console.log("[sharedQuery]", ...args)
|
|
307
270
|
};
|
|
271
|
+
function configureSharedQuery(config) {
|
|
272
|
+
Object.assign(SharedQueryConfig, config);
|
|
273
|
+
}
|
|
308
274
|
var SharedQuery = class {
|
|
309
275
|
inflightQueries = /* @__PURE__ */ new Map();
|
|
310
276
|
queryState;
|
|
@@ -326,29 +292,27 @@ var SharedQuery = class {
|
|
|
326
292
|
constructor(options) {
|
|
327
293
|
this.queryName = options.queryName;
|
|
328
294
|
this.queryFn = options.queryFn;
|
|
329
|
-
this.staleMs = options?.staleMs ??
|
|
330
|
-
this.expiryMs = options?.expiryMs ??
|
|
331
|
-
this.refetchOnStale = options?.refetchOnStale ??
|
|
332
|
-
if (!options.
|
|
333
|
-
const persistTo = options.persistTo ??
|
|
334
|
-
if (persistTo
|
|
335
|
-
options.
|
|
336
|
-
|
|
337
|
-
|
|
295
|
+
this.staleMs = options?.staleMs ?? SharedQueryConfig.staleMs;
|
|
296
|
+
this.expiryMs = options?.expiryMs ?? SharedQueryConfig.expiryMs;
|
|
297
|
+
this.refetchOnStale = options?.refetchOnStale ?? SharedQueryConfig.refetchOnStale;
|
|
298
|
+
if (!options.store) {
|
|
299
|
+
const persistTo = options.persistTo ?? SharedQueryConfig.persistTo;
|
|
300
|
+
if (persistTo) {
|
|
301
|
+
options.store = {
|
|
302
|
+
persistTo,
|
|
303
|
+
key: options.queryName,
|
|
304
|
+
expiryMs: this.expiryMs
|
|
305
|
+
};
|
|
338
306
|
}
|
|
339
307
|
}
|
|
340
|
-
this.maxSize = options?.maxSize ??
|
|
341
|
-
this.maxBytes = options?.maxBytes ??
|
|
308
|
+
this.maxSize = options?.maxSize ?? SharedQueryConfig.maxSize;
|
|
309
|
+
this.maxBytes = options?.maxBytes ?? SharedQueryConfig.maxBytes;
|
|
342
310
|
this.keepLastNonEmptyData = Boolean(options?.keepLastNonEmptyData);
|
|
343
|
-
this.log = options?.log ??
|
|
311
|
+
this.log = options?.log ?? SharedQueryConfig.log;
|
|
344
312
|
this.queryState = sharedState(
|
|
345
313
|
{},
|
|
346
314
|
// defaultValue
|
|
347
|
-
|
|
348
|
-
...options,
|
|
349
|
-
// Fallback to use expiryMs for the storeExpiryMs.
|
|
350
|
-
storeExpiryMs: options?.storeExpiryMs || this.expiryMs
|
|
351
|
-
}
|
|
315
|
+
options
|
|
352
316
|
);
|
|
353
317
|
}
|
|
354
318
|
/** Returns a key to identify requests based on the given args. */
|
|
@@ -459,7 +423,14 @@ var SharedQuery = class {
|
|
|
459
423
|
}
|
|
460
424
|
/** Get the current stored data for a query key. */
|
|
461
425
|
getData(queryKey) {
|
|
462
|
-
|
|
426
|
+
const stateValue = this.queryState.getSnapshot()?.[queryKey];
|
|
427
|
+
if (stateValue?.lastUpdatedMs) {
|
|
428
|
+
if (this.isExpired(stateValue.lastUpdatedMs)) {
|
|
429
|
+
this.deleteData(queryKey);
|
|
430
|
+
return void 0;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return stateValue?.data;
|
|
463
434
|
}
|
|
464
435
|
/** Set the data directly if the user obtained it from somewhere else. */
|
|
465
436
|
setData(queryKey, data, dataUpdatedMs = Date.now()) {
|
|
@@ -542,25 +513,41 @@ var SharedQuery = class {
|
|
|
542
513
|
);
|
|
543
514
|
const newState = { ...oldState };
|
|
544
515
|
let needUpdate = false;
|
|
545
|
-
const
|
|
546
|
-
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
547
|
-
);
|
|
548
|
-
for (const [key] of entriesByTimeAscending) {
|
|
516
|
+
const deleteKeyIfNotMounted = (key, expired) => {
|
|
549
517
|
if (this.mountedKeys.has(key)) {
|
|
550
518
|
this.log(`Cannot clean up ${key} as it is mounted`);
|
|
551
|
-
|
|
519
|
+
return;
|
|
552
520
|
}
|
|
553
521
|
const byteSize = getByteSize(key) + getByteSize(newState[key]);
|
|
554
522
|
this.log(
|
|
555
|
-
`Cleaning up unmounted ${key} (byteSize=${byteSize.toLocaleString()})`
|
|
523
|
+
`Cleaning up unmounted${expired ? ", expired" : ""} ${key} (byteSize=${byteSize.toLocaleString()})`
|
|
556
524
|
);
|
|
557
525
|
numToCut--;
|
|
558
526
|
bytesToCut -= byteSize;
|
|
559
527
|
delete newState[key];
|
|
560
528
|
needUpdate = true;
|
|
561
|
-
|
|
529
|
+
};
|
|
530
|
+
let entriesByTimeAscending = Object.entries(newState).sort(
|
|
531
|
+
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
532
|
+
);
|
|
533
|
+
for (const [key] of entriesByTimeAscending) {
|
|
534
|
+
if (!this.isExpired(newState[key].lastUpdatedMs)) {
|
|
562
535
|
break;
|
|
563
536
|
}
|
|
537
|
+
deleteKeyIfNotMounted(key, true);
|
|
538
|
+
}
|
|
539
|
+
if (numToCut > 0 || bytesToCut > 0) {
|
|
540
|
+
if (needUpdate) {
|
|
541
|
+
entriesByTimeAscending = Object.entries(newState).sort(
|
|
542
|
+
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
for (const [key] of entriesByTimeAscending) {
|
|
546
|
+
deleteKeyIfNotMounted(key, false);
|
|
547
|
+
if (numToCut <= 0 && bytesToCut <= 0) {
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
564
551
|
}
|
|
565
552
|
if (!needUpdate) {
|
|
566
553
|
this.log(
|
|
@@ -586,7 +573,7 @@ var DEFAULT_QUERY_STATE_ENTRY = {
|
|
|
586
573
|
lastUpdatedMs: 0,
|
|
587
574
|
loading: true
|
|
588
575
|
};
|
|
589
|
-
function useSharedQuery(query, args
|
|
576
|
+
function useSharedQuery(query, ...args) {
|
|
590
577
|
const stableArgs = useDeepMemo(args);
|
|
591
578
|
const [queryState, setQueryState] = useSharedState(query.queryState);
|
|
592
579
|
const isMounted = useRef(true);
|
|
@@ -702,7 +689,8 @@ function useSharedQuery(query, args = []) {
|
|
|
702
689
|
}
|
|
703
690
|
export {
|
|
704
691
|
SharedQuery,
|
|
705
|
-
|
|
692
|
+
SharedQueryConfig,
|
|
693
|
+
configureSharedQuery,
|
|
706
694
|
sharedQuery,
|
|
707
695
|
useSharedQuery
|
|
708
696
|
};
|
package/sharedState.cjs
CHANGED
|
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var sharedState_exports = {};
|
|
22
22
|
__export(sharedState_exports, {
|
|
23
23
|
SharedState: () => SharedState,
|
|
24
|
-
|
|
24
|
+
SharedStateConfig: () => SharedStateConfig,
|
|
25
|
+
configureSharedState: () => configureSharedState,
|
|
25
26
|
sharedState: () => sharedState,
|
|
26
27
|
useSharedState: () => useSharedState,
|
|
27
28
|
useSharedStateSetter: () => useSharedStateSetter,
|
|
@@ -31,108 +32,71 @@ module.exports = __toCommonJS(sharedState_exports);
|
|
|
31
32
|
var import_timeConstants = require("@choksheak/ts-utils/timeConstants");
|
|
32
33
|
var import_react = require("react");
|
|
33
34
|
|
|
34
|
-
// src/
|
|
35
|
+
// src/storage.ts
|
|
35
36
|
var import_kvStore = require("@choksheak/ts-utils/kvStore");
|
|
37
|
+
var import_localStore = require("@choksheak/ts-utils/localStore");
|
|
36
38
|
function getStorageAdapter(options, defaultStoreExpiryMs) {
|
|
37
|
-
const {
|
|
38
|
-
if (store) {
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
load(key) {
|
|
67
|
-
if (typeof window === "undefined") return void 0;
|
|
68
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
69
|
-
const raw = window.localStorage.getItem(fullKey);
|
|
70
|
-
if (!raw) return void 0;
|
|
71
|
-
try {
|
|
72
|
-
const box = JSON.parse(raw);
|
|
73
|
-
if (!box || box.expiresAt && Date.now() >= box.expiresAt) {
|
|
74
|
-
window.localStorage.removeItem(fullKey);
|
|
75
|
-
return void 0;
|
|
39
|
+
const { store } = options ?? {};
|
|
40
|
+
if (!store) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if ("persistTo" in store && typeof store.persistTo === "string" && "key" in store && typeof store.key === "string") {
|
|
44
|
+
const expiryMs = store.expiryMs || defaultStoreExpiryMs;
|
|
45
|
+
switch (store.persistTo) {
|
|
46
|
+
case "localStorage": {
|
|
47
|
+
const adapter = new import_localStore.LocalStore(store.key, {
|
|
48
|
+
defaultExpiryMs: expiryMs
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
set: (key, value) => {
|
|
52
|
+
if (typeof window === "undefined") return;
|
|
53
|
+
adapter.set(key, value);
|
|
54
|
+
},
|
|
55
|
+
get: (key) => {
|
|
56
|
+
if (typeof window === "undefined") return void 0;
|
|
57
|
+
return adapter.get(key);
|
|
58
|
+
},
|
|
59
|
+
delete: (key) => {
|
|
60
|
+
if (typeof window === "undefined") return;
|
|
61
|
+
adapter.delete(key);
|
|
62
|
+
},
|
|
63
|
+
clear: () => {
|
|
64
|
+
if (typeof window === "undefined") return;
|
|
65
|
+
adapter.clear();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
76
68
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
69
|
+
case "indexedDb": {
|
|
70
|
+
const keyPrefix = store.key + ":";
|
|
71
|
+
return {
|
|
72
|
+
set: async (key, value) => {
|
|
73
|
+
if (typeof window === "undefined") return;
|
|
74
|
+
await import_kvStore.kvStore.set(keyPrefix + key, value, expiryMs);
|
|
75
|
+
},
|
|
76
|
+
get: async (key) => {
|
|
77
|
+
if (typeof window === "undefined") return void 0;
|
|
78
|
+
return await import_kvStore.kvStore.get(keyPrefix + key);
|
|
79
|
+
},
|
|
80
|
+
delete: async (key) => {
|
|
81
|
+
if (typeof window === "undefined") return;
|
|
82
|
+
await import_kvStore.kvStore.delete(keyPrefix + key);
|
|
83
|
+
},
|
|
84
|
+
clear: async () => {
|
|
85
|
+
if (typeof window === "undefined") return;
|
|
86
|
+
await import_kvStore.kvStore.clear();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
93
89
|
}
|
|
90
|
+
default:
|
|
91
|
+
store.persistTo;
|
|
92
|
+
throw new Error(`Unknown store.adapter ${store.persistTo}`);
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
constructor(keyPrefix, expiryMs) {
|
|
99
|
-
this.keyPrefix = keyPrefix;
|
|
100
|
-
this.expiryMs = expiryMs;
|
|
101
|
-
}
|
|
102
|
-
async save(key, value) {
|
|
103
|
-
if (typeof window === "undefined") return;
|
|
104
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
105
|
-
await import_kvStore.kvStore.set(fullKey, JSON.stringify(value), this.expiryMs);
|
|
106
|
-
}
|
|
107
|
-
async load(key) {
|
|
108
|
-
if (typeof window === "undefined") return void 0;
|
|
109
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
110
|
-
const raw = await import_kvStore.kvStore.get(fullKey);
|
|
111
|
-
if (raw === void 0) return void 0;
|
|
112
|
-
try {
|
|
113
|
-
return JSON.parse(raw);
|
|
114
|
-
} catch {
|
|
115
|
-
await import_kvStore.kvStore.delete(fullKey);
|
|
116
|
-
return void 0;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
async delete(key) {
|
|
120
|
-
if (typeof window === "undefined") return;
|
|
121
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
122
|
-
await import_kvStore.kvStore.delete(fullKey);
|
|
123
|
-
}
|
|
124
|
-
async clear() {
|
|
125
|
-
if (typeof window === "undefined") return;
|
|
126
|
-
await import_kvStore.kvStore.forEach(async (k) => {
|
|
127
|
-
if (k.startsWith(this.keyPrefix)) {
|
|
128
|
-
await import_kvStore.kvStore.delete(k);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
};
|
|
95
|
+
return store;
|
|
96
|
+
}
|
|
133
97
|
|
|
134
98
|
// src/sharedState.ts
|
|
135
|
-
var
|
|
99
|
+
var SharedStateConfig = {
|
|
136
100
|
/**
|
|
137
101
|
* Default duration for storage expiration in milliseconds. Initial value
|
|
138
102
|
* is 30 days, but can be changed to anything.
|
|
@@ -144,6 +108,9 @@ var SharedStateDefaults = {
|
|
|
144
108
|
*/
|
|
145
109
|
lazyLoad: false
|
|
146
110
|
};
|
|
111
|
+
function configureSharedState(config) {
|
|
112
|
+
Object.assign(SharedStateConfig, config);
|
|
113
|
+
}
|
|
147
114
|
var PubSubStore = class {
|
|
148
115
|
dataByKey = /* @__PURE__ */ new Map();
|
|
149
116
|
subscribersByKey = /* @__PURE__ */ new Map();
|
|
@@ -199,14 +166,14 @@ var SharedState = class {
|
|
|
199
166
|
this.pubSubKey = String(stateKey++);
|
|
200
167
|
this.storageAdapter = getStorageAdapter(
|
|
201
168
|
options,
|
|
202
|
-
|
|
169
|
+
SharedStateConfig.storeExpiryMs
|
|
203
170
|
);
|
|
204
171
|
this.setValueBounded = (next) => {
|
|
205
172
|
this.setValue(next);
|
|
206
173
|
};
|
|
207
174
|
pubSubStore.setNoNotify(this.pubSubKey, defaultValue);
|
|
208
175
|
const lazyLoad = options?.lazyLoad;
|
|
209
|
-
const lazy = lazyLoad !== void 0 ? lazyLoad :
|
|
176
|
+
const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateConfig.lazyLoad;
|
|
210
177
|
if (!lazy) {
|
|
211
178
|
void this.initDefaultValueOnce();
|
|
212
179
|
}
|
|
@@ -231,19 +198,19 @@ var SharedState = class {
|
|
|
231
198
|
next = next(prev);
|
|
232
199
|
}
|
|
233
200
|
pubSubStore.set(this.pubSubKey, next);
|
|
234
|
-
void this.storageAdapter?.
|
|
201
|
+
void this.storageAdapter?.set(STORAGE_KEY, next);
|
|
235
202
|
}
|
|
236
203
|
// Remove the value of the shared state. Actually this just sets the value
|
|
237
204
|
// back to the given default value.
|
|
238
205
|
delete() {
|
|
239
206
|
pubSubStore.set(this.pubSubKey, this.defaultValue);
|
|
240
|
-
void this.storageAdapter?.
|
|
207
|
+
void this.storageAdapter?.set(STORAGE_KEY, this.defaultValue);
|
|
241
208
|
}
|
|
242
209
|
// Initial default handling
|
|
243
210
|
async initDefaultValueOnce() {
|
|
244
211
|
if (this.initDone) return;
|
|
245
212
|
this.initDone = true;
|
|
246
|
-
const v = await this.storageAdapter?.
|
|
213
|
+
const v = await this.storageAdapter?.get(STORAGE_KEY);
|
|
247
214
|
pubSubStore.set(this.pubSubKey, v !== void 0 ? v : this.defaultValue);
|
|
248
215
|
}
|
|
249
216
|
};
|
|
@@ -269,7 +236,8 @@ function useSharedStateSetter(state) {
|
|
|
269
236
|
// Annotate the CommonJS export names for ESM import in node:
|
|
270
237
|
0 && (module.exports = {
|
|
271
238
|
SharedState,
|
|
272
|
-
|
|
239
|
+
SharedStateConfig,
|
|
240
|
+
configureSharedState,
|
|
273
241
|
sharedState,
|
|
274
242
|
useSharedState,
|
|
275
243
|
useSharedStateSetter,
|
package/sharedState.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Dispatch, SetStateAction } from 'react';
|
|
2
|
-
import { StorageOptions } from './
|
|
2
|
+
import { StorageOptions } from './storage.mjs';
|
|
3
|
+
import '@choksheak/ts-utils/storageAdapter';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @packageDocumentation
|
|
@@ -48,7 +49,7 @@ import { StorageOptions } from './utils/storage.mjs';
|
|
|
48
49
|
/**
|
|
49
50
|
* These values are configurable by the user at any time.
|
|
50
51
|
*/
|
|
51
|
-
declare const
|
|
52
|
+
declare const SharedStateConfig: {
|
|
52
53
|
/**
|
|
53
54
|
* Default duration for storage expiration in milliseconds. Initial value
|
|
54
55
|
* is 30 days, but can be changed to anything.
|
|
@@ -60,6 +61,9 @@ declare const SharedStateDefaults: {
|
|
|
60
61
|
*/
|
|
61
62
|
lazyLoad: boolean;
|
|
62
63
|
};
|
|
64
|
+
type SharedStateConfig = typeof SharedStateConfig;
|
|
65
|
+
/** Convenience function to update global defaults. */
|
|
66
|
+
declare function configureSharedState(config: Partial<SharedStateConfig>): void;
|
|
63
67
|
/** Options to configure a shared state. */
|
|
64
68
|
type SharedStateOptions<T> = {
|
|
65
69
|
lazyLoad?: boolean;
|
|
@@ -115,4 +119,4 @@ declare function useSharedStateValue<T>(state: SharedState<T>): T;
|
|
|
115
119
|
*/
|
|
116
120
|
declare function useSharedStateSetter<T>(state: SharedState<T>): Dispatch<SetStateAction<T>>;
|
|
117
121
|
|
|
118
|
-
export { SharedState,
|
|
122
|
+
export { SharedState, SharedStateConfig, type SharedStateOptions, configureSharedState, sharedState, useSharedState, useSharedStateSetter, useSharedStateValue };
|
package/sharedState.d.ts
CHANGED
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
42
|
import { Dispatch, SetStateAction } from "react";
|
|
43
|
-
import { StorageOptions } from "./
|
|
43
|
+
import { StorageOptions } from "./storage";
|
|
44
44
|
/************************************************************************/
|
|
45
45
|
/************************************************************************/
|
|
46
46
|
/**
|
|
47
47
|
* These values are configurable by the user at any time.
|
|
48
48
|
*/
|
|
49
|
-
export declare const
|
|
49
|
+
export declare const SharedStateConfig: {
|
|
50
50
|
/**
|
|
51
51
|
* Default duration for storage expiration in milliseconds. Initial value
|
|
52
52
|
* is 30 days, but can be changed to anything.
|
|
@@ -58,6 +58,9 @@ export declare const SharedStateDefaults: {
|
|
|
58
58
|
*/
|
|
59
59
|
lazyLoad: boolean;
|
|
60
60
|
};
|
|
61
|
+
export type SharedStateConfig = typeof SharedStateConfig;
|
|
62
|
+
/** Convenience function to update global defaults. */
|
|
63
|
+
export declare function configureSharedState(config: Partial<SharedStateConfig>): void;
|
|
61
64
|
/** Options to configure a shared state. */
|
|
62
65
|
export type SharedStateOptions<T> = {
|
|
63
66
|
lazyLoad?: boolean;
|