@choksheak/react-utils 0.3.8 → 0.4.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/NoSSR.cjs +7 -30
- 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 +2 -0
- package/chunk-33UMQLKY.mjs +43 -0
- package/chunk-3V7WBGWQ.mjs +16 -0
- package/chunk-3X25NN6X.cjs +195 -0
- package/chunk-5DO7KC3L.cjs +43 -0
- package/chunk-5PDGU37E.cjs +104 -0
- package/chunk-6ZZ54XM5.min.mjs +2 -0
- package/chunk-6ZZ54XM5.min.mjs.map +1 -0
- package/chunk-74BS2FAO.cjs +12 -0
- package/chunk-F5L32IUC.min.cjs +2 -0
- package/chunk-F5L32IUC.min.cjs.map +1 -0
- package/chunk-GPV6JIQK.mjs +17 -0
- package/chunk-KE3RXVMS.min.cjs +2 -0
- package/chunk-KE3RXVMS.min.cjs.map +1 -0
- package/chunk-KILGR7YA.min.mjs +2 -0
- package/chunk-KILGR7YA.min.mjs.map +1 -0
- package/chunk-KRXENFK3.mjs +195 -0
- package/chunk-MWDH7YON.min.mjs +2 -0
- package/chunk-MWDH7YON.min.mjs.map +1 -0
- package/chunk-NTFFK7ZH.min.cjs +2 -0
- package/chunk-NTFFK7ZH.min.cjs.map +1 -0
- package/chunk-O3RBYG3W.min.cjs +2 -0
- package/chunk-O3RBYG3W.min.cjs.map +1 -0
- package/chunk-PHLY3LR4.mjs +104 -0
- package/chunk-RM4ZGGZ2.min.mjs +2 -0
- package/chunk-RM4ZGGZ2.min.mjs.map +1 -0
- package/chunk-TEZPF6BG.min.cjs +2 -0
- package/chunk-TEZPF6BG.min.cjs.map +1 -0
- package/chunk-UFJNJ3WV.cjs +16 -0
- package/chunk-UFJQLQFI.min.cjs +2 -0
- package/chunk-UFJQLQFI.min.cjs.map +1 -0
- package/chunk-V7L3UICC.min.mjs +2 -0
- package/chunk-V7L3UICC.min.mjs.map +1 -0
- package/chunk-VHMO75EY.min.mjs +2 -0
- package/chunk-VHMO75EY.min.mjs.map +1 -0
- package/chunk-WVLPJPWG.cjs +17 -0
- package/chunk-X6BYQHVC.mjs +12 -0
- package/fetcher.cjs +8 -50
- package/fetcher.d.mts +3 -3
- package/fetcher.d.ts +2 -2
- package/fetcher.min.cjs +1 -1
- package/fetcher.min.cjs.map +1 -1
- package/fetcher.min.mjs +1 -1
- package/fetcher.min.mjs.map +1 -1
- package/fetcher.mjs +5 -11
- package/package.json +124 -29
- package/sharedQuery.cjs +132 -392
- package/sharedQuery.d.mts +58 -13
- package/sharedQuery.d.ts +57 -12
- 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 +94 -322
- package/sharedState.cjs +15 -304
- package/sharedState.d.mts +4 -4
- package/sharedState.d.ts +4 -4
- 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 +10 -269
- package/storage.cjs +10 -123
- package/storage.d.mts +1 -0
- package/storage.d.ts +1 -0
- 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 +6 -92
- package/stringify.cjs +8 -57
- 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 +6 -30
- package/useDeepMemo.cjs +6 -50
- 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 +4 -13
package/sharedState.cjs
CHANGED
|
@@ -1,307 +1,18 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
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);
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
19
2
|
|
|
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
3
|
|
|
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 adapter = (0, import_localStore.createLocalStore)(key, { defaultExpiryMs: expiryMs });
|
|
64
|
-
return {
|
|
65
|
-
set: (key2, value) => {
|
|
66
|
-
if (IS_NOT_BROWSER) return;
|
|
67
|
-
adapter.set(key2, value);
|
|
68
|
-
},
|
|
69
|
-
get: (key2) => {
|
|
70
|
-
if (IS_NOT_BROWSER) return void 0;
|
|
71
|
-
const value = adapter.get(key2);
|
|
72
|
-
if (isValid && !isValid(value)) {
|
|
73
|
-
console.warn(
|
|
74
|
-
`localStorage adapter: Auto-discard invalid value for ${key2}: ${JSON.stringify(value)}`
|
|
75
|
-
);
|
|
76
|
-
adapter.delete(key2);
|
|
77
|
-
return void 0;
|
|
78
|
-
}
|
|
79
|
-
return value;
|
|
80
|
-
},
|
|
81
|
-
delete: (key2) => {
|
|
82
|
-
if (IS_NOT_BROWSER) return;
|
|
83
|
-
adapter.delete(key2);
|
|
84
|
-
},
|
|
85
|
-
clear: () => {
|
|
86
|
-
if (IS_NOT_BROWSER) return;
|
|
87
|
-
adapter.clear();
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
function kvStoreAdapter({
|
|
92
|
-
key,
|
|
93
|
-
expiryMs,
|
|
94
|
-
isValid
|
|
95
|
-
}) {
|
|
96
|
-
const keyPrefix = key + ":";
|
|
97
|
-
return {
|
|
98
|
-
set: async (key2, value) => {
|
|
99
|
-
if (IS_NOT_BROWSER) return;
|
|
100
|
-
await import_kvStore.kvStore.set(keyPrefix + key2, value, expiryMs);
|
|
101
|
-
},
|
|
102
|
-
get: async (key2) => {
|
|
103
|
-
if (IS_NOT_BROWSER) return void 0;
|
|
104
|
-
const fullKey = keyPrefix + key2;
|
|
105
|
-
const value = await import_kvStore.kvStore.get(fullKey);
|
|
106
|
-
if (value !== void 0 && isValid && !isValid(value)) {
|
|
107
|
-
console.warn(
|
|
108
|
-
`indexedDb adapter: Auto-discard invalid value for ${key2}:`,
|
|
109
|
-
value
|
|
110
|
-
);
|
|
111
|
-
await import_kvStore.kvStore.delete(fullKey);
|
|
112
|
-
return void 0;
|
|
113
|
-
}
|
|
114
|
-
return value;
|
|
115
|
-
},
|
|
116
|
-
delete: async (key2) => {
|
|
117
|
-
if (IS_NOT_BROWSER) return;
|
|
118
|
-
await import_kvStore.kvStore.delete(keyPrefix + key2);
|
|
119
|
-
},
|
|
120
|
-
clear: async () => {
|
|
121
|
-
if (IS_NOT_BROWSER) return;
|
|
122
|
-
await import_kvStore.kvStore.clear();
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
4
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
Object.assign(SharedStateConfig, config);
|
|
142
|
-
}
|
|
143
|
-
function createPubSubStore() {
|
|
144
|
-
const dataByKey = /* @__PURE__ */ new Map();
|
|
145
|
-
const subscribersByKey = /* @__PURE__ */ new Map();
|
|
146
|
-
function notify(key, next, prev) {
|
|
147
|
-
const subscribers = subscribersByKey.get(key);
|
|
148
|
-
if (!subscribers) return;
|
|
149
|
-
const copy = Array.from(subscribers.values());
|
|
150
|
-
for (const subscriber of copy) {
|
|
151
|
-
try {
|
|
152
|
-
subscriber(next, prev);
|
|
153
|
-
} catch (e) {
|
|
154
|
-
console.error(`Error invoking subscriber:`, e);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return {
|
|
159
|
-
// This could be undefined if T includes undefined, else it should never
|
|
160
|
-
// return undefined because the user has to always specify the default value.
|
|
161
|
-
get(key) {
|
|
162
|
-
return dataByKey.get(key);
|
|
163
|
-
},
|
|
164
|
-
set(key, value) {
|
|
165
|
-
const prev = dataByKey.get(key);
|
|
166
|
-
if (prev === value) return;
|
|
167
|
-
dataByKey.set(key, value);
|
|
168
|
-
notify(key, value, prev);
|
|
169
|
-
},
|
|
170
|
-
delete(key) {
|
|
171
|
-
dataByKey.delete(key);
|
|
172
|
-
},
|
|
173
|
-
setNoNotify(key, value) {
|
|
174
|
-
dataByKey.set(key, value);
|
|
175
|
-
},
|
|
176
|
-
// Subscribe to changes of a specific key
|
|
177
|
-
subscribe(key, subscriber) {
|
|
178
|
-
let subscribers = subscribersByKey.get(key);
|
|
179
|
-
if (!subscribers) {
|
|
180
|
-
subscribers = /* @__PURE__ */ new Set();
|
|
181
|
-
subscribersByKey.set(key, subscribers);
|
|
182
|
-
}
|
|
183
|
-
subscribers.add(subscriber);
|
|
184
|
-
return () => {
|
|
185
|
-
subscribers.delete(subscriber);
|
|
186
|
-
if (subscribers.size === 0) subscribersByKey.delete(key);
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
var pubSubStore = createPubSubStore();
|
|
192
|
-
var STORAGE_KEY = "state";
|
|
193
|
-
var stateKey = 0;
|
|
194
|
-
function sharedState(defaultValue, options) {
|
|
195
|
-
let readyResolve = () => {
|
|
196
|
-
};
|
|
197
|
-
const readyPromise = new Promise((resolve) => {
|
|
198
|
-
readyResolve = resolve;
|
|
199
|
-
});
|
|
200
|
-
const resolveReadyPromise = readyResolve;
|
|
201
|
-
const pubSubKey = String(stateKey++);
|
|
202
|
-
const storageAdapter = getStorageAdapter(
|
|
203
|
-
options,
|
|
204
|
-
SharedStateConfig.storeExpiryMs
|
|
205
|
-
);
|
|
206
|
-
pubSubStore.setNoNotify(pubSubKey, defaultValue);
|
|
207
|
-
const lazyLoad = options?.lazyLoad;
|
|
208
|
-
const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateConfig.lazyLoad;
|
|
209
|
-
const obj = {
|
|
210
|
-
/** Allow users to await for the completion of data init. */
|
|
211
|
-
readyPromise,
|
|
212
|
-
lazy,
|
|
213
|
-
initStarted: false,
|
|
214
|
-
initDone: false,
|
|
215
|
-
/** `subscribe` function required by useSyncExternalStore. */
|
|
216
|
-
subscribe(subscriber) {
|
|
217
|
-
return pubSubStore.subscribe(pubSubKey, () => subscriber());
|
|
218
|
-
},
|
|
219
|
-
/** Returns true if there is a backing store. */
|
|
220
|
-
hasStore() {
|
|
221
|
-
return Boolean(storageAdapter);
|
|
222
|
-
},
|
|
223
|
-
/**
|
|
224
|
-
* Set a value directly into the store. Does nothing if there is no
|
|
225
|
-
* backing store.
|
|
226
|
-
*
|
|
227
|
-
* Warning: If you want to set the value properly, you should use
|
|
228
|
-
* `setValue()` instead which also updates the in-memory copy.
|
|
229
|
-
*/
|
|
230
|
-
async setInStore(value) {
|
|
231
|
-
return await storageAdapter?.set(STORAGE_KEY, value);
|
|
232
|
-
},
|
|
233
|
-
/**
|
|
234
|
-
* Get a value directly from the store. Returns undefined if there is no
|
|
235
|
-
* backing store.
|
|
236
|
-
*/
|
|
237
|
-
async getFromStore() {
|
|
238
|
-
return await storageAdapter?.get(STORAGE_KEY);
|
|
239
|
-
},
|
|
240
|
-
/**
|
|
241
|
-
* Get the value of the shared state.
|
|
242
|
-
* `getSnapshot` function — must return same ref if value unchanged.
|
|
243
|
-
* Note that this would return the default value if data init from store is
|
|
244
|
-
* not completed yet.
|
|
245
|
-
*/
|
|
246
|
-
getSnapshot() {
|
|
247
|
-
return pubSubStore.get(pubSubKey);
|
|
248
|
-
},
|
|
249
|
-
/** Set the value of the shared state. */
|
|
250
|
-
setValue(next) {
|
|
251
|
-
if (typeof next === "function") {
|
|
252
|
-
const prev = pubSubStore.get(pubSubKey);
|
|
253
|
-
next = next(prev);
|
|
254
|
-
}
|
|
255
|
-
pubSubStore.set(pubSubKey, next);
|
|
256
|
-
void obj.setInStore(next);
|
|
257
|
-
},
|
|
258
|
-
/**
|
|
259
|
-
* Remove the value of the shared state. Actually this just sets the value
|
|
260
|
-
* back to the given default value.
|
|
261
|
-
*/
|
|
262
|
-
delete() {
|
|
263
|
-
pubSubStore.set(pubSubKey, defaultValue);
|
|
264
|
-
void storageAdapter?.set(STORAGE_KEY, defaultValue);
|
|
265
|
-
},
|
|
266
|
-
/** Initial default handling. */
|
|
267
|
-
async initDefaultValueOnce() {
|
|
268
|
-
if (obj.initDone || obj.initStarted) return;
|
|
269
|
-
obj.initStarted = true;
|
|
270
|
-
const stored = await obj.getFromStore();
|
|
271
|
-
const value = stored !== void 0 ? stored : defaultValue;
|
|
272
|
-
pubSubStore.set(pubSubKey, value);
|
|
273
|
-
obj.initDone = true;
|
|
274
|
-
resolveReadyPromise();
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
if (!lazy) {
|
|
278
|
-
void obj.initDefaultValueOnce();
|
|
279
|
-
}
|
|
280
|
-
return obj;
|
|
281
|
-
}
|
|
282
|
-
function useSharedState(state) {
|
|
283
|
-
void state.initDefaultValueOnce();
|
|
284
|
-
const value = (0, import_react.useSyncExternalStore)(
|
|
285
|
-
(onStoreChange) => state.subscribe(onStoreChange),
|
|
286
|
-
() => state.getSnapshot(),
|
|
287
|
-
// getServerSnapshot is needed to prevent SSR dev errors in nextjs.
|
|
288
|
-
() => state.getSnapshot()
|
|
289
|
-
);
|
|
290
|
-
return [value, state.setValue];
|
|
291
|
-
}
|
|
292
|
-
function useSharedStateValue(state) {
|
|
293
|
-
return useSharedState(state)[0];
|
|
294
|
-
}
|
|
295
|
-
function useSharedStateSetter(state) {
|
|
296
|
-
void state.initDefaultValueOnce();
|
|
297
|
-
return state.setValue;
|
|
298
|
-
}
|
|
299
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
300
|
-
0 && (module.exports = {
|
|
301
|
-
SharedStateConfig,
|
|
302
|
-
configureSharedState,
|
|
303
|
-
sharedState,
|
|
304
|
-
useSharedState,
|
|
305
|
-
useSharedStateSetter,
|
|
306
|
-
useSharedStateValue
|
|
307
|
-
});
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
var _chunk3X25NN6Xcjs = require('./chunk-3X25NN6X.cjs');
|
|
9
|
+
require('./chunk-5PDGU37E.cjs');
|
|
10
|
+
require('./chunk-74BS2FAO.cjs');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
exports.SharedStateConfig = _chunk3X25NN6Xcjs.SharedStateConfig; exports.configureSharedState = _chunk3X25NN6Xcjs.configureSharedState; exports.sharedState = _chunk3X25NN6Xcjs.sharedState; exports.useSharedState = _chunk3X25NN6Xcjs.useSharedState; exports.useSharedStateSetter = _chunk3X25NN6Xcjs.useSharedStateSetter; exports.useSharedStateValue = _chunk3X25NN6Xcjs.useSharedStateValue;
|
package/sharedState.d.mts
CHANGED
|
@@ -108,12 +108,12 @@ declare function sharedState<T>(defaultValue: T, options?: SharedStateOptions<T>
|
|
|
108
108
|
* Warning: If you want to set the value properly, you should use
|
|
109
109
|
* `setValue()` instead which also updates the in-memory copy.
|
|
110
110
|
*/
|
|
111
|
-
readonly setInStore: (value: T) => Promise<void
|
|
111
|
+
readonly setInStore: (value: T) => Promise<void> | void;
|
|
112
112
|
/**
|
|
113
113
|
* Get a value directly from the store. Returns undefined if there is no
|
|
114
114
|
* backing store.
|
|
115
115
|
*/
|
|
116
|
-
readonly getFromStore: () => Promise<T | undefined
|
|
116
|
+
readonly getFromStore: () => Promise<T | undefined> | T | undefined;
|
|
117
117
|
/**
|
|
118
118
|
* Get the value of the shared state.
|
|
119
119
|
* `getSnapshot` function — must return same ref if value unchanged.
|
|
@@ -127,9 +127,9 @@ declare function sharedState<T>(defaultValue: T, options?: SharedStateOptions<T>
|
|
|
127
127
|
* Remove the value of the shared state. Actually this just sets the value
|
|
128
128
|
* back to the given default value.
|
|
129
129
|
*/
|
|
130
|
-
readonly delete: () => void;
|
|
130
|
+
readonly delete: () => Promise<void> | void;
|
|
131
131
|
/** Initial default handling. */
|
|
132
|
-
readonly initDefaultValueOnce: () => Promise<void
|
|
132
|
+
readonly initDefaultValueOnce: () => Promise<void> | void;
|
|
133
133
|
};
|
|
134
134
|
type SharedState<T> = ReturnType<typeof sharedState<T>>;
|
|
135
135
|
/**
|
package/sharedState.d.ts
CHANGED
|
@@ -104,12 +104,12 @@ export declare function sharedState<T>(defaultValue: T, options?: SharedStateOpt
|
|
|
104
104
|
* Warning: If you want to set the value properly, you should use
|
|
105
105
|
* `setValue()` instead which also updates the in-memory copy.
|
|
106
106
|
*/
|
|
107
|
-
readonly setInStore: (value: T) => Promise<void
|
|
107
|
+
readonly setInStore: (value: T) => Promise<void> | void;
|
|
108
108
|
/**
|
|
109
109
|
* Get a value directly from the store. Returns undefined if there is no
|
|
110
110
|
* backing store.
|
|
111
111
|
*/
|
|
112
|
-
readonly getFromStore: () => Promise<T | undefined
|
|
112
|
+
readonly getFromStore: () => Promise<T | undefined> | T | undefined;
|
|
113
113
|
/**
|
|
114
114
|
* Get the value of the shared state.
|
|
115
115
|
* `getSnapshot` function — must return same ref if value unchanged.
|
|
@@ -123,9 +123,9 @@ export declare function sharedState<T>(defaultValue: T, options?: SharedStateOpt
|
|
|
123
123
|
* Remove the value of the shared state. Actually this just sets the value
|
|
124
124
|
* back to the given default value.
|
|
125
125
|
*/
|
|
126
|
-
readonly delete: () => void;
|
|
126
|
+
readonly delete: () => Promise<void> | void;
|
|
127
127
|
/** Initial default handling. */
|
|
128
|
-
readonly initDefaultValueOnce: () => Promise<void
|
|
128
|
+
readonly initDefaultValueOnce: () => Promise<void> | void;
|
|
129
129
|
};
|
|
130
130
|
export type SharedState<T> = ReturnType<typeof sharedState<T>>;
|
|
131
131
|
/**
|
package/sharedState.min.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkNTFFK7ZHmincjs = require('./chunk-NTFFK7ZH.min.cjs');require('./chunk-UFJQLQFI.min.cjs');require('./chunk-KE3RXVMS.min.cjs');exports.SharedStateConfig = _chunkNTFFK7ZHmincjs.a; exports.configureSharedState = _chunkNTFFK7ZHmincjs.b; exports.sharedState = _chunkNTFFK7ZHmincjs.c; exports.useSharedState = _chunkNTFFK7ZHmincjs.d; exports.useSharedStateSetter = _chunkNTFFK7ZHmincjs.f; exports.useSharedStateValue = _chunkNTFFK7ZHmincjs.e;
|
|
2
2
|
//# sourceMappingURL=sharedState.min.cjs.map
|
package/sharedState.min.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sharedState.ts","../src/storage.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * The \"shared state\" is a React state that shares the same value across the\n * entire app. Users declare a shared state constant that can be reused across\n * multiple components with the same underlying value.\n *\n * Shared states provide persistence to local storage and/or indexed DB out of\n * the box, by using \"@choksheak/ts-utils\". Note that no matter if the shared\n * state uses persistence or not, it will always maintain a copy of the state\n * in memory. Persisted values can be configured with an automatic expiration\n * duration.\n *\n * This module is largely similar to the open source \"jotai\" npm library. You\n * can use shared states to replace \"jotai\" in your code, and optionally make\n * use of the persistence mechanism. A quick migration guide from jotai is:\n *\n * ```\n * atom() --> sharedState()\n * useAtom() --> useSharedState()\n * useAtomValue() --> useSharedStateValue()\n * useSetAtom() --> useSharedStateSetter()\n * ```\n *\n * Example:\n * ```\n * import { sharedState, useSharedState } from \"@choksheak/react-utils/sharedState\";\n *\n * // Create a new shared state in the top level scope.\n * // The first argument is the default value, which is required.\n * // The second argument is an options object, and is optional (defaults\n * // to storing in memory only without any persistence).\n * const usersState = sharedState(\n * [], { store: { persistTo: \"indexedDb\", key: \"users\" }}\n * );\n *\n * export const UsersComponent: React.FC = () => {\n * // Get both the value and the setter.\n * const [users, setUsers] = useSharedState(usersState);\n * ...\n * };\n *\n * export const ReadOnlyComponent: React.FC = () => {\n * // Get the value only.\n * const users = useSharedStateValue(usersState);\n * ...\n * };\n *\n * export const WriteOnlyComponent: React.FC = () => {\n * // Get the setter only.\n * const setUsers = useSharedStateSetter(usersState);\n * ...\n * };\n * ```\n */\n\nimport { MS_PER_DAY } from \"@choksheak/ts-utils/timeConstants\";\nimport { Dispatch, SetStateAction, useSyncExternalStore } from \"react\";\n\nimport { getStorageAdapter, StorageOptions } from \"./storage\";\n\n/************************************************************************/\n/* Global config */\n/************************************************************************/\n\n/**\n * These values are configurable by the user at any time.\n */\nexport const SharedStateConfig = {\n /**\n * Default duration for storage expiration in milliseconds. Initial value\n * is 30 days, but can be changed to anything.\n */\n storeExpiryMs: 30 * MS_PER_DAY,\n\n /**\n * True to load from storage only on mount, false (default) to load in\n * the top level scope when the shared state is defined.\n */\n lazyLoad: false,\n};\n\nexport type SharedStateConfig = typeof SharedStateConfig;\n\n/** Convenience function to update global defaults. */\nexport function configureSharedState(config: Partial<SharedStateConfig>) {\n Object.assign(SharedStateConfig, config);\n}\n\n/************************************************************************/\n/* Pub-sub store\n/************************************************************************/\n\ntype Subscriber<T> = (next: T, prev: T) => void;\n\nfunction createPubSubStore() {\n const dataByKey = new Map<string, unknown>();\n const subscribersByKey = new Map<string, Set<Subscriber<unknown>>>();\n\n function notify<T>(key: string, next: T, prev: T): void {\n const subscribers = subscribersByKey.get(key);\n if (!subscribers) return;\n\n // Make copy to protect against mutation during iteration.\n const copy = Array.from(subscribers.values());\n for (const subscriber of copy) {\n try {\n subscriber(next, prev);\n } catch (e) {\n console.error(`Error invoking subscriber:`, e);\n }\n }\n }\n\n return {\n // This could be undefined if T includes undefined, else it should never\n // return undefined because the user has to always specify the default value.\n get<T>(key: string): T {\n return dataByKey.get(key) as T;\n },\n\n set<T>(key: string, value: T): void {\n const prev = dataByKey.get(key) as T;\n\n // Do nothing if no change.\n if (prev === value) return;\n\n dataByKey.set(key, value);\n notify(key, value, prev);\n },\n\n delete(key: string): void {\n dataByKey.delete(key);\n },\n\n setNoNotify<T>(key: string, value: T): void {\n dataByKey.set(key, value);\n },\n\n // Subscribe to changes of a specific key\n subscribe<T>(key: string, subscriber: Subscriber<T>): () => void {\n let subscribers = subscribersByKey.get(key);\n if (!subscribers) {\n subscribers = new Set();\n subscribersByKey.set(key, subscribers);\n }\n\n // Type coercion: we store Subscriber<unknown>\n subscribers.add(subscriber as Subscriber<unknown>);\n\n // Return unsubscribe function\n return () => {\n subscribers.delete(subscriber as Subscriber<unknown>);\n if (subscribers.size === 0) subscribersByKey.delete(key);\n };\n },\n } as const;\n}\n\nconst pubSubStore = createPubSubStore();\n\n/************************************************************************/\n/* Shared state implementation */\n/************************************************************************/\n\nconst STORAGE_KEY = \"state\";\n\n/** Options to configure a shared state. */\nexport type SharedStateOptions<T> = {\n lazyLoad?: boolean;\n} & StorageOptions<T>;\n\nlet stateKey = 0;\n\n/**\n * Create a new shared state object. Put this code at the top level scope:\n *\n * Example:\n * ```\n * const counterState = sharedState<number>(0);\n * ```\n */\nexport function sharedState<T>(\n defaultValue: T,\n options?: SharedStateOptions<T>,\n) {\n let readyResolve: () => void = () => {};\n\n const readyPromise = new Promise<void>((resolve) => {\n readyResolve = resolve;\n });\n\n const resolveReadyPromise = readyResolve;\n\n const pubSubKey = String(stateKey++);\n\n // Use max of 1 storage adapter per shared state.\n const storageAdapter = getStorageAdapter(\n options,\n SharedStateConfig.storeExpiryMs,\n );\n\n // Always set the default value first to avoid returning undefineds if that\n // is not part of T.\n pubSubStore.setNoNotify(pubSubKey, defaultValue);\n\n const lazyLoad = options?.lazyLoad;\n const lazy = lazyLoad !== undefined ? lazyLoad : SharedStateConfig.lazyLoad;\n\n const obj = {\n /** Allow users to await for the completion of data init. */\n readyPromise,\n\n lazy,\n\n initStarted: false,\n initDone: false,\n\n /** `subscribe` function required by useSyncExternalStore. */\n subscribe(subscriber: () => void): () => void {\n return pubSubStore.subscribe(pubSubKey, () => subscriber());\n },\n\n /** Returns true if there is a backing store. */\n hasStore(): boolean {\n return Boolean(storageAdapter);\n },\n\n /**\n * Set a value directly into the store. Does nothing if there is no\n * backing store.\n *\n * Warning: If you want to set the value properly, you should use\n * `setValue()` instead which also updates the in-memory copy.\n */\n async setInStore(value: T): Promise<void> {\n return await storageAdapter?.set(STORAGE_KEY, value);\n },\n\n /**\n * Get a value directly from the store. Returns undefined if there is no\n * backing store.\n */\n async getFromStore(): Promise<T | undefined> {\n return await storageAdapter?.get(STORAGE_KEY);\n },\n\n /**\n * Get the value of the shared state.\n * `getSnapshot` function — must return same ref if value unchanged.\n * Note that this would return the default value if data init from store is\n * not completed yet.\n */\n getSnapshot(): T {\n return pubSubStore.get(pubSubKey);\n },\n\n /** Set the value of the shared state. */\n setValue(next: SetStateAction<T>): void {\n if (typeof next === \"function\") {\n const prev = pubSubStore.get<T>(pubSubKey);\n next = (next as (p: T) => T)(prev);\n }\n\n pubSubStore.set(pubSubKey, next);\n void obj.setInStore(next);\n },\n\n /**\n * Remove the value of the shared state. Actually this just sets the value\n * back to the given default value.\n */\n delete() {\n pubSubStore.set(pubSubKey, defaultValue);\n void storageAdapter?.set(STORAGE_KEY, defaultValue);\n },\n\n /** Initial default handling. */\n async initDefaultValueOnce() {\n if (obj.initDone || obj.initStarted) return;\n // @ts-expect-error ts(2540) - Assign to readonly property.\n obj.initStarted = true;\n\n const stored = await obj.getFromStore();\n const value = stored !== undefined ? stored : defaultValue;\n\n pubSubStore.set(pubSubKey, value);\n\n // @ts-expect-error ts(2540) - Assign to readonly property.\n obj.initDone = true;\n resolveReadyPromise();\n },\n } as const;\n\n if (!lazy) {\n void obj.initDefaultValueOnce();\n }\n\n return obj;\n}\n\nexport type SharedState<T> = ReturnType<typeof sharedState<T>>;\n\n/**\n * React hook for subscribing to a key in the global store.\n *\n * Example:\n * ```\n * const [counter, setCounter] = useSharedState(counterState);\n * ```\n */\nexport function useSharedState<T>(\n state: SharedState<T>,\n): [T, Dispatch<SetStateAction<T>>] {\n void state.initDefaultValueOnce();\n\n const value = useSyncExternalStore(\n (onStoreChange) => state.subscribe(onStoreChange),\n () => state.getSnapshot(),\n // getServerSnapshot is needed to prevent SSR dev errors in nextjs.\n () => state.getSnapshot(),\n );\n\n return [value, state.setValue];\n}\n\n/**\n * Same as useSharedState(), but returns the value only.\n *\n * Example:\n * ```\n * const counter = useSharedStateValue(counterState);\n * ```\n */\nexport function useSharedStateValue<T>(state: SharedState<T>) {\n return useSharedState(state)[0];\n}\n\n/**\n * Same as useSharedState(), but returns the setter only.\n *\n * Example:\n * ```\n * const setCounter = useSharedStateSetter(counterState);\n * ```\n */\nexport function useSharedStateSetter<T>(state: SharedState<T>) {\n void state.initDefaultValueOnce();\n\n return state.setValue;\n}\n","/**\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 const adapter = createLocalStore(key, { defaultExpiryMs: expiryMs });\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(key, value);\n },\n\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const value = adapter.get<T>(key);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n adapter.delete(key);\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(key);\n },\n\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":"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","names":["sharedState_exports","__export","SharedStateConfig","configureSharedState","sharedState","useSharedState","useSharedStateSetter","useSharedStateValue","__toCommonJS","import_timeConstants","import_react","import_kvStore","import_localStore","IS_NOT_BROWSER","getStorageAdapter","options","defaultStoreExpiryMs","store","expiryMs","config","localStoreAdapter","kvStoreAdapter","key","isValid","adapter","value","keyPrefix","fullKey","SharedStateConfig","configureSharedState","config","createPubSubStore","dataByKey","subscribersByKey","notify","key","next","prev","subscribers","copy","subscriber","e","value","pubSubStore","STORAGE_KEY","stateKey","sharedState","defaultValue","options","readyResolve","readyPromise","resolve","resolveReadyPromise","pubSubKey","storageAdapter","getStorageAdapter","lazyLoad","lazy","obj","stored","useSharedState","state","onStoreChange","useSharedStateValue","useSharedStateSetter"]}
|
|
1
|
+
{"version":3,"sources":["/Users/choksheaklau/src/react-utils/dist/sharedState.min.cjs"],"names":[],"mappings":"AAAA,wIAAiD,oCAAiC,oCAAiC,sTAAiJ","file":"/Users/choksheaklau/src/react-utils/dist/sharedState.min.cjs"}
|
package/sharedState.min.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{a,b,c,d,e,f}from"./chunk-KILGR7YA.min.mjs";import"./chunk-VHMO75EY.min.mjs";import"./chunk-MWDH7YON.min.mjs";export{a as SharedStateConfig,b as configureSharedState,c as sharedState,d as useSharedState,f as useSharedStateSetter,e as useSharedStateValue};
|
|
2
2
|
//# sourceMappingURL=sharedState.min.mjs.map
|
package/sharedState.min.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sharedState.ts","../src/storage.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * The \"shared state\" is a React state that shares the same value across the\n * entire app. Users declare a shared state constant that can be reused across\n * multiple components with the same underlying value.\n *\n * Shared states provide persistence to local storage and/or indexed DB out of\n * the box, by using \"@choksheak/ts-utils\". Note that no matter if the shared\n * state uses persistence or not, it will always maintain a copy of the state\n * in memory. Persisted values can be configured with an automatic expiration\n * duration.\n *\n * This module is largely similar to the open source \"jotai\" npm library. You\n * can use shared states to replace \"jotai\" in your code, and optionally make\n * use of the persistence mechanism. A quick migration guide from jotai is:\n *\n * ```\n * atom() --> sharedState()\n * useAtom() --> useSharedState()\n * useAtomValue() --> useSharedStateValue()\n * useSetAtom() --> useSharedStateSetter()\n * ```\n *\n * Example:\n * ```\n * import { sharedState, useSharedState } from \"@choksheak/react-utils/sharedState\";\n *\n * // Create a new shared state in the top level scope.\n * // The first argument is the default value, which is required.\n * // The second argument is an options object, and is optional (defaults\n * // to storing in memory only without any persistence).\n * const usersState = sharedState(\n * [], { store: { persistTo: \"indexedDb\", key: \"users\" }}\n * );\n *\n * export const UsersComponent: React.FC = () => {\n * // Get both the value and the setter.\n * const [users, setUsers] = useSharedState(usersState);\n * ...\n * };\n *\n * export const ReadOnlyComponent: React.FC = () => {\n * // Get the value only.\n * const users = useSharedStateValue(usersState);\n * ...\n * };\n *\n * export const WriteOnlyComponent: React.FC = () => {\n * // Get the setter only.\n * const setUsers = useSharedStateSetter(usersState);\n * ...\n * };\n * ```\n */\n\nimport { MS_PER_DAY } from \"@choksheak/ts-utils/timeConstants\";\nimport { Dispatch, SetStateAction, useSyncExternalStore } from \"react\";\n\nimport { getStorageAdapter, StorageOptions } from \"./storage\";\n\n/************************************************************************/\n/* Global config */\n/************************************************************************/\n\n/**\n * These values are configurable by the user at any time.\n */\nexport const SharedStateConfig = {\n /**\n * Default duration for storage expiration in milliseconds. Initial value\n * is 30 days, but can be changed to anything.\n */\n storeExpiryMs: 30 * MS_PER_DAY,\n\n /**\n * True to load from storage only on mount, false (default) to load in\n * the top level scope when the shared state is defined.\n */\n lazyLoad: false,\n};\n\nexport type SharedStateConfig = typeof SharedStateConfig;\n\n/** Convenience function to update global defaults. */\nexport function configureSharedState(config: Partial<SharedStateConfig>) {\n Object.assign(SharedStateConfig, config);\n}\n\n/************************************************************************/\n/* Pub-sub store\n/************************************************************************/\n\ntype Subscriber<T> = (next: T, prev: T) => void;\n\nfunction createPubSubStore() {\n const dataByKey = new Map<string, unknown>();\n const subscribersByKey = new Map<string, Set<Subscriber<unknown>>>();\n\n function notify<T>(key: string, next: T, prev: T): void {\n const subscribers = subscribersByKey.get(key);\n if (!subscribers) return;\n\n // Make copy to protect against mutation during iteration.\n const copy = Array.from(subscribers.values());\n for (const subscriber of copy) {\n try {\n subscriber(next, prev);\n } catch (e) {\n console.error(`Error invoking subscriber:`, e);\n }\n }\n }\n\n return {\n // This could be undefined if T includes undefined, else it should never\n // return undefined because the user has to always specify the default value.\n get<T>(key: string): T {\n return dataByKey.get(key) as T;\n },\n\n set<T>(key: string, value: T): void {\n const prev = dataByKey.get(key) as T;\n\n // Do nothing if no change.\n if (prev === value) return;\n\n dataByKey.set(key, value);\n notify(key, value, prev);\n },\n\n delete(key: string): void {\n dataByKey.delete(key);\n },\n\n setNoNotify<T>(key: string, value: T): void {\n dataByKey.set(key, value);\n },\n\n // Subscribe to changes of a specific key\n subscribe<T>(key: string, subscriber: Subscriber<T>): () => void {\n let subscribers = subscribersByKey.get(key);\n if (!subscribers) {\n subscribers = new Set();\n subscribersByKey.set(key, subscribers);\n }\n\n // Type coercion: we store Subscriber<unknown>\n subscribers.add(subscriber as Subscriber<unknown>);\n\n // Return unsubscribe function\n return () => {\n subscribers.delete(subscriber as Subscriber<unknown>);\n if (subscribers.size === 0) subscribersByKey.delete(key);\n };\n },\n } as const;\n}\n\nconst pubSubStore = createPubSubStore();\n\n/************************************************************************/\n/* Shared state implementation */\n/************************************************************************/\n\nconst STORAGE_KEY = \"state\";\n\n/** Options to configure a shared state. */\nexport type SharedStateOptions<T> = {\n lazyLoad?: boolean;\n} & StorageOptions<T>;\n\nlet stateKey = 0;\n\n/**\n * Create a new shared state object. Put this code at the top level scope:\n *\n * Example:\n * ```\n * const counterState = sharedState<number>(0);\n * ```\n */\nexport function sharedState<T>(\n defaultValue: T,\n options?: SharedStateOptions<T>,\n) {\n let readyResolve: () => void = () => {};\n\n const readyPromise = new Promise<void>((resolve) => {\n readyResolve = resolve;\n });\n\n const resolveReadyPromise = readyResolve;\n\n const pubSubKey = String(stateKey++);\n\n // Use max of 1 storage adapter per shared state.\n const storageAdapter = getStorageAdapter(\n options,\n SharedStateConfig.storeExpiryMs,\n );\n\n // Always set the default value first to avoid returning undefineds if that\n // is not part of T.\n pubSubStore.setNoNotify(pubSubKey, defaultValue);\n\n const lazyLoad = options?.lazyLoad;\n const lazy = lazyLoad !== undefined ? lazyLoad : SharedStateConfig.lazyLoad;\n\n const obj = {\n /** Allow users to await for the completion of data init. */\n readyPromise,\n\n lazy,\n\n initStarted: false,\n initDone: false,\n\n /** `subscribe` function required by useSyncExternalStore. */\n subscribe(subscriber: () => void): () => void {\n return pubSubStore.subscribe(pubSubKey, () => subscriber());\n },\n\n /** Returns true if there is a backing store. */\n hasStore(): boolean {\n return Boolean(storageAdapter);\n },\n\n /**\n * Set a value directly into the store. Does nothing if there is no\n * backing store.\n *\n * Warning: If you want to set the value properly, you should use\n * `setValue()` instead which also updates the in-memory copy.\n */\n async setInStore(value: T): Promise<void> {\n return await storageAdapter?.set(STORAGE_KEY, value);\n },\n\n /**\n * Get a value directly from the store. Returns undefined if there is no\n * backing store.\n */\n async getFromStore(): Promise<T | undefined> {\n return await storageAdapter?.get(STORAGE_KEY);\n },\n\n /**\n * Get the value of the shared state.\n * `getSnapshot` function — must return same ref if value unchanged.\n * Note that this would return the default value if data init from store is\n * not completed yet.\n */\n getSnapshot(): T {\n return pubSubStore.get(pubSubKey);\n },\n\n /** Set the value of the shared state. */\n setValue(next: SetStateAction<T>): void {\n if (typeof next === \"function\") {\n const prev = pubSubStore.get<T>(pubSubKey);\n next = (next as (p: T) => T)(prev);\n }\n\n pubSubStore.set(pubSubKey, next);\n void obj.setInStore(next);\n },\n\n /**\n * Remove the value of the shared state. Actually this just sets the value\n * back to the given default value.\n */\n delete() {\n pubSubStore.set(pubSubKey, defaultValue);\n void storageAdapter?.set(STORAGE_KEY, defaultValue);\n },\n\n /** Initial default handling. */\n async initDefaultValueOnce() {\n if (obj.initDone || obj.initStarted) return;\n // @ts-expect-error ts(2540) - Assign to readonly property.\n obj.initStarted = true;\n\n const stored = await obj.getFromStore();\n const value = stored !== undefined ? stored : defaultValue;\n\n pubSubStore.set(pubSubKey, value);\n\n // @ts-expect-error ts(2540) - Assign to readonly property.\n obj.initDone = true;\n resolveReadyPromise();\n },\n } as const;\n\n if (!lazy) {\n void obj.initDefaultValueOnce();\n }\n\n return obj;\n}\n\nexport type SharedState<T> = ReturnType<typeof sharedState<T>>;\n\n/**\n * React hook for subscribing to a key in the global store.\n *\n * Example:\n * ```\n * const [counter, setCounter] = useSharedState(counterState);\n * ```\n */\nexport function useSharedState<T>(\n state: SharedState<T>,\n): [T, Dispatch<SetStateAction<T>>] {\n void state.initDefaultValueOnce();\n\n const value = useSyncExternalStore(\n (onStoreChange) => state.subscribe(onStoreChange),\n () => state.getSnapshot(),\n // getServerSnapshot is needed to prevent SSR dev errors in nextjs.\n () => state.getSnapshot(),\n );\n\n return [value, state.setValue];\n}\n\n/**\n * Same as useSharedState(), but returns the value only.\n *\n * Example:\n * ```\n * const counter = useSharedStateValue(counterState);\n * ```\n */\nexport function useSharedStateValue<T>(state: SharedState<T>) {\n return useSharedState(state)[0];\n}\n\n/**\n * Same as useSharedState(), but returns the setter only.\n *\n * Example:\n * ```\n * const setCounter = useSharedStateSetter(counterState);\n * ```\n */\nexport function useSharedStateSetter<T>(state: SharedState<T>) {\n void state.initDefaultValueOnce();\n\n return state.setValue;\n}\n","/**\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 const adapter = createLocalStore(key, { defaultExpiryMs: expiryMs });\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(key, value);\n },\n\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const value = adapter.get<T>(key);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n adapter.delete(key);\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(key);\n },\n\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":"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","names":["MS_PER_DAY","useSyncExternalStore","kvStore","createLocalStore","IS_NOT_BROWSER","getStorageAdapter","options","defaultStoreExpiryMs","store","expiryMs","config","localStoreAdapter","kvStoreAdapter","key","isValid","adapter","value","keyPrefix","fullKey","SharedStateConfig","MS_PER_DAY","configureSharedState","config","createPubSubStore","dataByKey","subscribersByKey","notify","key","next","prev","subscribers","copy","subscriber","e","value","pubSubStore","STORAGE_KEY","stateKey","sharedState","defaultValue","options","readyResolve","readyPromise","resolve","resolveReadyPromise","pubSubKey","storageAdapter","getStorageAdapter","lazyLoad","lazy","obj","stored","useSharedState","state","useSyncExternalStore","onStoreChange","useSharedStateValue","useSharedStateSetter"]}
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|