@braine/quantum-query 1.3.2 → 1.3.4
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/dist/index.cjs +363 -243
- package/dist/index.d.cts +44 -8
- package/dist/index.d.ts +44 -8
- package/dist/index.js +286 -169
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -76,7 +76,7 @@ function atom(initialValue, options) {
|
|
|
76
76
|
return s;
|
|
77
77
|
}
|
|
78
78
|
function setupPersistence(s, options) {
|
|
79
|
-
const { key, storage = "local", debug } = options;
|
|
79
|
+
const { key, storage = "local", debug, hydrateSync } = options;
|
|
80
80
|
if (!key) return;
|
|
81
81
|
let engine = null;
|
|
82
82
|
if (typeof storage === "string") {
|
|
@@ -87,27 +87,34 @@ function setupPersistence(s, options) {
|
|
|
87
87
|
engine = storage;
|
|
88
88
|
}
|
|
89
89
|
if (!engine) return;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
const hydrate2 = () => {
|
|
91
|
+
try {
|
|
92
|
+
const stored = engine?.getItem(key);
|
|
93
|
+
const applyValue = (val) => {
|
|
94
|
+
try {
|
|
95
|
+
const parsed = JSON.parse(val);
|
|
96
|
+
const validated = options.validate ? options.validate(parsed) : parsed;
|
|
97
|
+
s.set(validated);
|
|
98
|
+
if (debug) console.log(`[Quantum] Hydrated atom '${key}'`);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
if (debug) console.error(`[Quantum] Hydration validation failed for '${key}'`, e);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
if (stored instanceof Promise) {
|
|
104
|
+
stored.then((val) => {
|
|
105
|
+
if (val) applyValue(val);
|
|
106
|
+
});
|
|
107
|
+
} else if (stored) {
|
|
108
|
+
applyValue(stored);
|
|
100
109
|
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
stored.then((val) => {
|
|
104
|
-
if (val) applyValue(val);
|
|
105
|
-
});
|
|
106
|
-
} else if (stored) {
|
|
107
|
-
applyValue(stored);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (debug) console.error(`[Quantum] Hydration error`, err);
|
|
108
112
|
}
|
|
109
|
-
}
|
|
110
|
-
|
|
113
|
+
};
|
|
114
|
+
if (hydrateSync) {
|
|
115
|
+
hydrate2();
|
|
116
|
+
} else {
|
|
117
|
+
Promise.resolve().then(hydrate2);
|
|
111
118
|
}
|
|
112
119
|
s.subscribe((value) => {
|
|
113
120
|
try {
|
|
@@ -138,6 +145,19 @@ function SignalValue({ signal: signal2, render, children }) {
|
|
|
138
145
|
return /* @__PURE__ */ jsx(Fragment, { children: renderer(value) });
|
|
139
146
|
}
|
|
140
147
|
|
|
148
|
+
// src/react/QueryMatch.tsx
|
|
149
|
+
import "react";
|
|
150
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
151
|
+
function QueryMatch({ signal: signal2, selector, children }) {
|
|
152
|
+
return /* @__PURE__ */ jsx2(SignalValue, { signal: signal2, children: (value) => {
|
|
153
|
+
const selected = selector(value);
|
|
154
|
+
return children(selected);
|
|
155
|
+
} });
|
|
156
|
+
}
|
|
157
|
+
function Match({ signal: signal2, when, children }) {
|
|
158
|
+
return /* @__PURE__ */ jsx2(SignalValue, { signal: signal2, children: (value) => when(value) ? children : null });
|
|
159
|
+
}
|
|
160
|
+
|
|
141
161
|
// src/store/scheduler.ts
|
|
142
162
|
var pending = /* @__PURE__ */ new Set();
|
|
143
163
|
var timer = null;
|
|
@@ -201,41 +221,90 @@ function stableHash(value, depth = 0) {
|
|
|
201
221
|
const keys = Object.keys(value).sort();
|
|
202
222
|
return `object:{${keys.map((key) => `${key}:${stableHash(value[key], depth + 1)}`).join(",")}}`;
|
|
203
223
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
|
|
225
|
+
// src/query/trie.ts
|
|
226
|
+
var TrieNode = class {
|
|
227
|
+
children = /* @__PURE__ */ new Map();
|
|
228
|
+
keys = /* @__PURE__ */ new Set();
|
|
229
|
+
// Stores the full hashed keys valid at this path
|
|
230
|
+
};
|
|
231
|
+
var QueryKeyTrie = class {
|
|
232
|
+
root = new TrieNode();
|
|
233
|
+
insert(queryKey, hashedKey) {
|
|
234
|
+
const parts = this.normalizeParts(queryKey);
|
|
235
|
+
let node = this.root;
|
|
236
|
+
for (const part of parts) {
|
|
237
|
+
const hash = stableHash(part);
|
|
238
|
+
let child = node.children.get(hash);
|
|
239
|
+
if (!child) {
|
|
240
|
+
child = new TrieNode();
|
|
241
|
+
node.children.set(hash, child);
|
|
217
242
|
}
|
|
218
|
-
|
|
243
|
+
node = child;
|
|
244
|
+
}
|
|
245
|
+
node.keys.add(hashedKey);
|
|
246
|
+
}
|
|
247
|
+
remove(queryKey, hashedKey) {
|
|
248
|
+
const parts = this.normalizeParts(queryKey);
|
|
249
|
+
this.removeRecursive(this.root, parts, 0, hashedKey);
|
|
250
|
+
}
|
|
251
|
+
removeRecursive(node, parts, index, hashedKey) {
|
|
252
|
+
if (index === parts.length) {
|
|
253
|
+
node.keys.delete(hashedKey);
|
|
254
|
+
return node.children.size === 0 && node.keys.size === 0;
|
|
255
|
+
}
|
|
256
|
+
const part = parts[index];
|
|
257
|
+
const hash = stableHash(part);
|
|
258
|
+
const child = node.children.get(hash);
|
|
259
|
+
if (child) {
|
|
260
|
+
const shouldDeleteChild = this.removeRecursive(child, parts, index + 1, hashedKey);
|
|
261
|
+
if (shouldDeleteChild) {
|
|
262
|
+
node.children.delete(hash);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return node.children.size === 0 && node.keys.size === 0;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get all hashed keys that match the given partial query key (prefix)
|
|
269
|
+
*/
|
|
270
|
+
getMatchingKeys(partialKey) {
|
|
271
|
+
const parts = this.normalizeParts(partialKey);
|
|
272
|
+
let node = this.root;
|
|
273
|
+
for (const part of parts) {
|
|
274
|
+
const hash = stableHash(part);
|
|
275
|
+
const child = node.children.get(hash);
|
|
276
|
+
if (!child) {
|
|
277
|
+
return /* @__PURE__ */ new Set();
|
|
278
|
+
}
|
|
279
|
+
node = child;
|
|
219
280
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
for (const key of keys) {
|
|
226
|
-
|
|
281
|
+
const results = /* @__PURE__ */ new Set();
|
|
282
|
+
this.collectKeys(node, results);
|
|
283
|
+
return results;
|
|
284
|
+
}
|
|
285
|
+
collectKeys(node, results) {
|
|
286
|
+
for (const key of node.keys) {
|
|
287
|
+
results.add(key);
|
|
227
288
|
}
|
|
228
|
-
for (const
|
|
229
|
-
|
|
289
|
+
for (const child of node.children.values()) {
|
|
290
|
+
this.collectKeys(child, results);
|
|
230
291
|
}
|
|
231
|
-
return true;
|
|
232
292
|
}
|
|
233
|
-
|
|
234
|
-
|
|
293
|
+
normalizeParts(queryKey) {
|
|
294
|
+
if (Array.isArray(queryKey)) {
|
|
295
|
+
return queryKey;
|
|
296
|
+
}
|
|
297
|
+
if (queryKey && typeof queryKey === "object" && "key" in queryKey) {
|
|
298
|
+
const qk = queryKey;
|
|
299
|
+
return [qk.key, qk.params];
|
|
300
|
+
}
|
|
301
|
+
return [queryKey];
|
|
302
|
+
}
|
|
303
|
+
};
|
|
235
304
|
|
|
236
305
|
// src/query/queryStorage.ts
|
|
237
306
|
var QueryStorage = class {
|
|
238
|
-
//
|
|
307
|
+
// 10/10: O(K) Lookup
|
|
239
308
|
// Default configuration
|
|
240
309
|
constructor(defaultStaleTime = 5 * 60 * 1e3, defaultCacheTime = 5 * 60 * 1e3, maxSize = 100) {
|
|
241
310
|
this.defaultStaleTime = defaultStaleTime;
|
|
@@ -245,6 +314,8 @@ var QueryStorage = class {
|
|
|
245
314
|
signals = /* @__PURE__ */ new Map();
|
|
246
315
|
gcTimers = /* @__PURE__ */ new Map();
|
|
247
316
|
lruOrder = /* @__PURE__ */ new Set();
|
|
317
|
+
// Tracks access order (least to most recent)
|
|
318
|
+
trie = new QueryKeyTrie();
|
|
248
319
|
generateKey(queryKey) {
|
|
249
320
|
const key = Array.isArray(queryKey) ? stableHash(queryKey) : stableHash([queryKey.key, queryKey.params]);
|
|
250
321
|
return key;
|
|
@@ -319,6 +390,7 @@ var QueryStorage = class {
|
|
|
319
390
|
}
|
|
320
391
|
this.enforceMaxSize();
|
|
321
392
|
}
|
|
393
|
+
this.trie.insert(entry.key, key);
|
|
322
394
|
}
|
|
323
395
|
delete(key) {
|
|
324
396
|
const entry = this.signals.get(key)?.get();
|
|
@@ -331,6 +403,9 @@ var QueryStorage = class {
|
|
|
331
403
|
}
|
|
332
404
|
}
|
|
333
405
|
}
|
|
406
|
+
if (entry?.key) {
|
|
407
|
+
this.trie.remove(entry.key, key);
|
|
408
|
+
}
|
|
334
409
|
this.signals.delete(key);
|
|
335
410
|
this.lruOrder.delete(key);
|
|
336
411
|
this.cancelGC(key);
|
|
@@ -355,6 +430,7 @@ var QueryStorage = class {
|
|
|
355
430
|
clear() {
|
|
356
431
|
this.signals.clear();
|
|
357
432
|
this.tagIndex.clear();
|
|
433
|
+
this.trie = new QueryKeyTrie();
|
|
358
434
|
this.lruOrder.clear();
|
|
359
435
|
this.gcTimers.forEach((timer2) => clearTimeout(timer2));
|
|
360
436
|
this.gcTimers.clear();
|
|
@@ -907,11 +983,26 @@ var QueryClient = class {
|
|
|
907
983
|
});
|
|
908
984
|
this.pluginManager.onFetchStart(normalizedKey);
|
|
909
985
|
try {
|
|
910
|
-
const
|
|
986
|
+
const fetchPromise = this.remotes.fetch(key, fn, {
|
|
911
987
|
signal: options?.signal,
|
|
912
988
|
retry: options?.retry,
|
|
913
989
|
retryDelay: options?.retryDelay
|
|
914
990
|
});
|
|
991
|
+
this.storage.set(key, {
|
|
992
|
+
data: currentEntry?.data,
|
|
993
|
+
status: currentEntry?.status || "pending",
|
|
994
|
+
error: null,
|
|
995
|
+
isFetching: true,
|
|
996
|
+
fetchDirection: direction,
|
|
997
|
+
timestamp: currentEntry?.timestamp || Date.now(),
|
|
998
|
+
staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
|
|
999
|
+
cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
|
|
1000
|
+
key: queryKey,
|
|
1001
|
+
tags: mergedTags,
|
|
1002
|
+
promise: fetchPromise
|
|
1003
|
+
// Store for Suspense
|
|
1004
|
+
});
|
|
1005
|
+
const data = await fetchPromise;
|
|
915
1006
|
this.storage.set(key, {
|
|
916
1007
|
data,
|
|
917
1008
|
status: "success",
|
|
@@ -924,7 +1015,9 @@ var QueryClient = class {
|
|
|
924
1015
|
staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
|
|
925
1016
|
cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
|
|
926
1017
|
key: queryKey,
|
|
927
|
-
tags: mergedTags
|
|
1018
|
+
tags: mergedTags,
|
|
1019
|
+
promise: void 0
|
|
1020
|
+
// Clear promise
|
|
928
1021
|
});
|
|
929
1022
|
const schema = options?.schema || this.defaultSchema;
|
|
930
1023
|
const validatedData = validateWithSchema(data, schema);
|
|
@@ -942,7 +1035,9 @@ var QueryClient = class {
|
|
|
942
1035
|
staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
|
|
943
1036
|
cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
|
|
944
1037
|
key: queryKey,
|
|
945
|
-
tags: mergedTags
|
|
1038
|
+
tags: mergedTags,
|
|
1039
|
+
promise: void 0
|
|
1040
|
+
// Clear promise
|
|
946
1041
|
});
|
|
947
1042
|
this.pluginManager.onFetchError(normalizedKey, err);
|
|
948
1043
|
throw err;
|
|
@@ -952,18 +1047,15 @@ var QueryClient = class {
|
|
|
952
1047
|
* Invalidate queries
|
|
953
1048
|
*/
|
|
954
1049
|
invalidate = (queryKey) => {
|
|
955
|
-
const prefix = this.storage.generateKey(queryKey);
|
|
956
1050
|
const normalizedKey = this.normalizeKey(queryKey);
|
|
957
1051
|
this.pluginManager.onInvalidate(normalizedKey);
|
|
958
|
-
const
|
|
959
|
-
for (const key of
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
signal2.set({ ...current, isInvalidated: true });
|
|
966
|
-
}
|
|
1052
|
+
const matchingKeys = this.storage.trie.getMatchingKeys(queryKey);
|
|
1053
|
+
for (const key of matchingKeys) {
|
|
1054
|
+
const signal2 = this.storage.get(key, false);
|
|
1055
|
+
if (signal2) {
|
|
1056
|
+
const current = signal2.get();
|
|
1057
|
+
if (current) {
|
|
1058
|
+
signal2.set({ ...current, isInvalidated: true });
|
|
967
1059
|
}
|
|
968
1060
|
}
|
|
969
1061
|
}
|
|
@@ -1056,13 +1148,13 @@ var QueryClient = class {
|
|
|
1056
1148
|
};
|
|
1057
1149
|
|
|
1058
1150
|
// src/query/context.tsx
|
|
1059
|
-
import { jsx as
|
|
1151
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1060
1152
|
var QueryClientContext = createContext(void 0);
|
|
1061
1153
|
var QueryClientProvider = ({
|
|
1062
1154
|
client,
|
|
1063
1155
|
children
|
|
1064
1156
|
}) => {
|
|
1065
|
-
return /* @__PURE__ */
|
|
1157
|
+
return /* @__PURE__ */ jsx3(QueryClientContext.Provider, { value: client, children: children || null });
|
|
1066
1158
|
};
|
|
1067
1159
|
var useQueryClient = () => {
|
|
1068
1160
|
const client = useContext(QueryClientContext);
|
|
@@ -1086,7 +1178,7 @@ function useQueryStore() {
|
|
|
1086
1178
|
}
|
|
1087
1179
|
|
|
1088
1180
|
// src/devtools/QueryPanel.tsx
|
|
1089
|
-
import { jsx as
|
|
1181
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
1090
1182
|
function QueryPanel() {
|
|
1091
1183
|
const cache = useQueryStore();
|
|
1092
1184
|
const client = useQueryClient();
|
|
@@ -1111,7 +1203,7 @@ function QueryPanel() {
|
|
|
1111
1203
|
display: "flex",
|
|
1112
1204
|
gap: "8px"
|
|
1113
1205
|
}, children: [
|
|
1114
|
-
/* @__PURE__ */
|
|
1206
|
+
/* @__PURE__ */ jsx4(
|
|
1115
1207
|
"input",
|
|
1116
1208
|
{
|
|
1117
1209
|
type: "text",
|
|
@@ -1130,7 +1222,7 @@ function QueryPanel() {
|
|
|
1130
1222
|
}
|
|
1131
1223
|
}
|
|
1132
1224
|
),
|
|
1133
|
-
/* @__PURE__ */
|
|
1225
|
+
/* @__PURE__ */ jsx4(
|
|
1134
1226
|
"button",
|
|
1135
1227
|
{
|
|
1136
1228
|
onClick: () => client.invalidateAll(),
|
|
@@ -1147,7 +1239,7 @@ function QueryPanel() {
|
|
|
1147
1239
|
}
|
|
1148
1240
|
)
|
|
1149
1241
|
] }),
|
|
1150
|
-
/* @__PURE__ */
|
|
1242
|
+
/* @__PURE__ */ jsx4("div", { style: {
|
|
1151
1243
|
flex: 1,
|
|
1152
1244
|
overflowY: "auto",
|
|
1153
1245
|
padding: "8px",
|
|
@@ -1155,7 +1247,7 @@ function QueryPanel() {
|
|
|
1155
1247
|
flexDirection: "column",
|
|
1156
1248
|
gap: "8px",
|
|
1157
1249
|
background: "#050505"
|
|
1158
|
-
}, children: entries.length === 0 ? /* @__PURE__ */
|
|
1250
|
+
}, children: entries.length === 0 ? /* @__PURE__ */ jsx4("div", { style: { padding: "20px", textAlign: "center", color: "#444", fontSize: "12px" }, children: "No active queries." }) : filteredEntries.map(([keyHash, entry]) => /* @__PURE__ */ jsx4(
|
|
1159
1251
|
QueryItem,
|
|
1160
1252
|
{
|
|
1161
1253
|
entry,
|
|
@@ -1188,12 +1280,12 @@ function QueryItem({ entry, client, isStale }) {
|
|
|
1188
1280
|
},
|
|
1189
1281
|
children: [
|
|
1190
1282
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center", overflow: "hidden" }, children: [
|
|
1191
|
-
/* @__PURE__ */
|
|
1283
|
+
/* @__PURE__ */ jsx4("span", { style: {
|
|
1192
1284
|
color: isStale ? "#d69e2e" : "#b0fb5d",
|
|
1193
1285
|
fontSize: "12px",
|
|
1194
1286
|
fontWeight: "bold"
|
|
1195
1287
|
}, children: "\u2022" }),
|
|
1196
|
-
/* @__PURE__ */
|
|
1288
|
+
/* @__PURE__ */ jsx4("span", { style: {
|
|
1197
1289
|
color: "#e0e0e0",
|
|
1198
1290
|
fontSize: "12px",
|
|
1199
1291
|
whiteSpace: "nowrap",
|
|
@@ -1201,7 +1293,7 @@ function QueryItem({ entry, client, isStale }) {
|
|
|
1201
1293
|
textOverflow: "ellipsis"
|
|
1202
1294
|
}, children: JSON.stringify(entry.key) })
|
|
1203
1295
|
] }),
|
|
1204
|
-
/* @__PURE__ */
|
|
1296
|
+
/* @__PURE__ */ jsx4("span", { style: {
|
|
1205
1297
|
fontSize: "9px",
|
|
1206
1298
|
color: isStale ? "#d69e2e" : "#b0fb5d",
|
|
1207
1299
|
padding: "1px 4px",
|
|
@@ -1218,7 +1310,7 @@ function QueryItem({ entry, client, isStale }) {
|
|
|
1218
1310
|
background: "#0a0a0a"
|
|
1219
1311
|
}, children: [
|
|
1220
1312
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", marginBottom: "8px" }, children: [
|
|
1221
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ jsx4(
|
|
1222
1314
|
"button",
|
|
1223
1315
|
{
|
|
1224
1316
|
onClick: (e) => {
|
|
@@ -1229,7 +1321,7 @@ function QueryItem({ entry, client, isStale }) {
|
|
|
1229
1321
|
children: "Invalidate"
|
|
1230
1322
|
}
|
|
1231
1323
|
),
|
|
1232
|
-
/* @__PURE__ */
|
|
1324
|
+
/* @__PURE__ */ jsx4(
|
|
1233
1325
|
"button",
|
|
1234
1326
|
{
|
|
1235
1327
|
onClick: (e) => {
|
|
@@ -1241,13 +1333,13 @@ function QueryItem({ entry, client, isStale }) {
|
|
|
1241
1333
|
}
|
|
1242
1334
|
)
|
|
1243
1335
|
] }),
|
|
1244
|
-
/* @__PURE__ */
|
|
1336
|
+
/* @__PURE__ */ jsx4("pre", { style: { margin: 0, fontSize: "10px", color: "#a0a0a0", overflowX: "auto", fontFamily: "monospace" }, children: JSON.stringify(entry.data, null, 2) })
|
|
1245
1337
|
] })
|
|
1246
1338
|
] });
|
|
1247
1339
|
}
|
|
1248
1340
|
|
|
1249
1341
|
// src/devtools/index.tsx
|
|
1250
|
-
import { jsx as
|
|
1342
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1251
1343
|
function QuantumDevTools() {
|
|
1252
1344
|
const [isOpen, setIsOpen] = useState4(false);
|
|
1253
1345
|
const [activeTab, setActiveTab] = useState4("queries");
|
|
@@ -1271,7 +1363,7 @@ function QuantumDevTools() {
|
|
|
1271
1363
|
};
|
|
1272
1364
|
}, []);
|
|
1273
1365
|
if (!isOpen) {
|
|
1274
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ jsx5(
|
|
1275
1367
|
"button",
|
|
1276
1368
|
{
|
|
1277
1369
|
onClick: () => setIsOpen(true),
|
|
@@ -1309,7 +1401,7 @@ function QuantumDevTools() {
|
|
|
1309
1401
|
flexDirection: "column",
|
|
1310
1402
|
fontFamily: "monospace"
|
|
1311
1403
|
}, children: [
|
|
1312
|
-
/* @__PURE__ */
|
|
1404
|
+
/* @__PURE__ */ jsx5(
|
|
1313
1405
|
"div",
|
|
1314
1406
|
{
|
|
1315
1407
|
onMouseDown: () => {
|
|
@@ -1328,19 +1420,19 @@ function QuantumDevTools() {
|
|
|
1328
1420
|
borderBottom: "1px solid #222"
|
|
1329
1421
|
}, children: [
|
|
1330
1422
|
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "16px", alignItems: "center" }, children: [
|
|
1331
|
-
/* @__PURE__ */
|
|
1423
|
+
/* @__PURE__ */ jsx5("span", { style: { color: "#b0fb5d", fontWeight: "bold" }, children: "Quantum DevTools" }),
|
|
1332
1424
|
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "4px", background: "#000", padding: "2px", borderRadius: "4px" }, children: [
|
|
1333
|
-
/* @__PURE__ */
|
|
1334
|
-
/* @__PURE__ */
|
|
1425
|
+
/* @__PURE__ */ jsx5(TabButton, { active: activeTab === "queries", onClick: () => setActiveTab("queries"), children: "Queries" }),
|
|
1426
|
+
/* @__PURE__ */ jsx5(TabButton, { active: activeTab === "state", onClick: () => setActiveTab("state"), children: "State" })
|
|
1335
1427
|
] })
|
|
1336
1428
|
] }),
|
|
1337
|
-
/* @__PURE__ */
|
|
1429
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setIsOpen(false), style: { background: "none", border: "none", color: "#666", cursor: "pointer" }, children: "\xD7" })
|
|
1338
1430
|
] }),
|
|
1339
|
-
/* @__PURE__ */
|
|
1431
|
+
/* @__PURE__ */ jsx5("div", { style: { flex: 1, overflow: "hidden" }, children: activeTab === "queries" ? /* @__PURE__ */ jsx5(QueryPanel, {}) : /* @__PURE__ */ jsx5("div", { children: "State Panel (Under Construction)" }) })
|
|
1340
1432
|
] });
|
|
1341
1433
|
}
|
|
1342
1434
|
function TabButton({ active, children, onClick }) {
|
|
1343
|
-
return /* @__PURE__ */
|
|
1435
|
+
return /* @__PURE__ */ jsx5(
|
|
1344
1436
|
"button",
|
|
1345
1437
|
{
|
|
1346
1438
|
onClick,
|
|
@@ -1506,6 +1598,8 @@ var RetryMiddleware = async (ctx, next) => {
|
|
|
1506
1598
|
let config;
|
|
1507
1599
|
if (typeof retryConfigRaw === "number") {
|
|
1508
1600
|
config = { retries: retryConfigRaw };
|
|
1601
|
+
} else if (typeof retryConfigRaw === "boolean") {
|
|
1602
|
+
config = retryConfigRaw ? { retries: 3 } : { retries: 0 };
|
|
1509
1603
|
} else if (typeof retryConfigRaw === "object" && retryConfigRaw !== null) {
|
|
1510
1604
|
config = retryConfigRaw;
|
|
1511
1605
|
} else {
|
|
@@ -1932,7 +2026,7 @@ var QueryObserver = class {
|
|
|
1932
2026
|
status: selectorError ? "error" : status,
|
|
1933
2027
|
refetch: this.refetch
|
|
1934
2028
|
};
|
|
1935
|
-
const isDataEqual = lastResult?.data === nextResult.data
|
|
2029
|
+
const isDataEqual = lastResult?.data === nextResult.data;
|
|
1936
2030
|
if (lastResult && isDataEqual && lastResult.status === nextResult.status && lastResult.isFetching === nextResult.isFetching && lastResult.isStale === nextResult.isStale && lastResult.error === nextResult.error) {
|
|
1937
2031
|
return lastResult;
|
|
1938
2032
|
}
|
|
@@ -2076,6 +2170,33 @@ function useQuery(options) {
|
|
|
2076
2170
|
};
|
|
2077
2171
|
}
|
|
2078
2172
|
|
|
2173
|
+
// src/query/useSuspenseQuery.ts
|
|
2174
|
+
function useSuspenseQuery(options) {
|
|
2175
|
+
const client = useQueryClient();
|
|
2176
|
+
const signal2 = client.getSignal(options.queryKey);
|
|
2177
|
+
const entry = signal2.get();
|
|
2178
|
+
if (entry?.status === "error") {
|
|
2179
|
+
throw entry.error;
|
|
2180
|
+
}
|
|
2181
|
+
if (!entry || entry.status === "pending" && entry.data === void 0) {
|
|
2182
|
+
if (entry?.promise) {
|
|
2183
|
+
throw entry.promise;
|
|
2184
|
+
}
|
|
2185
|
+
const fetchPromise = client.fetch(options.queryKey, options.queryFn, {
|
|
2186
|
+
retry: options.retry,
|
|
2187
|
+
retryDelay: options.retryDelay,
|
|
2188
|
+
tags: options.tags,
|
|
2189
|
+
schema: options.schema
|
|
2190
|
+
});
|
|
2191
|
+
throw fetchPromise;
|
|
2192
|
+
}
|
|
2193
|
+
const query = useQuery(options);
|
|
2194
|
+
return {
|
|
2195
|
+
...query,
|
|
2196
|
+
data: query.data
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2079
2200
|
// src/query/useMutation.ts
|
|
2080
2201
|
import { useCallback as useCallback3, useEffect as useEffect6, useSyncExternalStore as useSyncExternalStore3, useState as useState7 } from "react";
|
|
2081
2202
|
|
|
@@ -2241,7 +2362,7 @@ var InfiniteQueryObserver = class {
|
|
|
2241
2362
|
options$;
|
|
2242
2363
|
result$;
|
|
2243
2364
|
unsubscribe = null;
|
|
2244
|
-
|
|
2365
|
+
abortController = null;
|
|
2245
2366
|
constructor(client, options) {
|
|
2246
2367
|
this.client = client;
|
|
2247
2368
|
this.options$ = createSignal(options);
|
|
@@ -2294,8 +2415,7 @@ var InfiniteQueryObserver = class {
|
|
|
2294
2415
|
fetchPreviousPage: this.fetchPreviousPage,
|
|
2295
2416
|
refetch: this.refetch
|
|
2296
2417
|
};
|
|
2297
|
-
|
|
2298
|
-
if (lastResult && isDataEqual && lastResult.isFetching === nextResult.isFetching && lastResult.status === nextResult.status && lastResult.hasNextPage === nextResult.hasNextPage && lastResult.hasPreviousPage === nextResult.hasPreviousPage) {
|
|
2418
|
+
if (lastResult && lastResult.data === nextResult.data && lastResult.isFetching === nextResult.isFetching && lastResult.status === nextResult.status && lastResult.hasNextPage === nextResult.hasNextPage && lastResult.hasPreviousPage === nextResult.hasPreviousPage && lastResult.error === nextResult.error) {
|
|
2299
2419
|
return lastResult;
|
|
2300
2420
|
}
|
|
2301
2421
|
lastResult = nextResult;
|
|
@@ -2307,8 +2427,8 @@ var InfiniteQueryObserver = class {
|
|
|
2307
2427
|
const current = this.options$.get();
|
|
2308
2428
|
if (current === options) return;
|
|
2309
2429
|
const isKeyEqual = stableHash(current.queryKey) === stableHash(options.queryKey);
|
|
2310
|
-
const isConfigEqual = current.enabled === options.enabled && current.staleTime === options.staleTime;
|
|
2311
|
-
if (!isKeyEqual || !isConfigEqual
|
|
2430
|
+
const isConfigEqual = current.enabled === options.enabled && current.staleTime === options.staleTime && current.retry === options.retry;
|
|
2431
|
+
if (!isKeyEqual || !isConfigEqual) {
|
|
2312
2432
|
this.options$.set(options);
|
|
2313
2433
|
}
|
|
2314
2434
|
}
|
|
@@ -2341,25 +2461,37 @@ var InfiniteQueryObserver = class {
|
|
|
2341
2461
|
}
|
|
2342
2462
|
});
|
|
2343
2463
|
this.unsubscribe = () => {
|
|
2464
|
+
this.cancel();
|
|
2344
2465
|
dispose();
|
|
2345
2466
|
disposeFocus();
|
|
2346
2467
|
disposeOnline();
|
|
2347
2468
|
};
|
|
2348
2469
|
}
|
|
2470
|
+
cancel() {
|
|
2471
|
+
if (this.abortController) {
|
|
2472
|
+
this.abortController.abort();
|
|
2473
|
+
this.abortController = null;
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2349
2476
|
fetchInitial = async (options) => {
|
|
2477
|
+
this.cancel();
|
|
2478
|
+
this.abortController = new AbortController();
|
|
2479
|
+
const signal2 = this.abortController.signal;
|
|
2350
2480
|
const opts = this.options$.get();
|
|
2351
2481
|
const infiniteKey = [...opts.queryKey, "__infinite__"];
|
|
2352
2482
|
try {
|
|
2353
2483
|
const entrySignal = this.client.getSignal(infiniteKey);
|
|
2354
|
-
const
|
|
2355
|
-
if (
|
|
2356
|
-
const firstParam2 =
|
|
2484
|
+
const currentState = entrySignal.get()?.data;
|
|
2485
|
+
if (currentState && currentState.pageParams.length > 0 && !options?.force) {
|
|
2486
|
+
const firstParam2 = currentState.pageParams[0];
|
|
2357
2487
|
const firstPage = await opts.queryFn({ pageParam: firstParam2 });
|
|
2488
|
+
if (signal2.aborted) return;
|
|
2358
2489
|
const latest = entrySignal.get()?.data;
|
|
2359
2490
|
if (!latest) return;
|
|
2360
2491
|
const updatedData = {
|
|
2361
2492
|
...latest,
|
|
2362
2493
|
pages: [firstPage, ...latest.pages.slice(1)]
|
|
2494
|
+
// pageParams remain the same
|
|
2363
2495
|
};
|
|
2364
2496
|
this.client.set(infiniteKey, updatedData, {
|
|
2365
2497
|
staleTime: opts.staleTime,
|
|
@@ -2369,107 +2501,116 @@ var InfiniteQueryObserver = class {
|
|
|
2369
2501
|
}
|
|
2370
2502
|
const initialParam = opts.initialPageParam;
|
|
2371
2503
|
const firstParam = initialParam !== void 0 ? initialParam : 0;
|
|
2372
|
-
const initialData = await this.client.fetch(infiniteKey, async () => {
|
|
2504
|
+
const initialData = await this.client.fetch(infiniteKey, async (ctx) => {
|
|
2373
2505
|
const firstPage = await opts.queryFn({ pageParam: firstParam });
|
|
2374
2506
|
return {
|
|
2375
2507
|
pages: [firstPage],
|
|
2376
2508
|
pageParams: [firstParam]
|
|
2377
2509
|
};
|
|
2378
|
-
}, {
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2510
|
+
}, {
|
|
2511
|
+
fetchDirection: "initial",
|
|
2512
|
+
retry: opts.retry,
|
|
2513
|
+
signal: signal2
|
|
2382
2514
|
});
|
|
2515
|
+
if (!signal2.aborted) {
|
|
2516
|
+
this.client.set(infiniteKey, initialData, {
|
|
2517
|
+
staleTime: opts.staleTime,
|
|
2518
|
+
cacheTime: opts.cacheTime
|
|
2519
|
+
});
|
|
2520
|
+
}
|
|
2383
2521
|
} catch (err) {
|
|
2384
|
-
|
|
2522
|
+
if (!signal2.aborted) {
|
|
2523
|
+
getLogger().error("Initial fetch failed", err);
|
|
2524
|
+
}
|
|
2385
2525
|
}
|
|
2386
2526
|
};
|
|
2387
2527
|
fetchNextPage = async () => {
|
|
2388
2528
|
const res = this.result$.get();
|
|
2389
|
-
const opts = this.options$.get();
|
|
2390
2529
|
if (!res.hasNextPage || res.isFetching || !res.data) return;
|
|
2530
|
+
this.cancel();
|
|
2531
|
+
this.abortController = new AbortController();
|
|
2532
|
+
const signal2 = this.abortController.signal;
|
|
2533
|
+
const opts = this.options$.get();
|
|
2391
2534
|
const infiniteKey = [...opts.queryKey, "__infinite__"];
|
|
2392
2535
|
const lastPage = res.data.pages[res.data.pages.length - 1];
|
|
2393
|
-
if (!lastPage)
|
|
2394
|
-
return;
|
|
2395
|
-
}
|
|
2536
|
+
if (!lastPage) return;
|
|
2396
2537
|
const nextPageParam = opts.getNextPageParam?.(lastPage, res.data.pages);
|
|
2397
2538
|
if (nextPageParam === void 0) return;
|
|
2398
2539
|
try {
|
|
2399
|
-
const updatedData = await this.client.fetch(infiniteKey, async () => {
|
|
2540
|
+
const updatedData = await this.client.fetch(infiniteKey, async (ctx) => {
|
|
2400
2541
|
const newPage = await opts.queryFn({ pageParam: nextPageParam });
|
|
2542
|
+
if (ctx.signal?.aborted) throw new Error("Aborted");
|
|
2401
2543
|
const currentData = this.client.getSignal(infiniteKey).get()?.data;
|
|
2402
2544
|
if (!currentData) throw new Error("Infinite query data missing");
|
|
2403
|
-
const updatedParams = [...currentData.pageParams, nextPageParam];
|
|
2404
|
-
const nextCursor = opts.getNextPageParam?.(newPage, [...currentData.pages, newPage]);
|
|
2405
|
-
if (nextCursor !== void 0) {
|
|
2406
|
-
updatedParams.push(nextCursor);
|
|
2407
|
-
}
|
|
2408
2545
|
return {
|
|
2409
2546
|
pages: [...currentData.pages, newPage],
|
|
2410
|
-
pageParams:
|
|
2547
|
+
pageParams: [...currentData.pageParams, nextPageParam]
|
|
2411
2548
|
};
|
|
2412
|
-
}, {
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2549
|
+
}, {
|
|
2550
|
+
fetchDirection: "next",
|
|
2551
|
+
retry: opts.retry,
|
|
2552
|
+
signal: signal2
|
|
2416
2553
|
});
|
|
2554
|
+
if (!signal2.aborted) {
|
|
2555
|
+
this.client.set(infiniteKey, updatedData, {
|
|
2556
|
+
staleTime: opts.staleTime,
|
|
2557
|
+
cacheTime: opts.cacheTime
|
|
2558
|
+
});
|
|
2559
|
+
}
|
|
2417
2560
|
} catch (err) {
|
|
2418
|
-
|
|
2561
|
+
if (!signal2.aborted) {
|
|
2562
|
+
getLogger().error("Fetch next page failed", err);
|
|
2563
|
+
}
|
|
2419
2564
|
}
|
|
2420
2565
|
};
|
|
2421
2566
|
fetchPreviousPage = async () => {
|
|
2422
2567
|
const res = this.result$.get();
|
|
2423
|
-
const opts = this.options$.get();
|
|
2424
2568
|
if (!res.hasPreviousPage || res.isFetching || !res.data) return;
|
|
2569
|
+
this.cancel();
|
|
2570
|
+
this.abortController = new AbortController();
|
|
2571
|
+
const signal2 = this.abortController.signal;
|
|
2572
|
+
const opts = this.options$.get();
|
|
2425
2573
|
const infiniteKey = [...opts.queryKey, "__infinite__"];
|
|
2426
2574
|
const firstPage = res.data.pages[0];
|
|
2427
|
-
if (!firstPage)
|
|
2428
|
-
return;
|
|
2429
|
-
}
|
|
2575
|
+
if (!firstPage) return;
|
|
2430
2576
|
const previousPageParam = opts.getPreviousPageParam?.(firstPage, res.data.pages);
|
|
2431
2577
|
if (previousPageParam === void 0) return;
|
|
2432
2578
|
try {
|
|
2433
|
-
const updatedData = await this.client.fetch(infiniteKey, async () => {
|
|
2579
|
+
const updatedData = await this.client.fetch(infiniteKey, async (ctx) => {
|
|
2434
2580
|
const newPage = await opts.queryFn({ pageParam: previousPageParam });
|
|
2581
|
+
if (ctx.signal?.aborted) throw new Error("Aborted");
|
|
2435
2582
|
const currentData = this.client.getSignal(infiniteKey).get()?.data;
|
|
2436
2583
|
if (!currentData) throw new Error("Infinite query data missing");
|
|
2437
2584
|
return {
|
|
2438
2585
|
pages: [newPage, ...currentData.pages],
|
|
2439
2586
|
pageParams: [previousPageParam, ...currentData.pageParams]
|
|
2440
2587
|
};
|
|
2441
|
-
}, {
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2588
|
+
}, {
|
|
2589
|
+
fetchDirection: "previous",
|
|
2590
|
+
retry: opts.retry,
|
|
2591
|
+
signal: signal2
|
|
2445
2592
|
});
|
|
2593
|
+
if (!signal2.aborted) {
|
|
2594
|
+
this.client.set(infiniteKey, updatedData, {
|
|
2595
|
+
staleTime: opts.staleTime,
|
|
2596
|
+
cacheTime: opts.cacheTime
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
2446
2599
|
} catch (err) {
|
|
2447
|
-
|
|
2600
|
+
if (!signal2.aborted) {
|
|
2601
|
+
getLogger().error("Fetch previous page failed", err);
|
|
2602
|
+
}
|
|
2448
2603
|
}
|
|
2449
2604
|
};
|
|
2450
2605
|
refetch = async () => {
|
|
2606
|
+
this.cancel();
|
|
2451
2607
|
const opts = this.options$.get();
|
|
2452
2608
|
const infiniteKey = [...opts.queryKey, "__infinite__"];
|
|
2453
2609
|
this.client.invalidate(infiniteKey);
|
|
2454
|
-
|
|
2455
|
-
const firstParam = initialParam !== void 0 ? initialParam : 0;
|
|
2456
|
-
try {
|
|
2457
|
-
const initialData = await this.client.fetch(infiniteKey, async () => {
|
|
2458
|
-
const firstPage = await opts.queryFn({ pageParam: firstParam });
|
|
2459
|
-
return {
|
|
2460
|
-
pages: [firstPage],
|
|
2461
|
-
pageParams: [firstParam]
|
|
2462
|
-
};
|
|
2463
|
-
}, { fetchDirection: "initial", retry: opts.retry });
|
|
2464
|
-
this.client.set(infiniteKey, initialData, {
|
|
2465
|
-
staleTime: opts.staleTime,
|
|
2466
|
-
cacheTime: opts.cacheTime
|
|
2467
|
-
});
|
|
2468
|
-
} catch (err) {
|
|
2469
|
-
getLogger().error("Refetch failed", err);
|
|
2470
|
-
}
|
|
2610
|
+
await this.fetchInitial({ force: true });
|
|
2471
2611
|
};
|
|
2472
2612
|
destroy() {
|
|
2613
|
+
this.cancel();
|
|
2473
2614
|
if (this.unsubscribe) this.unsubscribe();
|
|
2474
2615
|
}
|
|
2475
2616
|
};
|
|
@@ -2521,7 +2662,7 @@ function hydrate(client, state) {
|
|
|
2521
2662
|
}
|
|
2522
2663
|
|
|
2523
2664
|
// src/query/HydrationBoundary.tsx
|
|
2524
|
-
import { Fragment as Fragment2, jsx as
|
|
2665
|
+
import { Fragment as Fragment2, jsx as jsx6 } from "react/jsx-runtime";
|
|
2525
2666
|
function HydrationBoundary({ state, children }) {
|
|
2526
2667
|
const client = useQueryClient();
|
|
2527
2668
|
const hydratedRef = useRef4(false);
|
|
@@ -2529,34 +2670,7 @@ function HydrationBoundary({ state, children }) {
|
|
|
2529
2670
|
hydrate(client, state);
|
|
2530
2671
|
hydratedRef.current = true;
|
|
2531
2672
|
}
|
|
2532
|
-
return /* @__PURE__ */
|
|
2533
|
-
}
|
|
2534
|
-
|
|
2535
|
-
// src/query/useSuspenseQuery.ts
|
|
2536
|
-
function useSuspenseQuery(options) {
|
|
2537
|
-
const client = useQueryClient();
|
|
2538
|
-
const signal2 = client.getSignal(options.queryKey);
|
|
2539
|
-
const entry = signal2.get();
|
|
2540
|
-
const shouldSuspend = !entry || entry.status === "pending" && entry.data === void 0;
|
|
2541
|
-
if (shouldSuspend) {
|
|
2542
|
-
const fetchPromise = client.fetch(
|
|
2543
|
-
options.queryKey,
|
|
2544
|
-
(ctx) => options.queryFn({ ...ctx, signal: void 0 }),
|
|
2545
|
-
{ signal: void 0 }
|
|
2546
|
-
).then((data) => {
|
|
2547
|
-
client.set(options.queryKey, data);
|
|
2548
|
-
return data;
|
|
2549
|
-
});
|
|
2550
|
-
throw fetchPromise;
|
|
2551
|
-
}
|
|
2552
|
-
if (entry?.status === "error") {
|
|
2553
|
-
throw entry.error;
|
|
2554
|
-
}
|
|
2555
|
-
const query = useQuery(options);
|
|
2556
|
-
return {
|
|
2557
|
-
...query,
|
|
2558
|
-
data: query.data
|
|
2559
|
-
};
|
|
2673
|
+
return /* @__PURE__ */ jsx6(Fragment2, { children });
|
|
2560
2674
|
}
|
|
2561
2675
|
|
|
2562
2676
|
// src/query/useQuerySignal.ts
|
|
@@ -2638,9 +2752,12 @@ function useCombinedQueries(queries, client) {
|
|
|
2638
2752
|
}
|
|
2639
2753
|
export {
|
|
2640
2754
|
HydrationBoundary,
|
|
2755
|
+
Match,
|
|
2756
|
+
MutationCache,
|
|
2641
2757
|
QuantumDevTools,
|
|
2642
2758
|
QueryClient,
|
|
2643
2759
|
QueryClientProvider,
|
|
2760
|
+
QueryMatch,
|
|
2644
2761
|
SignalValue,
|
|
2645
2762
|
atom,
|
|
2646
2763
|
createHttpClient,
|