@choksheak/react-utils 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NoSSR.cjs +30 -7
- 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 +0 -2
- package/index.cjs +979 -43
- 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 +916 -25
- package/package.json +1 -41
- package/sharedQuery.cjs +938 -10
- package/sharedQuery.d.cts +21 -20
- package/sharedQuery.d.ts +21 -20
- 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 +906 -10
- package/sharedState.cjs +326 -15
- 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 +291 -10
- package/storage.cjs +129 -10
- 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 +98 -6
- package/stringify.cjs +57 -6
- 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 +30 -4
- package/useDeepMemo.cjs +40 -6
- 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 +13 -4
- package/chunk-4235I4VO.mjs +0 -34
- package/chunk-433OAJVP.min.cjs +0 -2
- package/chunk-433OAJVP.min.cjs.map +0 -1
- package/chunk-4J7TN5JN.mjs +0 -17
- package/chunk-5PDGU37E.cjs +0 -104
- package/chunk-7D2YNZO3.cjs +0 -577
- package/chunk-BQIRLDQC.min.mjs +0 -2
- package/chunk-BQIRLDQC.min.mjs.map +0 -1
- package/chunk-CYTO5EZE.cjs +0 -34
- package/chunk-FXCYHS3L.mjs +0 -577
- package/chunk-HRE7YPUJ.min.mjs +0 -2
- package/chunk-HRE7YPUJ.min.mjs.map +0 -1
- package/chunk-IS3BZTWE.cjs +0 -35
- package/chunk-JOHZV3FD.min.cjs +0 -2
- package/chunk-JOHZV3FD.min.cjs.map +0 -1
- package/chunk-KGN4HQPP.min.cjs +0 -2
- package/chunk-KGN4HQPP.min.cjs.map +0 -1
- package/chunk-NGGNAAHA.cjs +0 -203
- package/chunk-NL4FU2MJ.min.mjs +0 -2
- package/chunk-NL4FU2MJ.min.mjs.map +0 -1
- package/chunk-PHLY3LR4.mjs +0 -104
- package/chunk-R7POPVJR.mjs +0 -35
- package/chunk-RP2TWHFU.min.cjs +0 -2
- package/chunk-RP2TWHFU.min.cjs.map +0 -1
- package/chunk-TI3FMEYP.min.mjs +0 -2
- package/chunk-TI3FMEYP.min.mjs.map +0 -1
- package/chunk-UFJQLQFI.min.cjs +0 -2
- package/chunk-UFJQLQFI.min.cjs.map +0 -1
- package/chunk-VHMO75EY.min.mjs +0 -2
- package/chunk-VHMO75EY.min.mjs.map +0 -1
- package/chunk-WXLUEDBO.cjs +0 -17
- package/chunk-XRHQCN2J.min.mjs +0 -2
- package/chunk-XRHQCN2J.min.mjs.map +0 -1
- package/chunk-YHU4KW2D.mjs +0 -203
- package/chunk-ZCDXPV3A.min.cjs +0 -2
- package/chunk-ZCDXPV3A.min.cjs.map +0 -1
- package/dist-O6NNX4Y3.min.mjs +0 -2
- package/dist-O6NNX4Y3.min.mjs.map +0 -1
- package/dist-SEGTJ72R.min.cjs +0 -2
- package/dist-SEGTJ72R.min.cjs.map +0 -1
- package/dist-UKP7SPWZ.cjs +0 -545
- package/dist-YXYQDOH5.mjs +0 -545
- package/magic-string.es-5QZEPJXJ.min.mjs +0 -14
- package/magic-string.es-5QZEPJXJ.min.mjs.map +0 -1
- package/magic-string.es-EREYSDLL.mjs +0 -1308
- package/magic-string.es-FXUUD55Y.min.cjs +0 -14
- package/magic-string.es-FXUUD55Y.min.cjs.map +0 -1
- package/magic-string.es-HC5PDAU3.cjs +0 -1308
package/chunk-7D2YNZO3.cjs
DELETED
|
@@ -1,577 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var _chunkNGGNAAHAcjs = require('./chunk-NGGNAAHA.cjs');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var _chunkCYTO5EZEcjs = require('./chunk-CYTO5EZE.cjs');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
var _chunkWXLUEDBOcjs = require('./chunk-WXLUEDBO.cjs');
|
|
11
|
-
|
|
12
|
-
// src/sharedQuery.ts
|
|
13
|
-
var _http = require('@choksheak/ts-utils/http');
|
|
14
|
-
var _nonNil = require('@choksheak/ts-utils/nonNil');
|
|
15
|
-
var _objectsizeof = require('object-sizeof'); var _objectsizeof2 = _interopRequireDefault(_objectsizeof);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
var _react = require('react');
|
|
23
|
-
var _xxhashjs = require('xxhashjs'); var _xxhashjs2 = _interopRequireDefault(_xxhashjs);
|
|
24
|
-
var SharedQueryConfig = {
|
|
25
|
-
/** Refetch on every page load. */
|
|
26
|
-
staleMs: 0,
|
|
27
|
-
/** Keep in cache for a long time. */
|
|
28
|
-
expiryMs: 30 * 864e5,
|
|
29
|
-
/** Always refetch automatically if the data is stale. */
|
|
30
|
-
refetchOnStale: true,
|
|
31
|
-
/** No default persistence configured. */
|
|
32
|
-
persistTo: void 0,
|
|
33
|
-
/** 100 is not too large, but please tweak accordingly. */
|
|
34
|
-
maxSize: 100,
|
|
35
|
-
/** 100kb limit before discarding old records. */
|
|
36
|
-
maxBytes: 1e5,
|
|
37
|
-
/** Default to log to console. */
|
|
38
|
-
log: (...args) => console.log("[sharedQuery]", ...args)
|
|
39
|
-
};
|
|
40
|
-
function configureSharedQuery(config) {
|
|
41
|
-
Object.assign(SharedQueryConfig, config);
|
|
42
|
-
}
|
|
43
|
-
var seenQueryNames = /* @__PURE__ */ new Set();
|
|
44
|
-
function sharedQuery(options) {
|
|
45
|
-
const url = options.url || "";
|
|
46
|
-
const queryName = options.queryName || url;
|
|
47
|
-
if (!queryName) {
|
|
48
|
-
throw new Error(`Either queryName or url must be specified.`);
|
|
49
|
-
}
|
|
50
|
-
if (seenQueryNames.has(queryName)) {
|
|
51
|
-
console.warn(`Duplicate shared query name "${queryName}"`);
|
|
52
|
-
}
|
|
53
|
-
seenQueryNames.add(queryName);
|
|
54
|
-
const inflightQueries = /* @__PURE__ */ new Map();
|
|
55
|
-
const mountedKeys = /* @__PURE__ */ new Map();
|
|
56
|
-
let queryFn;
|
|
57
|
-
if (options.queryFn) {
|
|
58
|
-
queryFn = options.queryFn;
|
|
59
|
-
} else if (url) {
|
|
60
|
-
const fetcher = _http.http.use(_http.retries.call(void 0, ));
|
|
61
|
-
queryFn = async (...args) => {
|
|
62
|
-
let params = "";
|
|
63
|
-
const firstArg = _optionalChain([args, 'optionalAccess', _ => _[0]]);
|
|
64
|
-
if (firstArg) {
|
|
65
|
-
if (typeof firstArg === "string") {
|
|
66
|
-
params = firstArg;
|
|
67
|
-
} else if (typeof firstArg === "object") {
|
|
68
|
-
const entries = [];
|
|
69
|
-
for (const [k, v] of Object.entries(firstArg)) {
|
|
70
|
-
if (v === void 0) continue;
|
|
71
|
-
if (Array.isArray(v)) {
|
|
72
|
-
for (const item of v) {
|
|
73
|
-
if (item === void 0) continue;
|
|
74
|
-
entries.push([k, String(item)]);
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
entries.push([k, String(v)]);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
params = new URLSearchParams(entries).toString();
|
|
81
|
-
}
|
|
82
|
-
if (params) {
|
|
83
|
-
if (url.includes("?")) {
|
|
84
|
-
params = "&" + params;
|
|
85
|
-
} else {
|
|
86
|
-
params = "?" + params;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const response = await fetcher.get(url + params);
|
|
91
|
-
return await response.json();
|
|
92
|
-
};
|
|
93
|
-
} else {
|
|
94
|
-
throw new Error(`Either queryFn or url must be specified`);
|
|
95
|
-
}
|
|
96
|
-
const refetchFn = options.refetchFn;
|
|
97
|
-
const staleMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.staleMs]), () => ( SharedQueryConfig.staleMs));
|
|
98
|
-
const expiryMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.expiryMs]), () => ( SharedQueryConfig.expiryMs));
|
|
99
|
-
const refetchOnStale = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.refetchOnStale]), () => ( SharedQueryConfig.refetchOnStale));
|
|
100
|
-
const store = options.store;
|
|
101
|
-
if (store) {
|
|
102
|
-
if ("persistTo" in store && store.isValid) {
|
|
103
|
-
const isValid = store.isValid;
|
|
104
|
-
options = {
|
|
105
|
-
...options,
|
|
106
|
-
store: {
|
|
107
|
-
...store,
|
|
108
|
-
isValid: (u) => {
|
|
109
|
-
if (!u || typeof u !== "object") {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
for (const v of Object.values(u)) {
|
|
113
|
-
if (!v || typeof v !== "object" || !("data" in v) || !("dataUpdatedMs" in v) || !("lastUpdatedMs" in v) || typeof v.dataUpdatedMs !== "number" || typeof v.lastUpdatedMs !== "number" || !isValid(v.data)) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
const persistTo = _nullishCoalesce(options.persistTo, () => ( SharedQueryConfig.persistTo));
|
|
124
|
-
if (persistTo) {
|
|
125
|
-
options = {
|
|
126
|
-
...options,
|
|
127
|
-
store: {
|
|
128
|
-
persistTo,
|
|
129
|
-
key: queryName,
|
|
130
|
-
expiryMs
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const maxSize = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.maxSize]), () => ( SharedQueryConfig.maxSize));
|
|
136
|
-
const maxBytes = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _6 => _6.maxBytes]), () => ( SharedQueryConfig.maxBytes));
|
|
137
|
-
const keepLastNonEmptyData = Boolean(_optionalChain([options, 'optionalAccess', _7 => _7.keepLastNonEmptyData]));
|
|
138
|
-
const log = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _8 => _8.log]), () => ( SharedQueryConfig.log));
|
|
139
|
-
const queryState = _chunkNGGNAAHAcjs.sharedState.call(void 0,
|
|
140
|
-
{},
|
|
141
|
-
// defaultValue
|
|
142
|
-
options
|
|
143
|
-
);
|
|
144
|
-
function isStale(dataUpdatedMs) {
|
|
145
|
-
if (staleMs === 0) return true;
|
|
146
|
-
const ageMs = Date.now() - dataUpdatedMs;
|
|
147
|
-
return ageMs > staleMs;
|
|
148
|
-
}
|
|
149
|
-
function isExpired(dataUpdatedMs) {
|
|
150
|
-
if (expiryMs === 0) return false;
|
|
151
|
-
const ageMs = Date.now() - dataUpdatedMs;
|
|
152
|
-
return ageMs > expiryMs;
|
|
153
|
-
}
|
|
154
|
-
function enforceSizeLimit() {
|
|
155
|
-
if (!maxSize && !maxBytes) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const oldState = queryState.getSnapshot();
|
|
159
|
-
const oldSize = Object.keys(oldState).length;
|
|
160
|
-
if (oldSize <= 1) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const oldByteSize = _objectsizeof2.default.call(void 0, oldState);
|
|
164
|
-
let numToCut = maxSize ? oldSize - maxSize : 0;
|
|
165
|
-
let bytesToCut = maxBytes ? oldByteSize - maxBytes : 0;
|
|
166
|
-
if (numToCut <= 0 && bytesToCut <= 0) {
|
|
167
|
-
log(
|
|
168
|
-
`No need to trim data for ${queryName}: size=${oldSize} (limit=${maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${maxBytes.toLocaleString()})`
|
|
169
|
-
);
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
log(
|
|
173
|
-
`Need to trim ${queryName}: numToCut=${numToCut}, bytesToCut=${bytesToCut}`
|
|
174
|
-
);
|
|
175
|
-
const newState = { ...oldState };
|
|
176
|
-
let needUpdate = false;
|
|
177
|
-
const deleteKeyIfNotMounted = (key, expired) => {
|
|
178
|
-
if (mountedKeys.has(key)) {
|
|
179
|
-
log(`Cannot clean up ${key} as it is mounted`);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const byteSize = _objectsizeof2.default.call(void 0, key) + _objectsizeof2.default.call(void 0, newState[key]);
|
|
183
|
-
log(
|
|
184
|
-
`Cleaning up unmounted${expired ? ", expired" : ""} ${key} (byteSize=${byteSize.toLocaleString()})`
|
|
185
|
-
);
|
|
186
|
-
numToCut--;
|
|
187
|
-
bytesToCut -= byteSize;
|
|
188
|
-
delete newState[key];
|
|
189
|
-
needUpdate = true;
|
|
190
|
-
};
|
|
191
|
-
let entriesByTimeAscending = Object.entries(newState).sort(
|
|
192
|
-
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
193
|
-
);
|
|
194
|
-
for (const [key] of entriesByTimeAscending) {
|
|
195
|
-
if (!isExpired(newState[key].lastUpdatedMs)) {
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
deleteKeyIfNotMounted(key, true);
|
|
199
|
-
}
|
|
200
|
-
if (numToCut > 0 || bytesToCut > 0) {
|
|
201
|
-
if (needUpdate) {
|
|
202
|
-
entriesByTimeAscending = Object.entries(newState).sort(
|
|
203
|
-
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
for (const [key] of entriesByTimeAscending) {
|
|
207
|
-
deleteKeyIfNotMounted(key, false);
|
|
208
|
-
if (numToCut <= 0 && bytesToCut <= 0) {
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (!needUpdate) {
|
|
214
|
-
log(
|
|
215
|
-
`No trimmable entries found for ${queryName}: size=${oldSize} (limit=${maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${maxBytes.toLocaleString()})`
|
|
216
|
-
);
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
queryState.setValue(newState);
|
|
220
|
-
log(
|
|
221
|
-
`Trimmed data for ${queryName}: size=[${oldSize} -> ${Object.keys(newState).length}] (limit=${maxSize}), byteSize=[${oldByteSize.toLocaleString()} -> ${_objectsizeof2.default.call(void 0, newState).toLocaleString()}] (limit=${maxBytes.toLocaleString()})`
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
function setData(queryKey, data, dataUpdatedMs = Date.now()) {
|
|
225
|
-
const entry = {
|
|
226
|
-
lastUpdatedMs: Date.now(),
|
|
227
|
-
loading: false,
|
|
228
|
-
data,
|
|
229
|
-
dataUpdatedMs
|
|
230
|
-
};
|
|
231
|
-
queryState.setValue((prev) => ({ ...prev, [queryKey]: entry }));
|
|
232
|
-
enforceSizeLimit();
|
|
233
|
-
}
|
|
234
|
-
async function startFetching(queryKey, queryType, args) {
|
|
235
|
-
log(`Start fetching ${queryKey}, queryType=${queryType}`);
|
|
236
|
-
try {
|
|
237
|
-
const data = await (queryType === "refetch" && refetchFn ? refetchFn(...args) : queryFn(...args));
|
|
238
|
-
log(`Successfully fetched ${queryKey}`);
|
|
239
|
-
setData(queryKey, data, Date.now());
|
|
240
|
-
return data;
|
|
241
|
-
} catch (e) {
|
|
242
|
-
log(`Failed to fetch ${queryKey} for queryType=${queryType}: ${e}`);
|
|
243
|
-
throw e;
|
|
244
|
-
} finally {
|
|
245
|
-
inflightQueries.delete(queryKey);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
function dedupedFetch(queryKey, queryType, ...args) {
|
|
249
|
-
const inflightQuery = inflightQueries.get(queryKey);
|
|
250
|
-
if (inflightQuery) {
|
|
251
|
-
log(
|
|
252
|
-
`Deduplicating inflight fetch for ${queryKey}, queryType=${queryType}`
|
|
253
|
-
);
|
|
254
|
-
return inflightQuery.promise;
|
|
255
|
-
}
|
|
256
|
-
const promise = startFetching(queryKey, queryType, args);
|
|
257
|
-
const abortController = new AbortController();
|
|
258
|
-
inflightQueries.set(queryKey, { promise, abortController });
|
|
259
|
-
return promise;
|
|
260
|
-
}
|
|
261
|
-
const obj = {
|
|
262
|
-
queryName,
|
|
263
|
-
queryFn,
|
|
264
|
-
refetchFn,
|
|
265
|
-
expiryMs,
|
|
266
|
-
staleMs,
|
|
267
|
-
refetchOnStale,
|
|
268
|
-
maxSize,
|
|
269
|
-
maxBytes,
|
|
270
|
-
keepLastNonEmptyData,
|
|
271
|
-
log,
|
|
272
|
-
queryState,
|
|
273
|
-
/** Returns a key to identify requests based on the given args. */
|
|
274
|
-
getQueryKey(args) {
|
|
275
|
-
let s = _chunkCYTO5EZEcjs.stringifyDeterministicForKeys.call(void 0, args);
|
|
276
|
-
if (s.length > 30) {
|
|
277
|
-
s = _xxhashjs2.default.h32(s, 39406).toString(16).slice(2);
|
|
278
|
-
}
|
|
279
|
-
return queryName + ":" + s;
|
|
280
|
-
},
|
|
281
|
-
/**
|
|
282
|
-
* Get the AbortController to abort the inflight query (if any).
|
|
283
|
-
*
|
|
284
|
-
* Note that once you get the controller, you can also get the signal easily
|
|
285
|
-
* using `controller.signal`. So if you need both the controller and the
|
|
286
|
-
* signal, just use this function.
|
|
287
|
-
*/
|
|
288
|
-
getAbortController(args) {
|
|
289
|
-
const queryKey = obj.getQueryKey(args);
|
|
290
|
-
return obj.getAbortControllerByKey(queryKey);
|
|
291
|
-
},
|
|
292
|
-
getAbortControllerByKey(queryKey) {
|
|
293
|
-
return _nullishCoalesce(_optionalChain([inflightQueries, 'access', _9 => _9.get, 'call', _10 => _10(queryKey), 'optionalAccess', _11 => _11.abortController]), () => ( null));
|
|
294
|
-
},
|
|
295
|
-
/**
|
|
296
|
-
* Get the AbortSignal to check for query abortions.
|
|
297
|
-
*
|
|
298
|
-
* Example using fetch:
|
|
299
|
-
* ```
|
|
300
|
-
* const getUserQuery = sharedQuery({
|
|
301
|
-
* queryName: "getUser",
|
|
302
|
-
* queryFn: (userId: string) => {
|
|
303
|
-
* // Get the signal for this current execution.
|
|
304
|
-
* const signal = getUserQuery.getAbortSignal([userId]);
|
|
305
|
-
*
|
|
306
|
-
* // Pass the signal to fetch so that it can be aborted.
|
|
307
|
-
* const response = await fetch(`/users/${userId}`, { signal });
|
|
308
|
-
*
|
|
309
|
-
* // Check for errors.
|
|
310
|
-
* if (!response.ok) {
|
|
311
|
-
* throw new Error(response.statusText);
|
|
312
|
-
* }
|
|
313
|
-
*
|
|
314
|
-
* // Return the data.
|
|
315
|
-
* return await response.json();
|
|
316
|
-
* },
|
|
317
|
-
* });
|
|
318
|
-
* ```
|
|
319
|
-
*
|
|
320
|
-
* Example using `http.ts`:
|
|
321
|
-
* ```
|
|
322
|
-
* const getUserQuery = sharedQuery({
|
|
323
|
-
* queryName: "getUser",
|
|
324
|
-
* queryFn: (userId: string) => {
|
|
325
|
-
* // Get the signal for this current execution.
|
|
326
|
-
* const signal = getUserQuery.getAbortSignal([userId]);
|
|
327
|
-
*
|
|
328
|
-
* // Pass the signal to fetch so that it can be aborted.
|
|
329
|
-
* const response = await http.get(`/users/${userId}`, { signal });
|
|
330
|
-
* return await response.json();
|
|
331
|
-
* },
|
|
332
|
-
* });
|
|
333
|
-
* ```
|
|
334
|
-
*/
|
|
335
|
-
getAbortSignal(args) {
|
|
336
|
-
const queryKey = obj.getQueryKey(args);
|
|
337
|
-
return obj.getAbortSignalByKey(queryKey);
|
|
338
|
-
},
|
|
339
|
-
getAbortSignalByKey(queryKey) {
|
|
340
|
-
return _nullishCoalesce(_optionalChain([obj, 'access', _12 => _12.getAbortControllerByKey, 'call', _13 => _13(queryKey), 'optionalAccess', _14 => _14.signal]), () => ( null));
|
|
341
|
-
},
|
|
342
|
-
/** For cached data, we need to return the correct timestamps as well. */
|
|
343
|
-
async getCachedOrFetch(...args) {
|
|
344
|
-
const startMs = Date.now();
|
|
345
|
-
await queryState.readyPromise;
|
|
346
|
-
const waitedMs = Date.now() - startMs;
|
|
347
|
-
const queryKey = obj.getQueryKey(args);
|
|
348
|
-
const cached = _optionalChain([queryState, 'access', _15 => _15.getSnapshot, 'call', _16 => _16(), 'optionalAccess', _17 => _17[queryKey]]);
|
|
349
|
-
if (waitedMs) {
|
|
350
|
-
log(`${queryKey}: Waited for ${waitedMs}ms before data is ready`);
|
|
351
|
-
}
|
|
352
|
-
if (_optionalChain([cached, 'optionalAccess', _18 => _18.data]) && !isExpired(_nullishCoalesce(cached.dataUpdatedMs, () => ( 0)))) {
|
|
353
|
-
if (!isStale(_nullishCoalesce(cached.dataUpdatedMs, () => ( 0)))) {
|
|
354
|
-
log(`Return fresh data ${queryKey} from cache without fetching`);
|
|
355
|
-
return cached;
|
|
356
|
-
}
|
|
357
|
-
if (refetchOnStale) {
|
|
358
|
-
log(`refetchOnStale for ${queryKey}`);
|
|
359
|
-
void dedupedFetch(queryKey, "query", ...args);
|
|
360
|
-
}
|
|
361
|
-
log(`Returning stale data for ${queryKey}`);
|
|
362
|
-
return cached;
|
|
363
|
-
}
|
|
364
|
-
const data = await dedupedFetch(queryKey, "query", ...args);
|
|
365
|
-
const now = Date.now();
|
|
366
|
-
return {
|
|
367
|
-
// Don't keep old error.
|
|
368
|
-
lastUpdatedMs: now,
|
|
369
|
-
loading: false,
|
|
370
|
-
data,
|
|
371
|
-
dataUpdatedMs: now
|
|
372
|
-
};
|
|
373
|
-
},
|
|
374
|
-
/** Get the entire stored entry for a query key. */
|
|
375
|
-
getQueryValue(queryKey) {
|
|
376
|
-
return _optionalChain([queryState, 'access', _19 => _19.getSnapshot, 'call', _20 => _20(), 'optionalAccess', _21 => _21[queryKey]]);
|
|
377
|
-
},
|
|
378
|
-
/** Get the current stored data for a query key. */
|
|
379
|
-
getData(queryKey) {
|
|
380
|
-
const stateValue = _optionalChain([queryState, 'access', _22 => _22.getSnapshot, 'call', _23 => _23(), 'optionalAccess', _24 => _24[queryKey]]);
|
|
381
|
-
if (_optionalChain([stateValue, 'optionalAccess', _25 => _25.lastUpdatedMs])) {
|
|
382
|
-
if (isExpired(stateValue.lastUpdatedMs)) {
|
|
383
|
-
obj.deleteData(queryKey);
|
|
384
|
-
return void 0;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
return _optionalChain([stateValue, 'optionalAccess', _26 => _26.data]);
|
|
388
|
-
},
|
|
389
|
-
/** Set the data directly if the user obtained it from somewhere else. */
|
|
390
|
-
setData,
|
|
391
|
-
/**
|
|
392
|
-
* Do a new fetch even when the data is already cached, but don't fetch if
|
|
393
|
-
* another fetch is already inflight.
|
|
394
|
-
*/
|
|
395
|
-
async updateFromSource(...args) {
|
|
396
|
-
const key = obj.getQueryKey(args);
|
|
397
|
-
return await dedupedFetch(key, "query", ...args);
|
|
398
|
-
},
|
|
399
|
-
/**
|
|
400
|
-
* Perform an explicit refetch. If `options.refetchFn` was not specified,
|
|
401
|
-
* then this would be identical to calling `obj.updateFromSource()`.
|
|
402
|
-
*/
|
|
403
|
-
async refetch(...args) {
|
|
404
|
-
const key = obj.getQueryKey(args);
|
|
405
|
-
return await dedupedFetch(key, "refetch", ...args);
|
|
406
|
-
},
|
|
407
|
-
/** Delete the cached data for one set of arguments. */
|
|
408
|
-
deleteData(queryKey) {
|
|
409
|
-
const record = queryState.getSnapshot();
|
|
410
|
-
const clone = { ...record };
|
|
411
|
-
delete clone[queryKey];
|
|
412
|
-
queryState.setValue(clone);
|
|
413
|
-
const inflight = inflightQueries.get(queryKey);
|
|
414
|
-
if (inflight) {
|
|
415
|
-
inflightQueries.delete(queryKey);
|
|
416
|
-
inflight.abortController.abort("Deleted");
|
|
417
|
-
}
|
|
418
|
-
},
|
|
419
|
-
/** Delete all currently cached data & all inflight promises. */
|
|
420
|
-
clear() {
|
|
421
|
-
queryState.delete();
|
|
422
|
-
for (const { abortController } of Array.from(inflightQueries.values())) {
|
|
423
|
-
abortController.abort("Cleared");
|
|
424
|
-
}
|
|
425
|
-
inflightQueries.clear();
|
|
426
|
-
},
|
|
427
|
-
/** Keep track of mounted keys. */
|
|
428
|
-
mount(queryKey) {
|
|
429
|
-
mountedKeys.set(queryKey, (_nullishCoalesce(mountedKeys.get(queryKey), () => ( 0))) + 1);
|
|
430
|
-
},
|
|
431
|
-
/** Clean up mounted keys. */
|
|
432
|
-
unmount(queryKey) {
|
|
433
|
-
const count = mountedKeys.get(queryKey);
|
|
434
|
-
if (count === 1) {
|
|
435
|
-
mountedKeys.delete(queryKey);
|
|
436
|
-
} else {
|
|
437
|
-
mountedKeys.set(queryKey, (_nullishCoalesce(count, () => ( 0))) - 1);
|
|
438
|
-
}
|
|
439
|
-
},
|
|
440
|
-
/**
|
|
441
|
-
* Discard the oldest entries if the size exceeds the limit. The last
|
|
442
|
-
* remaining record cannot be deleted no matter what the limit is.
|
|
443
|
-
*/
|
|
444
|
-
enforceSizeLimit
|
|
445
|
-
};
|
|
446
|
-
return obj;
|
|
447
|
-
}
|
|
448
|
-
var DEFAULT_QUERY_STATE_ENTRY = {
|
|
449
|
-
lastUpdatedMs: 0,
|
|
450
|
-
loading: true
|
|
451
|
-
};
|
|
452
|
-
function useSharedQuery(query, ...args) {
|
|
453
|
-
const stableArgs = _chunkWXLUEDBOcjs.useDeepMemo.call(void 0, args);
|
|
454
|
-
const [queryState, setQueryState] = _chunkNGGNAAHAcjs.useSharedState.call(void 0, query.queryState);
|
|
455
|
-
const isMounted = _react.useRef.call(void 0, true);
|
|
456
|
-
const queryKey = _react.useMemo.call(void 0,
|
|
457
|
-
() => query.getQueryKey(stableArgs),
|
|
458
|
-
[query, stableArgs]
|
|
459
|
-
);
|
|
460
|
-
const queryStateValue = _nullishCoalesce(queryState[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY));
|
|
461
|
-
const setQueryStateValue = _react.useCallback.call(void 0,
|
|
462
|
-
(next) => {
|
|
463
|
-
setQueryState((prev) => {
|
|
464
|
-
const clone = { ...prev };
|
|
465
|
-
clone[queryKey] = typeof next === "function" ? next(_nullishCoalesce(clone[queryKey], () => ( DEFAULT_QUERY_STATE_ENTRY))) : next;
|
|
466
|
-
return clone;
|
|
467
|
-
});
|
|
468
|
-
},
|
|
469
|
-
[queryKey, setQueryState]
|
|
470
|
-
);
|
|
471
|
-
const [lastNonEmptyData, setLastNonEmptyData] = _react.useState.call(void 0, );
|
|
472
|
-
_react.useEffect.call(void 0, () => {
|
|
473
|
-
if (query.keepLastNonEmptyData && queryStateValue.data !== void 0) {
|
|
474
|
-
setLastNonEmptyData(queryStateValue.data);
|
|
475
|
-
}
|
|
476
|
-
}, [query.keepLastNonEmptyData, queryStateValue.data]);
|
|
477
|
-
const executeQuery = _react.useCallback.call(void 0,
|
|
478
|
-
async (isRefetch) => {
|
|
479
|
-
query.log(
|
|
480
|
-
`Begin executing shared query ${queryKey}, isRefetch=${isRefetch}`
|
|
481
|
-
);
|
|
482
|
-
if (!isMounted.current) return;
|
|
483
|
-
setQueryStateValue((prev) => ({
|
|
484
|
-
// Keep old data and error.
|
|
485
|
-
...prev,
|
|
486
|
-
lastUpdatedMs: Date.now(),
|
|
487
|
-
loading: true
|
|
488
|
-
}));
|
|
489
|
-
try {
|
|
490
|
-
let state;
|
|
491
|
-
if (isRefetch) {
|
|
492
|
-
const data = await query.refetch(...stableArgs);
|
|
493
|
-
const now = Date.now();
|
|
494
|
-
state = {
|
|
495
|
-
// Don't keep old error.
|
|
496
|
-
lastUpdatedMs: now,
|
|
497
|
-
loading: false,
|
|
498
|
-
data,
|
|
499
|
-
dataUpdatedMs: now
|
|
500
|
-
};
|
|
501
|
-
} else {
|
|
502
|
-
state = await query.getCachedOrFetch(...stableArgs);
|
|
503
|
-
}
|
|
504
|
-
if (!isMounted.current) return;
|
|
505
|
-
setQueryStateValue({ ...state, loading: false });
|
|
506
|
-
return state.data;
|
|
507
|
-
} catch (e) {
|
|
508
|
-
if (!isMounted.current) return;
|
|
509
|
-
const now = Date.now();
|
|
510
|
-
setQueryStateValue((prev) => ({
|
|
511
|
-
// Keep old data.
|
|
512
|
-
...prev,
|
|
513
|
-
lastUpdatedMs: now,
|
|
514
|
-
loading: false,
|
|
515
|
-
error: e,
|
|
516
|
-
errorUpdatedMs: now
|
|
517
|
-
}));
|
|
518
|
-
}
|
|
519
|
-
},
|
|
520
|
-
[query, queryKey, setQueryStateValue, stableArgs]
|
|
521
|
-
);
|
|
522
|
-
_react.useEffect.call(void 0, () => {
|
|
523
|
-
isMounted.current = true;
|
|
524
|
-
query.mount(queryKey);
|
|
525
|
-
void executeQuery(false);
|
|
526
|
-
return () => {
|
|
527
|
-
isMounted.current = false;
|
|
528
|
-
query.unmount(queryKey);
|
|
529
|
-
};
|
|
530
|
-
}, [executeQuery, query, queryKey]);
|
|
531
|
-
return _react.useMemo.call(void 0, () => {
|
|
532
|
-
return {
|
|
533
|
-
...queryStateValue,
|
|
534
|
-
// Fill with lastNonEmptyData when data is undefined.
|
|
535
|
-
data: queryStateValue.data !== void 0 ? queryStateValue.data : lastNonEmptyData,
|
|
536
|
-
latestData: queryStateValue.data,
|
|
537
|
-
// This works only if the user-given queryFn supports abort. If not,
|
|
538
|
-
// this function doesn't do anything, since we don't have any means to
|
|
539
|
-
// abort the running queryFn.
|
|
540
|
-
abortCurrentQuery: (reason) => {
|
|
541
|
-
const controller = query.getAbortControllerByKey(queryKey);
|
|
542
|
-
_optionalChain([controller, 'optionalAccess', _27 => _27.abort, 'call', _28 => _28(reason)]);
|
|
543
|
-
return Boolean(controller);
|
|
544
|
-
},
|
|
545
|
-
getCachedOrFetch: async () => {
|
|
546
|
-
const data = await query.getCachedOrFetch(...stableArgs);
|
|
547
|
-
return _nonNil.nonNil.call(void 0,
|
|
548
|
-
data.data,
|
|
549
|
-
typeof data.error === "string" ? data.error : JSON.stringify(data.error)
|
|
550
|
-
);
|
|
551
|
-
},
|
|
552
|
-
refetch: () => {
|
|
553
|
-
return executeQuery(true);
|
|
554
|
-
},
|
|
555
|
-
setData: (data, dataUpdatedMs) => {
|
|
556
|
-
query.setData(queryKey, data, dataUpdatedMs);
|
|
557
|
-
},
|
|
558
|
-
deleteData: () => {
|
|
559
|
-
query.deleteData(queryKey);
|
|
560
|
-
}
|
|
561
|
-
};
|
|
562
|
-
}, [
|
|
563
|
-
executeQuery,
|
|
564
|
-
lastNonEmptyData,
|
|
565
|
-
query,
|
|
566
|
-
queryKey,
|
|
567
|
-
queryStateValue,
|
|
568
|
-
stableArgs
|
|
569
|
-
]);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
exports.SharedQueryConfig = SharedQueryConfig; exports.configureSharedQuery = configureSharedQuery; exports.sharedQuery = sharedQuery; exports.useSharedQuery = useSharedQuery;
|
package/chunk-BQIRLDQC.min.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as l}from"./chunk-VHMO75EY.min.mjs";import{MS_PER_DAY as y}from"@choksheak/ts-utils/timeConstants";import{useSyncExternalStore as v}from"react";var T={storeExpiryMs:30*y,lazyLoad:!1};function E(e){Object.assign(T,e)}function g(){let e=new Map,i=new Map;function S(o,n,t){let a=i.get(o);if(!a)return;let c=Array.from(a.values());for(let 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){let 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"){let e=window.globalThis;return e.reactUtilsPubSubStore||(e.reactUtilsPubSubStore=g())}return g()}var u=h(),p="state",m=0;function R(e,i){let S=()=>{},o=new Promise(r=>{S=r}),n=S,t=String(m++),a=l(i,T.storeExpiryMs);u.setNoNotify(t,e);let c=i?.lazyLoad,d=c!==void 0?c:T.lazyLoad;function f(r){let b=r!==void 0?r:e;u.set(t,b),s.initDone=!0,n()}let s={defaultValue:e,readyPromise:o,lazy:d,initStarted:!1,initDone:!1,subscribe(r){return u.subscribe(t,()=>r())},hasStore(){return!!a},setInStore(r){return a?.set(p,r)},getFromStore(){return a?.get(p)},getSnapshot(){return u.get(t)},setValue(r){if(typeof r=="function"){let b=u.get(t);r=r(b)}u.set(t,r),s.setInStore(r)},delete(){return u.set(t,e),a?.set(p,e)},initDefaultValueOnce(){if(s.initDone||s.initStarted)return;s.initStarted=!0;let r=s.getFromStore();if(r instanceof Promise)return r.then(f);f(r)}};return d||s.initDefaultValueOnce(),s}function P(e){return e.initDefaultValueOnce(),[v(S=>e.subscribe(S),()=>e.getSnapshot(),()=>e.getSnapshot()),e.setValue]}function C(e){return P(e)[0]}function K(e){return e.initDefaultValueOnce(),e.setValue}export{T as a,E as b,R as c,P as d,C as e,K as f};
|
|
2
|
-
//# sourceMappingURL=chunk-BQIRLDQC.min.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sharedState.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\n/**\n * Ensure we always use the same store. If we create two stores, then the\n * reactive updates will fail.\n */\nfunction getOrCreatePubSubStore() {\n if (typeof window !== \"undefined\") {\n const t = window.globalThis as unknown as {\n reactUtilsPubSubStore: ReturnType<typeof createPubSubStore> | undefined;\n };\n return (\n t.reactUtilsPubSubStore || (t.reactUtilsPubSubStore = createPubSubStore())\n );\n }\n return createPubSubStore();\n}\n\nconst pubSubStore = getOrCreatePubSubStore();\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. Don't notify with the default value.\n pubSubStore.setNoNotify(pubSubKey, defaultValue);\n\n const lazyLoad = options?.lazyLoad;\n const lazy = lazyLoad !== undefined ? lazyLoad : SharedStateConfig.lazyLoad;\n\n function completeInit(stored: T | undefined) {\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\n const obj = {\n defaultValue,\n\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 setInStore(value: T): Promise<void> | void {\n return 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 getFromStore(): Promise<T | undefined> | T | undefined {\n return 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(): Promise<void> | void {\n pubSubStore.set(pubSubKey, defaultValue);\n return storageAdapter?.set(STORAGE_KEY, defaultValue);\n },\n\n /** Initial default handling. */\n initDefaultValueOnce(): Promise<void> | void {\n if (obj.initDone || obj.initStarted) return;\n // @ts-expect-error ts(2540) - Assign to readonly property.\n obj.initStarted = true;\n\n const maybePromise = obj.getFromStore();\n\n // Allow sync vs async code paths. This allows init to be fully completed\n // from store before the sharedState() function returns.\n if (maybePromise instanceof Promise) {\n return maybePromise.then(completeInit);\n } else {\n const stored = maybePromise;\n completeInit(stored);\n }\n },\n } as const;\n\n if (!lazy) {\n 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"],"mappings":"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","names":["MS_PER_DAY","useSyncExternalStore","SharedStateConfig","MS_PER_DAY","configureSharedState","config","createPubSubStore","dataByKey","subscribersByKey","notify","key","next","prev","subscribers","copy","subscriber","e","value","getOrCreatePubSubStore","t","pubSubStore","STORAGE_KEY","stateKey","sharedState","defaultValue","options","readyResolve","readyPromise","resolve","resolveReadyPromise","pubSubKey","storageAdapter","getStorageAdapter","lazyLoad","lazy","completeInit","stored","obj","maybePromise","useSharedState","state","useSyncExternalStore","onStoreChange","useSharedStateValue","useSharedStateSetter"]}
|
package/chunk-CYTO5EZE.cjs
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/stringify.ts
|
|
2
|
-
function stringifyDeterministicForKeys(params) {
|
|
3
|
-
const cache = /* @__PURE__ */ new Set();
|
|
4
|
-
return JSON.stringify(params, (_, value) => {
|
|
5
|
-
if (typeof value === "function") {
|
|
6
|
-
throw new Error(`Functions should not be passed into query parameters`);
|
|
7
|
-
}
|
|
8
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
9
|
-
return value;
|
|
10
|
-
}
|
|
11
|
-
if (cache.has(value)) {
|
|
12
|
-
return "[Circular]";
|
|
13
|
-
}
|
|
14
|
-
cache.add(value);
|
|
15
|
-
if (value !== params) {
|
|
16
|
-
try {
|
|
17
|
-
JSON.stringify(value);
|
|
18
|
-
} catch (e) {
|
|
19
|
-
return "[Unserializable]";
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return Object.keys(value).sort().reduce(
|
|
23
|
-
(result, key) => {
|
|
24
|
-
result[key] = value[key];
|
|
25
|
-
return result;
|
|
26
|
-
},
|
|
27
|
-
{}
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
exports.stringifyDeterministicForKeys = stringifyDeterministicForKeys;
|