@choksheak/react-utils 0.4.5 → 0.4.7
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/NoSSR.cjs +7 -33
- package/NoSSR.min.cjs +1 -1
- package/NoSSR.min.cjs.map +1 -1
- package/NoSSR.min.mjs +1 -1
- package/NoSSR.min.mjs.map +1 -1
- package/NoSSR.mjs +1 -2
- package/index.cjs +5 -979
- package/index.d.cts +1 -1
- package/index.d.ts +1 -1
- package/index.min.cjs +1 -1
- package/index.min.cjs.map +1 -1
- package/index.min.mjs +1 -1
- package/index.min.mjs.map +1 -1
- package/index.mjs +5 -934
- package/package.json +1 -1
- package/sharedQuery.cjs +59 -420
- 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 +12 -341
- package/sharedState.cjs +31 -154
- 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 +14 -107
- package/storage.cjs +15 -43
- package/storage.min.cjs +1 -1
- package/storage.min.cjs.map +1 -1
- package/storage.min.mjs +1 -1
- package/storage.min.mjs.map +1 -1
- package/storage.mjs +1 -2
- package/stringify.cjs +5 -31
- package/stringify.min.cjs +1 -1
- package/stringify.min.cjs.map +1 -1
- package/stringify.min.mjs +1 -1
- package/stringify.min.mjs.map +1 -1
- package/stringify.mjs +0 -1
- package/useDeepMemo.cjs +8 -34
- package/useDeepMemo.min.cjs +1 -1
- package/useDeepMemo.min.cjs.map +1 -1
- package/useDeepMemo.min.mjs +1 -1
- package/useDeepMemo.min.mjs.map +1 -1
- package/useDeepMemo.mjs +0 -1
package/sharedQuery.mjs
CHANGED
|
@@ -1,345 +1,18 @@
|
|
|
1
|
-
// src/sharedQuery.ts
|
|
2
1
|
import { http, retries } from "@choksheak/ts-utils/http";
|
|
3
2
|
import { nonNil } from "@choksheak/ts-utils/nonNil";
|
|
4
3
|
import getByteSize from "object-sizeof";
|
|
5
4
|
import {
|
|
6
5
|
useCallback,
|
|
7
6
|
useEffect,
|
|
8
|
-
useMemo
|
|
7
|
+
useMemo,
|
|
9
8
|
useRef,
|
|
10
|
-
useState
|
|
9
|
+
useState
|
|
11
10
|
} from "react";
|
|
12
11
|
import XXH from "xxhashjs";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// src/storage.ts
|
|
19
|
-
import { kvStore } from "@choksheak/ts-utils/kvStore";
|
|
20
|
-
import { createLocalStore } from "@choksheak/ts-utils/localStore";
|
|
21
|
-
var IS_NOT_BROWSER = typeof window === "undefined";
|
|
22
|
-
function getStorageAdapter(options, defaultStoreExpiryMs) {
|
|
23
|
-
const { store } = options ?? {};
|
|
24
|
-
if (!store) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
if ("persistTo" in store && typeof store.persistTo === "string" && "key" in store && typeof store.key === "string") {
|
|
28
|
-
const expiryMs = store.expiryMs || defaultStoreExpiryMs;
|
|
29
|
-
const config = { ...store, expiryMs };
|
|
30
|
-
switch (store.persistTo) {
|
|
31
|
-
case "localStorage":
|
|
32
|
-
return localStoreAdapter(config);
|
|
33
|
-
case "indexedDb":
|
|
34
|
-
return kvStoreAdapter(config);
|
|
35
|
-
default:
|
|
36
|
-
store.persistTo;
|
|
37
|
-
throw new Error(`Unknown store.adapter ${store.persistTo}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return store;
|
|
41
|
-
}
|
|
42
|
-
function localStoreAdapter({
|
|
43
|
-
key,
|
|
44
|
-
expiryMs,
|
|
45
|
-
isValid
|
|
46
|
-
}) {
|
|
47
|
-
const STORE_NAME = "react-utils";
|
|
48
|
-
const adapter = createLocalStore(STORE_NAME, {
|
|
49
|
-
defaultExpiryMs: expiryMs
|
|
50
|
-
});
|
|
51
|
-
const keyPrefix = key + ":";
|
|
52
|
-
return {
|
|
53
|
-
set: (key2, value) => {
|
|
54
|
-
if (IS_NOT_BROWSER) return;
|
|
55
|
-
adapter.set(keyPrefix + key2, value);
|
|
56
|
-
},
|
|
57
|
-
get: (key2) => {
|
|
58
|
-
if (IS_NOT_BROWSER) return void 0;
|
|
59
|
-
const fullKey = keyPrefix + key2;
|
|
60
|
-
const value = adapter.get(fullKey);
|
|
61
|
-
if (value !== void 0 && isValid && !isValid(value)) {
|
|
62
|
-
console.warn(
|
|
63
|
-
`localStorage adapter: Auto-discard invalid value for ${fullKey}: ${JSON.stringify(value)}`
|
|
64
|
-
);
|
|
65
|
-
adapter.delete(fullKey);
|
|
66
|
-
return void 0;
|
|
67
|
-
}
|
|
68
|
-
return value;
|
|
69
|
-
},
|
|
70
|
-
delete: (key2) => {
|
|
71
|
-
if (IS_NOT_BROWSER) return;
|
|
72
|
-
adapter.delete(keyPrefix + key2);
|
|
73
|
-
},
|
|
74
|
-
/** Note that this will clear all keys in all shared states. */
|
|
75
|
-
clear: () => {
|
|
76
|
-
if (IS_NOT_BROWSER) return;
|
|
77
|
-
adapter.clear();
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function kvStoreAdapter({
|
|
82
|
-
key,
|
|
83
|
-
expiryMs,
|
|
84
|
-
isValid
|
|
85
|
-
}) {
|
|
86
|
-
const keyPrefix = key + ":";
|
|
87
|
-
return {
|
|
88
|
-
set: async (key2, value) => {
|
|
89
|
-
if (IS_NOT_BROWSER) return;
|
|
90
|
-
await kvStore.set(keyPrefix + key2, value, expiryMs);
|
|
91
|
-
},
|
|
92
|
-
get: async (key2) => {
|
|
93
|
-
if (IS_NOT_BROWSER) return void 0;
|
|
94
|
-
const fullKey = keyPrefix + key2;
|
|
95
|
-
const value = await kvStore.get(fullKey);
|
|
96
|
-
if (value !== void 0 && isValid && !isValid(value)) {
|
|
97
|
-
console.warn(
|
|
98
|
-
`indexedDb adapter: Auto-discard invalid value for ${key2}:`,
|
|
99
|
-
value
|
|
100
|
-
);
|
|
101
|
-
await kvStore.delete(fullKey);
|
|
102
|
-
return void 0;
|
|
103
|
-
}
|
|
104
|
-
return value;
|
|
105
|
-
},
|
|
106
|
-
delete: async (key2) => {
|
|
107
|
-
if (IS_NOT_BROWSER) return;
|
|
108
|
-
await kvStore.delete(keyPrefix + key2);
|
|
109
|
-
},
|
|
110
|
-
clear: async () => {
|
|
111
|
-
if (IS_NOT_BROWSER) return;
|
|
112
|
-
await kvStore.clear();
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// src/sharedState.ts
|
|
118
|
-
var SharedStateConfig = {
|
|
119
|
-
/**
|
|
120
|
-
* Default duration for storage expiration in milliseconds. Initial value
|
|
121
|
-
* is 30 days, but can be changed to anything.
|
|
122
|
-
*/
|
|
123
|
-
storeExpiryMs: 30 * MS_PER_DAY,
|
|
124
|
-
/**
|
|
125
|
-
* True to load from storage only on mount, false (default) to load in
|
|
126
|
-
* the top level scope when the shared state is defined.
|
|
127
|
-
*/
|
|
128
|
-
lazyLoad: false
|
|
129
|
-
};
|
|
130
|
-
function createPubSubStore() {
|
|
131
|
-
const dataByKey = /* @__PURE__ */ new Map();
|
|
132
|
-
const subscribersByKey = /* @__PURE__ */ new Map();
|
|
133
|
-
function notify(key, next, prev) {
|
|
134
|
-
const subscribers = subscribersByKey.get(key);
|
|
135
|
-
if (!subscribers) return;
|
|
136
|
-
const copy = Array.from(subscribers.values());
|
|
137
|
-
for (const subscriber of copy) {
|
|
138
|
-
try {
|
|
139
|
-
subscriber(next, prev);
|
|
140
|
-
} catch (e) {
|
|
141
|
-
console.error(`Error invoking subscriber:`, e);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
// This could be undefined if T includes undefined, else it should never
|
|
147
|
-
// return undefined because the user has to always specify the default value.
|
|
148
|
-
get(key) {
|
|
149
|
-
return dataByKey.get(key);
|
|
150
|
-
},
|
|
151
|
-
set(key, value) {
|
|
152
|
-
const prev = dataByKey.get(key);
|
|
153
|
-
if (prev === value) return;
|
|
154
|
-
dataByKey.set(key, value);
|
|
155
|
-
notify(key, value, prev);
|
|
156
|
-
},
|
|
157
|
-
delete(key) {
|
|
158
|
-
dataByKey.delete(key);
|
|
159
|
-
},
|
|
160
|
-
setNoNotify(key, value) {
|
|
161
|
-
dataByKey.set(key, value);
|
|
162
|
-
},
|
|
163
|
-
// Subscribe to changes of a specific key
|
|
164
|
-
subscribe(key, subscriber) {
|
|
165
|
-
let subscribers = subscribersByKey.get(key);
|
|
166
|
-
if (!subscribers) {
|
|
167
|
-
subscribers = /* @__PURE__ */ new Set();
|
|
168
|
-
subscribersByKey.set(key, subscribers);
|
|
169
|
-
}
|
|
170
|
-
subscribers.add(subscriber);
|
|
171
|
-
return () => {
|
|
172
|
-
subscribers.delete(subscriber);
|
|
173
|
-
if (subscribers.size === 0) subscribersByKey.delete(key);
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
function getOrCreatePubSubStore() {
|
|
179
|
-
if (typeof window !== "undefined") {
|
|
180
|
-
const t = window.globalThis;
|
|
181
|
-
return t.reactUtilsPubSubStore || (t.reactUtilsPubSubStore = createPubSubStore());
|
|
182
|
-
}
|
|
183
|
-
return createPubSubStore();
|
|
184
|
-
}
|
|
185
|
-
var pubSubStore = getOrCreatePubSubStore();
|
|
186
|
-
var STORAGE_KEY = "state";
|
|
187
|
-
var stateKey = 0;
|
|
188
|
-
function sharedState(defaultValue, options) {
|
|
189
|
-
let readyResolve = () => {
|
|
190
|
-
};
|
|
191
|
-
const readyPromise = new Promise((resolve) => {
|
|
192
|
-
readyResolve = resolve;
|
|
193
|
-
});
|
|
194
|
-
const resolveReadyPromise = readyResolve;
|
|
195
|
-
const pubSubKey = String(stateKey++);
|
|
196
|
-
const storageAdapter = getStorageAdapter(
|
|
197
|
-
options,
|
|
198
|
-
SharedStateConfig.storeExpiryMs
|
|
199
|
-
);
|
|
200
|
-
pubSubStore.setNoNotify(pubSubKey, defaultValue);
|
|
201
|
-
const lazyLoad = options?.lazyLoad;
|
|
202
|
-
const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateConfig.lazyLoad;
|
|
203
|
-
function completeInit(stored) {
|
|
204
|
-
const value = stored !== void 0 ? stored : defaultValue;
|
|
205
|
-
pubSubStore.set(pubSubKey, value);
|
|
206
|
-
obj.initDone = true;
|
|
207
|
-
resolveReadyPromise();
|
|
208
|
-
}
|
|
209
|
-
const obj = {
|
|
210
|
-
defaultValue,
|
|
211
|
-
/** Allow users to await for the completion of data init. */
|
|
212
|
-
readyPromise,
|
|
213
|
-
lazy,
|
|
214
|
-
initStarted: false,
|
|
215
|
-
initDone: false,
|
|
216
|
-
/** `subscribe` function required by useSyncExternalStore. */
|
|
217
|
-
subscribe(subscriber) {
|
|
218
|
-
return pubSubStore.subscribe(pubSubKey, () => subscriber());
|
|
219
|
-
},
|
|
220
|
-
/** Returns true if there is a backing store. */
|
|
221
|
-
hasStore() {
|
|
222
|
-
return Boolean(storageAdapter);
|
|
223
|
-
},
|
|
224
|
-
/**
|
|
225
|
-
* Set a value directly into the store. Does nothing if there is no
|
|
226
|
-
* backing store.
|
|
227
|
-
*
|
|
228
|
-
* Warning: If you want to set the value properly, you should use
|
|
229
|
-
* `setValue()` instead which also updates the in-memory copy.
|
|
230
|
-
*/
|
|
231
|
-
setInStore(value) {
|
|
232
|
-
return storageAdapter?.set(STORAGE_KEY, value);
|
|
233
|
-
},
|
|
234
|
-
/**
|
|
235
|
-
* Get a value directly from the store. Returns undefined if there is no
|
|
236
|
-
* backing store.
|
|
237
|
-
*/
|
|
238
|
-
getFromStore() {
|
|
239
|
-
return storageAdapter?.get(STORAGE_KEY);
|
|
240
|
-
},
|
|
241
|
-
/**
|
|
242
|
-
* Get the value of the shared state.
|
|
243
|
-
* `getSnapshot` function — must return same ref if value unchanged.
|
|
244
|
-
* Note that this would return the default value if data init from store is
|
|
245
|
-
* not completed yet.
|
|
246
|
-
*/
|
|
247
|
-
getSnapshot() {
|
|
248
|
-
return pubSubStore.get(pubSubKey);
|
|
249
|
-
},
|
|
250
|
-
/** Set the value of the shared state. */
|
|
251
|
-
setValue(next) {
|
|
252
|
-
if (typeof next === "function") {
|
|
253
|
-
const prev = pubSubStore.get(pubSubKey);
|
|
254
|
-
next = next(prev);
|
|
255
|
-
}
|
|
256
|
-
pubSubStore.set(pubSubKey, next);
|
|
257
|
-
void obj.setInStore(next);
|
|
258
|
-
},
|
|
259
|
-
/**
|
|
260
|
-
* Remove the value of the shared state. Actually this just sets the value
|
|
261
|
-
* back to the given default value.
|
|
262
|
-
*/
|
|
263
|
-
delete() {
|
|
264
|
-
pubSubStore.set(pubSubKey, defaultValue);
|
|
265
|
-
return storageAdapter?.set(STORAGE_KEY, defaultValue);
|
|
266
|
-
},
|
|
267
|
-
/** Initial default handling. */
|
|
268
|
-
initDefaultValueOnce() {
|
|
269
|
-
if (obj.initDone || obj.initStarted) return;
|
|
270
|
-
obj.initStarted = true;
|
|
271
|
-
const maybePromise = obj.getFromStore();
|
|
272
|
-
if (maybePromise instanceof Promise) {
|
|
273
|
-
return maybePromise.then(completeInit);
|
|
274
|
-
} else {
|
|
275
|
-
const stored = maybePromise;
|
|
276
|
-
completeInit(stored);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
if (!lazy) {
|
|
281
|
-
obj.initDefaultValueOnce();
|
|
282
|
-
}
|
|
283
|
-
return obj;
|
|
284
|
-
}
|
|
285
|
-
function useSharedState(state) {
|
|
286
|
-
void state.initDefaultValueOnce();
|
|
287
|
-
const value = useSyncExternalStore(
|
|
288
|
-
(onStoreChange) => state.subscribe(onStoreChange),
|
|
289
|
-
() => state.getSnapshot(),
|
|
290
|
-
// getServerSnapshot is needed to prevent SSR dev errors in nextjs.
|
|
291
|
-
() => state.getSnapshot()
|
|
292
|
-
);
|
|
293
|
-
return [value, state.setValue];
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// src/stringify.ts
|
|
297
|
-
function stringifyDeterministicForKeys(params) {
|
|
298
|
-
const cache = /* @__PURE__ */ new Set();
|
|
299
|
-
return JSON.stringify(params, (_, value) => {
|
|
300
|
-
if (typeof value === "function") {
|
|
301
|
-
throw new Error(`Functions should not be passed into query parameters`);
|
|
302
|
-
}
|
|
303
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
304
|
-
return value;
|
|
305
|
-
}
|
|
306
|
-
if (cache.has(value)) {
|
|
307
|
-
return "[Circular]";
|
|
308
|
-
}
|
|
309
|
-
cache.add(value);
|
|
310
|
-
if (value !== params) {
|
|
311
|
-
try {
|
|
312
|
-
JSON.stringify(value);
|
|
313
|
-
} catch {
|
|
314
|
-
return "[Unserializable]";
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
return Object.keys(value).sort().reduce(
|
|
318
|
-
(result, key) => {
|
|
319
|
-
result[key] = value[key];
|
|
320
|
-
return result;
|
|
321
|
-
},
|
|
322
|
-
{}
|
|
323
|
-
);
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// src/useDeepMemo.ts
|
|
328
|
-
import { isEqual } from "lodash-es";
|
|
329
|
-
import { useMemo, useState } from "react";
|
|
330
|
-
function useDeepMemo(value) {
|
|
331
|
-
const [state, setState] = useState(value);
|
|
332
|
-
return useMemo(() => {
|
|
333
|
-
if (isEqual(state, value)) {
|
|
334
|
-
return state;
|
|
335
|
-
}
|
|
336
|
-
setState(value);
|
|
337
|
-
return value;
|
|
338
|
-
}, [state, value]);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// src/sharedQuery.ts
|
|
342
|
-
var SharedQueryConfig = {
|
|
12
|
+
import { sharedState, useSharedState } from "./sharedState";
|
|
13
|
+
import { stringifyDeterministicForKeys } from "./stringify";
|
|
14
|
+
import { useDeepMemo } from "./useDeepMemo";
|
|
15
|
+
const SharedQueryConfig = {
|
|
343
16
|
/** Refetch on every page load. */
|
|
344
17
|
staleMs: 0,
|
|
345
18
|
/** Keep in cache for a long time. */
|
|
@@ -358,7 +31,7 @@ var SharedQueryConfig = {
|
|
|
358
31
|
function configureSharedQuery(config) {
|
|
359
32
|
Object.assign(SharedQueryConfig, config);
|
|
360
33
|
}
|
|
361
|
-
|
|
34
|
+
const moduleQueryRegistry = /* @__PURE__ */ new Map();
|
|
362
35
|
function getOrCreateQueryRegistry() {
|
|
363
36
|
if (typeof window !== "undefined") {
|
|
364
37
|
const g = window.globalThis;
|
|
@@ -369,9 +42,7 @@ function getOrCreateQueryRegistry() {
|
|
|
369
42
|
function sharedQuery1(options) {
|
|
370
43
|
const registry = getOrCreateQueryRegistry();
|
|
371
44
|
const key = options.queryName || options.url;
|
|
372
|
-
const existing = registry.get(
|
|
373
|
-
options.queryName || options.url
|
|
374
|
-
);
|
|
45
|
+
const existing = registry.get(key);
|
|
375
46
|
if (existing) {
|
|
376
47
|
return existing;
|
|
377
48
|
}
|
|
@@ -782,7 +453,7 @@ function sharedQuery2(options) {
|
|
|
782
453
|
function sharedQuery(options) {
|
|
783
454
|
return sharedQuery1(options);
|
|
784
455
|
}
|
|
785
|
-
|
|
456
|
+
const DEFAULT_QUERY_STATE_ENTRY = {
|
|
786
457
|
lastUpdatedMs: 0,
|
|
787
458
|
loading: true
|
|
788
459
|
};
|
|
@@ -790,7 +461,7 @@ function useSharedQuery(query, ...args) {
|
|
|
790
461
|
const stableArgs = useDeepMemo(args);
|
|
791
462
|
const [queryState, setQueryState] = useSharedState(query.queryState);
|
|
792
463
|
const isMounted = useRef(true);
|
|
793
|
-
const queryKey =
|
|
464
|
+
const queryKey = useMemo(
|
|
794
465
|
() => query.getQueryKey(stableArgs),
|
|
795
466
|
[query, stableArgs]
|
|
796
467
|
);
|
|
@@ -805,7 +476,7 @@ function useSharedQuery(query, ...args) {
|
|
|
805
476
|
},
|
|
806
477
|
[queryKey, setQueryState]
|
|
807
478
|
);
|
|
808
|
-
const [lastNonEmptyData, setLastNonEmptyData] =
|
|
479
|
+
const [lastNonEmptyData, setLastNonEmptyData] = useState();
|
|
809
480
|
useEffect(() => {
|
|
810
481
|
if (query.keepLastNonEmptyData && queryStateValue.data !== void 0) {
|
|
811
482
|
setLastNonEmptyData(queryStateValue.data);
|
|
@@ -865,7 +536,7 @@ function useSharedQuery(query, ...args) {
|
|
|
865
536
|
query.unmount(queryKey);
|
|
866
537
|
};
|
|
867
538
|
}, [executeQuery, query, queryKey]);
|
|
868
|
-
return
|
|
539
|
+
return useMemo(() => {
|
|
869
540
|
return {
|
|
870
541
|
...queryStateValue,
|
|
871
542
|
// Fill with lastNonEmptyData when data is undefined.
|
package/sharedState.cjs
CHANGED
|
@@ -1,142 +1,12 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/sharedState.ts
|
|
21
|
-
var sharedState_exports = {};
|
|
22
|
-
__export(sharedState_exports, {
|
|
23
|
-
SharedStateConfig: () => SharedStateConfig,
|
|
24
|
-
configureSharedState: () => configureSharedState,
|
|
25
|
-
sharedState: () => sharedState,
|
|
26
|
-
useSharedState: () => useSharedState,
|
|
27
|
-
useSharedStateSetter: () => useSharedStateSetter,
|
|
28
|
-
useSharedStateValue: () => useSharedStateValue
|
|
29
|
-
});
|
|
30
|
-
module.exports = __toCommonJS(sharedState_exports);
|
|
31
|
-
var import_timeConstants = require("@choksheak/ts-utils/timeConstants");
|
|
32
|
-
var import_react = require("react");
|
|
33
|
-
|
|
34
|
-
// src/storage.ts
|
|
35
|
-
var import_kvStore = require("@choksheak/ts-utils/kvStore");
|
|
36
|
-
var import_localStore = require("@choksheak/ts-utils/localStore");
|
|
37
|
-
var IS_NOT_BROWSER = typeof window === "undefined";
|
|
38
|
-
function getStorageAdapter(options, defaultStoreExpiryMs) {
|
|
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
|
-
const config = { ...store, expiryMs };
|
|
46
|
-
switch (store.persistTo) {
|
|
47
|
-
case "localStorage":
|
|
48
|
-
return localStoreAdapter(config);
|
|
49
|
-
case "indexedDb":
|
|
50
|
-
return kvStoreAdapter(config);
|
|
51
|
-
default:
|
|
52
|
-
store.persistTo;
|
|
53
|
-
throw new Error(`Unknown store.adapter ${store.persistTo}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return store;
|
|
57
|
-
}
|
|
58
|
-
function localStoreAdapter({
|
|
59
|
-
key,
|
|
60
|
-
expiryMs,
|
|
61
|
-
isValid
|
|
62
|
-
}) {
|
|
63
|
-
const STORE_NAME = "react-utils";
|
|
64
|
-
const adapter = (0, import_localStore.createLocalStore)(STORE_NAME, {
|
|
65
|
-
defaultExpiryMs: expiryMs
|
|
66
|
-
});
|
|
67
|
-
const keyPrefix = key + ":";
|
|
68
|
-
return {
|
|
69
|
-
set: (key2, value) => {
|
|
70
|
-
if (IS_NOT_BROWSER) return;
|
|
71
|
-
adapter.set(keyPrefix + key2, value);
|
|
72
|
-
},
|
|
73
|
-
get: (key2) => {
|
|
74
|
-
if (IS_NOT_BROWSER) return void 0;
|
|
75
|
-
const fullKey = keyPrefix + key2;
|
|
76
|
-
const value = adapter.get(fullKey);
|
|
77
|
-
if (value !== void 0 && isValid && !isValid(value)) {
|
|
78
|
-
console.warn(
|
|
79
|
-
`localStorage adapter: Auto-discard invalid value for ${fullKey}: ${JSON.stringify(value)}`
|
|
80
|
-
);
|
|
81
|
-
adapter.delete(fullKey);
|
|
82
|
-
return void 0;
|
|
83
|
-
}
|
|
84
|
-
return value;
|
|
85
|
-
},
|
|
86
|
-
delete: (key2) => {
|
|
87
|
-
if (IS_NOT_BROWSER) return;
|
|
88
|
-
adapter.delete(keyPrefix + key2);
|
|
89
|
-
},
|
|
90
|
-
/** Note that this will clear all keys in all shared states. */
|
|
91
|
-
clear: () => {
|
|
92
|
-
if (IS_NOT_BROWSER) return;
|
|
93
|
-
adapter.clear();
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
function kvStoreAdapter({
|
|
98
|
-
key,
|
|
99
|
-
expiryMs,
|
|
100
|
-
isValid
|
|
101
|
-
}) {
|
|
102
|
-
const keyPrefix = key + ":";
|
|
103
|
-
return {
|
|
104
|
-
set: async (key2, value) => {
|
|
105
|
-
if (IS_NOT_BROWSER) return;
|
|
106
|
-
await import_kvStore.kvStore.set(keyPrefix + key2, value, expiryMs);
|
|
107
|
-
},
|
|
108
|
-
get: async (key2) => {
|
|
109
|
-
if (IS_NOT_BROWSER) return void 0;
|
|
110
|
-
const fullKey = keyPrefix + key2;
|
|
111
|
-
const value = await import_kvStore.kvStore.get(fullKey);
|
|
112
|
-
if (value !== void 0 && isValid && !isValid(value)) {
|
|
113
|
-
console.warn(
|
|
114
|
-
`indexedDb adapter: Auto-discard invalid value for ${key2}:`,
|
|
115
|
-
value
|
|
116
|
-
);
|
|
117
|
-
await import_kvStore.kvStore.delete(fullKey);
|
|
118
|
-
return void 0;
|
|
119
|
-
}
|
|
120
|
-
return value;
|
|
121
|
-
},
|
|
122
|
-
delete: async (key2) => {
|
|
123
|
-
if (IS_NOT_BROWSER) return;
|
|
124
|
-
await import_kvStore.kvStore.delete(keyPrefix + key2);
|
|
125
|
-
},
|
|
126
|
-
clear: async () => {
|
|
127
|
-
if (IS_NOT_BROWSER) return;
|
|
128
|
-
await import_kvStore.kvStore.clear();
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// src/sharedState.ts
|
|
134
|
-
var SharedStateConfig = {
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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 _timeConstants = require('@choksheak/ts-utils/timeConstants');
|
|
2
|
+
var _react = require('react');
|
|
3
|
+
var _storage = require('./storage');
|
|
4
|
+
const SharedStateConfig = {
|
|
135
5
|
/**
|
|
136
6
|
* Default duration for storage expiration in milliseconds. Initial value
|
|
137
7
|
* is 30 days, but can be changed to anything.
|
|
138
8
|
*/
|
|
139
|
-
storeExpiryMs: 30 *
|
|
9
|
+
storeExpiryMs: 30 * _timeConstants.MS_PER_DAY,
|
|
140
10
|
/**
|
|
141
11
|
* True to load from storage only on mount, false (default) to load in
|
|
142
12
|
* the top level scope when the shared state is defined.
|
|
@@ -201,9 +71,17 @@ function getOrCreatePubSubStore() {
|
|
|
201
71
|
}
|
|
202
72
|
return createPubSubStore();
|
|
203
73
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
74
|
+
const pubSubStore = getOrCreatePubSubStore();
|
|
75
|
+
const STORAGE_KEY = "state";
|
|
76
|
+
let stateKey = 0;
|
|
77
|
+
function getNextStateKey() {
|
|
78
|
+
if (typeof window !== "undefined") {
|
|
79
|
+
const t = window.globalThis;
|
|
80
|
+
t.reactUtilsStateKey = (_nullishCoalesce(t.reactUtilsStateKey, () => ( 0))) + 1;
|
|
81
|
+
return t.reactUtilsStateKey;
|
|
82
|
+
}
|
|
83
|
+
return ++stateKey;
|
|
84
|
+
}
|
|
207
85
|
function sharedState(defaultValue, options) {
|
|
208
86
|
let readyResolve = () => {
|
|
209
87
|
};
|
|
@@ -211,13 +89,13 @@ function sharedState(defaultValue, options) {
|
|
|
211
89
|
readyResolve = resolve;
|
|
212
90
|
});
|
|
213
91
|
const resolveReadyPromise = readyResolve;
|
|
214
|
-
const pubSubKey = String(
|
|
215
|
-
const storageAdapter = getStorageAdapter(
|
|
92
|
+
const pubSubKey = String(getNextStateKey());
|
|
93
|
+
const storageAdapter = _storage.getStorageAdapter.call(void 0,
|
|
216
94
|
options,
|
|
217
95
|
SharedStateConfig.storeExpiryMs
|
|
218
96
|
);
|
|
219
97
|
pubSubStore.setNoNotify(pubSubKey, defaultValue);
|
|
220
|
-
const lazyLoad = options
|
|
98
|
+
const lazyLoad = _optionalChain([options, 'optionalAccess', _ => _.lazyLoad]);
|
|
221
99
|
const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateConfig.lazyLoad;
|
|
222
100
|
function completeInit(stored) {
|
|
223
101
|
const value = stored !== void 0 ? stored : defaultValue;
|
|
@@ -248,14 +126,14 @@ function sharedState(defaultValue, options) {
|
|
|
248
126
|
* `setValue()` instead which also updates the in-memory copy.
|
|
249
127
|
*/
|
|
250
128
|
setInStore(value) {
|
|
251
|
-
return storageAdapter
|
|
129
|
+
return _optionalChain([storageAdapter, 'optionalAccess', _2 => _2.set, 'call', _3 => _3(STORAGE_KEY, value)]);
|
|
252
130
|
},
|
|
253
131
|
/**
|
|
254
132
|
* Get a value directly from the store. Returns undefined if there is no
|
|
255
133
|
* backing store.
|
|
256
134
|
*/
|
|
257
135
|
getFromStore() {
|
|
258
|
-
return storageAdapter
|
|
136
|
+
return _optionalChain([storageAdapter, 'optionalAccess', _4 => _4.get, 'call', _5 => _5(STORAGE_KEY)]);
|
|
259
137
|
},
|
|
260
138
|
/**
|
|
261
139
|
* Get the value of the shared state.
|
|
@@ -281,7 +159,7 @@ function sharedState(defaultValue, options) {
|
|
|
281
159
|
*/
|
|
282
160
|
delete() {
|
|
283
161
|
pubSubStore.set(pubSubKey, defaultValue);
|
|
284
|
-
return storageAdapter
|
|
162
|
+
return _optionalChain([storageAdapter, 'optionalAccess', _6 => _6.set, 'call', _7 => _7(STORAGE_KEY, defaultValue)]);
|
|
285
163
|
},
|
|
286
164
|
/** Initial default handling. */
|
|
287
165
|
initDefaultValueOnce() {
|
|
@@ -303,7 +181,7 @@ function sharedState(defaultValue, options) {
|
|
|
303
181
|
}
|
|
304
182
|
function useSharedState(state) {
|
|
305
183
|
void state.initDefaultValueOnce();
|
|
306
|
-
const value = (0,
|
|
184
|
+
const value = _react.useSyncExternalStore.call(void 0,
|
|
307
185
|
(onStoreChange) => state.subscribe(onStoreChange),
|
|
308
186
|
() => state.getSnapshot(),
|
|
309
187
|
// getServerSnapshot is needed to prevent SSR dev errors in nextjs.
|
|
@@ -318,12 +196,11 @@ function useSharedStateSetter(state) {
|
|
|
318
196
|
void state.initDefaultValueOnce();
|
|
319
197
|
return state.setValue;
|
|
320
198
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
});
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
exports.SharedStateConfig = SharedStateConfig; exports.configureSharedState = configureSharedState; exports.sharedState = sharedState; exports.useSharedState = useSharedState; exports.useSharedStateSetter = useSharedStateSetter; exports.useSharedStateValue = useSharedStateValue;
|
package/sharedState.min.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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 _timeConstants = require('@choksheak/ts-utils/timeConstants');var _react = require('react');var _storage = require('./storage');const p={storeExpiryMs:30*_timeConstants.MS_PER_DAY,lazyLoad:!1};function E(e){Object.assign(p,e)}function l(){const e=new Map,i=new Map;function S(o,n,t){const a=i.get(o);if(!a)return;const c=Array.from(a.values());for(const d of c)try{d(n,t)}catch(f){console.error("Error invoking subscriber:",f)}}return{get(o){return e.get(o)},set(o,n){const t=e.get(o);t!==n&&(e.set(o,n),S(o,n,t))},delete(o){e.delete(o)},setNoNotify(o,n){e.set(o,n)},subscribe(o,n){let t=i.get(o);return t||(t=new Set,i.set(o,t)),t.add(n),()=>{t.delete(n),t.size===0&&i.delete(o)}}}}function h(){if(typeof window<"u"){const e=window.globalThis;return e.reactUtilsPubSubStore||(e.reactUtilsPubSubStore=l())}return l()}const u=h(),T="state";let m=0;function P(){if(typeof window<"u"){const e=window.globalThis;return e.reactUtilsStateKey=(_nullishCoalesce(e.reactUtilsStateKey, () => (0)))+1,e.reactUtilsStateKey}return++m}function U(e,i){let S=()=>{};const o=new Promise(r=>{S=r}),n=S,t=String(P()),a=_storage.getStorageAdapter.call(void 0, i,p.storeExpiryMs);u.setNoNotify(t,e);const c=_optionalChain([i, 'optionalAccess', _ => _.lazyLoad]),d=c!==void 0?c:p.lazyLoad;function f(r){const b=r!==void 0?r:e;u.set(t,b),s.initDone=!0,n()}const s={defaultValue:e,readyPromise:o,lazy:d,initStarted:!1,initDone:!1,subscribe(r){return u.subscribe(t,()=>r())},hasStore(){return!!a},setInStore(r){return _optionalChain([a, 'optionalAccess', _2 => _2.set, 'call', _3 => _3(T,r)])},getFromStore(){return _optionalChain([a, 'optionalAccess', _4 => _4.get, 'call', _5 => _5(T)])},getSnapshot(){return u.get(t)},setValue(r){if(typeof r=="function"){const b=u.get(t);r=r(b)}u.set(t,r),s.setInStore(r)},delete(){return u.set(t,e),_optionalChain([a, 'optionalAccess', _6 => _6.set, 'call', _7 => _7(T,e)])},initDefaultValueOnce(){if(s.initDone||s.initStarted)return;s.initStarted=!0;const r=s.getFromStore();if(r instanceof Promise)return r.then(f);f(r)}};return d||s.initDefaultValueOnce(),s}function w(e){return e.initDefaultValueOnce(),[_react.useSyncExternalStore.call(void 0, S=>e.subscribe(S),()=>e.getSnapshot(),()=>e.getSnapshot()),e.setValue]}function R(e){return w(e)[0]}function C(e){return e.initDefaultValueOnce(),e.setValue}exports.SharedStateConfig = p; exports.configureSharedState = E; exports.sharedState = U; exports.useSharedState = w; exports.useSharedStateSetter = C; exports.useSharedStateValue = R;
|
|
2
2
|
//# sourceMappingURL=sharedState.min.cjs.map
|