@braine/quantum-query 1.3.2 → 1.3.3

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 CHANGED
@@ -21,9 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  HydrationBoundary: () => HydrationBoundary,
24
+ Match: () => Match,
25
+ MutationCache: () => MutationCache,
24
26
  QuantumDevTools: () => QuantumDevTools,
25
27
  QueryClient: () => QueryClient,
26
28
  QueryClientProvider: () => QueryClientProvider,
29
+ QueryMatch: () => QueryMatch,
27
30
  SignalValue: () => SignalValue,
28
31
  atom: () => atom,
29
32
  createHttpClient: () => createHttpClient,
@@ -37,7 +40,6 @@ __export(index_exports, {
37
40
  unwrapPromise: () => unwrapPromise,
38
41
  useCombinedQueries: () => useCombinedQueries,
39
42
  useInfiniteQuery: () => useInfiniteQuery,
40
- useMutation: () => useMutation,
41
43
  usePaginatedQuery: () => usePaginatedQuery,
42
44
  useQueries: () => useQueries,
43
45
  useQuery: () => useQuery,
@@ -120,7 +122,7 @@ function atom(initialValue, options) {
120
122
  return s;
121
123
  }
122
124
  function setupPersistence(s, options) {
123
- const { key, storage = "local", debug } = options;
125
+ const { key, storage = "local", debug, hydrateSync } = options;
124
126
  if (!key) return;
125
127
  let engine = null;
126
128
  if (typeof storage === "string") {
@@ -131,27 +133,34 @@ function setupPersistence(s, options) {
131
133
  engine = storage;
132
134
  }
133
135
  if (!engine) return;
134
- try {
135
- const stored = engine.getItem(key);
136
- const applyValue = (val) => {
137
- try {
138
- const parsed = JSON.parse(val);
139
- const validated = options.validate ? options.validate(parsed) : parsed;
140
- s.set(validated);
141
- if (debug) console.log(`[Quantum] Hydrated atom '${key}'`);
142
- } catch (e) {
143
- if (debug) console.error(`[Quantum] Hydration validation failed for '${key}'`, e);
136
+ const hydrate2 = () => {
137
+ try {
138
+ const stored = engine?.getItem(key);
139
+ const applyValue = (val) => {
140
+ try {
141
+ const parsed = JSON.parse(val);
142
+ const validated = options.validate ? options.validate(parsed) : parsed;
143
+ s.set(validated);
144
+ if (debug) console.log(`[Quantum] Hydrated atom '${key}'`);
145
+ } catch (e) {
146
+ if (debug) console.error(`[Quantum] Hydration validation failed for '${key}'`, e);
147
+ }
148
+ };
149
+ if (stored instanceof Promise) {
150
+ stored.then((val) => {
151
+ if (val) applyValue(val);
152
+ });
153
+ } else if (stored) {
154
+ applyValue(stored);
144
155
  }
145
- };
146
- if (stored instanceof Promise) {
147
- stored.then((val) => {
148
- if (val) applyValue(val);
149
- });
150
- } else if (stored) {
151
- applyValue(stored);
156
+ } catch (err) {
157
+ if (debug) console.error(`[Quantum] Hydration error`, err);
152
158
  }
153
- } catch (err) {
154
- if (debug) console.error(`[Quantum] Hydration error`, err);
159
+ };
160
+ if (hydrateSync) {
161
+ hydrate2();
162
+ } else {
163
+ Promise.resolve().then(hydrate2);
155
164
  }
156
165
  s.subscribe((value) => {
157
166
  try {
@@ -182,6 +191,19 @@ function SignalValue({ signal: signal2, render, children }) {
182
191
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: renderer(value) });
183
192
  }
184
193
 
194
+ // src/react/QueryMatch.tsx
195
+ var import_react2 = require("react");
196
+ var import_jsx_runtime2 = require("react/jsx-runtime");
197
+ function QueryMatch({ signal: signal2, selector, children }) {
198
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SignalValue, { signal: signal2, children: (value) => {
199
+ const selected = selector(value);
200
+ return children(selected);
201
+ } });
202
+ }
203
+ function Match({ signal: signal2, when, children }) {
204
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SignalValue, { signal: signal2, children: (value) => when(value) ? children : null });
205
+ }
206
+
185
207
  // src/store/scheduler.ts
186
208
  var pending = /* @__PURE__ */ new Set();
187
209
  var timer = null;
@@ -214,16 +236,16 @@ function enableDevTools(store, name = "Store") {
214
236
  }
215
237
 
216
238
  // src/devtools/index.tsx
217
- var import_react5 = require("react");
239
+ var import_react6 = require("react");
218
240
 
219
241
  // src/devtools/QueryPanel.tsx
220
- var import_react4 = require("react");
242
+ var import_react5 = require("react");
221
243
 
222
244
  // src/query/useQueryStore.ts
223
- var import_react3 = require("react");
245
+ var import_react4 = require("react");
224
246
 
225
247
  // src/query/context.tsx
226
- var import_react2 = require("react");
248
+ var import_react3 = require("react");
227
249
 
228
250
  // src/query/utils.ts
229
251
  function stableHash(value, depth = 0) {
@@ -245,41 +267,90 @@ function stableHash(value, depth = 0) {
245
267
  const keys = Object.keys(value).sort();
246
268
  return `object:{${keys.map((key) => `${key}:${stableHash(value[key], depth + 1)}`).join(",")}}`;
247
269
  }
248
- function isDeepEqual(a, b) {
249
- if (a === b) return true;
250
- if (a && b && typeof a === "object" && typeof b === "object") {
251
- const objA = a;
252
- const objB = b;
253
- if (objA.constructor !== objB.constructor) return false;
254
- let length, i, keys;
255
- if (Array.isArray(a)) {
256
- if (!Array.isArray(b)) return false;
257
- length = a.length;
258
- if (length !== b.length) return false;
259
- for (i = length; i-- !== 0; ) {
260
- if (!isDeepEqual(a[i], b[i])) return false;
270
+
271
+ // src/query/trie.ts
272
+ var TrieNode = class {
273
+ children = /* @__PURE__ */ new Map();
274
+ keys = /* @__PURE__ */ new Set();
275
+ // Stores the full hashed keys valid at this path
276
+ };
277
+ var QueryKeyTrie = class {
278
+ root = new TrieNode();
279
+ insert(queryKey, hashedKey) {
280
+ const parts = this.normalizeParts(queryKey);
281
+ let node = this.root;
282
+ for (const part of parts) {
283
+ const hash = stableHash(part);
284
+ let child = node.children.get(hash);
285
+ if (!child) {
286
+ child = new TrieNode();
287
+ node.children.set(hash, child);
288
+ }
289
+ node = child;
290
+ }
291
+ node.keys.add(hashedKey);
292
+ }
293
+ remove(queryKey, hashedKey) {
294
+ const parts = this.normalizeParts(queryKey);
295
+ this.removeRecursive(this.root, parts, 0, hashedKey);
296
+ }
297
+ removeRecursive(node, parts, index, hashedKey) {
298
+ if (index === parts.length) {
299
+ node.keys.delete(hashedKey);
300
+ return node.children.size === 0 && node.keys.size === 0;
301
+ }
302
+ const part = parts[index];
303
+ const hash = stableHash(part);
304
+ const child = node.children.get(hash);
305
+ if (child) {
306
+ const shouldDeleteChild = this.removeRecursive(child, parts, index + 1, hashedKey);
307
+ if (shouldDeleteChild) {
308
+ node.children.delete(hash);
261
309
  }
262
- return true;
263
310
  }
264
- if (objA.valueOf !== Object.prototype.valueOf) return objA.valueOf() === objB.valueOf();
265
- if (objA.toString !== Object.prototype.toString) return objA.toString() === objB.toString();
266
- keys = Object.keys(objA);
267
- length = keys.length;
268
- if (length !== Object.keys(objB).length) return false;
269
- for (const key of keys) {
270
- if (!Object.prototype.hasOwnProperty.call(objB, key)) return false;
311
+ return node.children.size === 0 && node.keys.size === 0;
312
+ }
313
+ /**
314
+ * Get all hashed keys that match the given partial query key (prefix)
315
+ */
316
+ getMatchingKeys(partialKey) {
317
+ const parts = this.normalizeParts(partialKey);
318
+ let node = this.root;
319
+ for (const part of parts) {
320
+ const hash = stableHash(part);
321
+ const child = node.children.get(hash);
322
+ if (!child) {
323
+ return /* @__PURE__ */ new Set();
324
+ }
325
+ node = child;
271
326
  }
272
- for (const key of keys) {
273
- if (!isDeepEqual(objA[key], objB[key])) return false;
327
+ const results = /* @__PURE__ */ new Set();
328
+ this.collectKeys(node, results);
329
+ return results;
330
+ }
331
+ collectKeys(node, results) {
332
+ for (const key of node.keys) {
333
+ results.add(key);
334
+ }
335
+ for (const child of node.children.values()) {
336
+ this.collectKeys(child, results);
274
337
  }
275
- return true;
276
338
  }
277
- return a !== a && b !== b;
278
- }
339
+ normalizeParts(queryKey) {
340
+ if (Array.isArray(queryKey)) {
341
+ return queryKey;
342
+ }
343
+ if (queryKey && typeof queryKey === "object" && "key" in queryKey) {
344
+ const qk = queryKey;
345
+ return [qk.key, qk.params];
346
+ }
347
+ return [queryKey];
348
+ }
349
+ };
279
350
 
280
351
  // src/query/queryStorage.ts
281
352
  var QueryStorage = class {
282
- // Tracks access order (least to most recent)
353
+ // 10/10: O(K) Lookup
283
354
  // Default configuration
284
355
  constructor(defaultStaleTime = 5 * 60 * 1e3, defaultCacheTime = 5 * 60 * 1e3, maxSize = 100) {
285
356
  this.defaultStaleTime = defaultStaleTime;
@@ -289,6 +360,8 @@ var QueryStorage = class {
289
360
  signals = /* @__PURE__ */ new Map();
290
361
  gcTimers = /* @__PURE__ */ new Map();
291
362
  lruOrder = /* @__PURE__ */ new Set();
363
+ // Tracks access order (least to most recent)
364
+ trie = new QueryKeyTrie();
292
365
  generateKey(queryKey) {
293
366
  const key = Array.isArray(queryKey) ? stableHash(queryKey) : stableHash([queryKey.key, queryKey.params]);
294
367
  return key;
@@ -363,6 +436,7 @@ var QueryStorage = class {
363
436
  }
364
437
  this.enforceMaxSize();
365
438
  }
439
+ this.trie.insert(entry.key, key);
366
440
  }
367
441
  delete(key) {
368
442
  const entry = this.signals.get(key)?.get();
@@ -375,6 +449,9 @@ var QueryStorage = class {
375
449
  }
376
450
  }
377
451
  }
452
+ if (entry?.key) {
453
+ this.trie.remove(entry.key, key);
454
+ }
378
455
  this.signals.delete(key);
379
456
  this.lruOrder.delete(key);
380
457
  this.cancelGC(key);
@@ -399,6 +476,7 @@ var QueryStorage = class {
399
476
  clear() {
400
477
  this.signals.clear();
401
478
  this.tagIndex.clear();
479
+ this.trie = new QueryKeyTrie();
402
480
  this.lruOrder.clear();
403
481
  this.gcTimers.forEach((timer2) => clearTimeout(timer2));
404
482
  this.gcTimers.clear();
@@ -951,11 +1029,26 @@ var QueryClient = class {
951
1029
  });
952
1030
  this.pluginManager.onFetchStart(normalizedKey);
953
1031
  try {
954
- const data = await this.remotes.fetch(key, fn, {
1032
+ const fetchPromise = this.remotes.fetch(key, fn, {
955
1033
  signal: options?.signal,
956
1034
  retry: options?.retry,
957
1035
  retryDelay: options?.retryDelay
958
1036
  });
1037
+ this.storage.set(key, {
1038
+ data: currentEntry?.data,
1039
+ status: currentEntry?.status || "pending",
1040
+ error: null,
1041
+ isFetching: true,
1042
+ fetchDirection: direction,
1043
+ timestamp: currentEntry?.timestamp || Date.now(),
1044
+ staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
1045
+ cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
1046
+ key: queryKey,
1047
+ tags: mergedTags,
1048
+ promise: fetchPromise
1049
+ // Store for Suspense
1050
+ });
1051
+ const data = await fetchPromise;
959
1052
  this.storage.set(key, {
960
1053
  data,
961
1054
  status: "success",
@@ -968,7 +1061,9 @@ var QueryClient = class {
968
1061
  staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
969
1062
  cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
970
1063
  key: queryKey,
971
- tags: mergedTags
1064
+ tags: mergedTags,
1065
+ promise: void 0
1066
+ // Clear promise
972
1067
  });
973
1068
  const schema = options?.schema || this.defaultSchema;
974
1069
  const validatedData = validateWithSchema(data, schema);
@@ -986,7 +1081,9 @@ var QueryClient = class {
986
1081
  staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
987
1082
  cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
988
1083
  key: queryKey,
989
- tags: mergedTags
1084
+ tags: mergedTags,
1085
+ promise: void 0
1086
+ // Clear promise
990
1087
  });
991
1088
  this.pluginManager.onFetchError(normalizedKey, err);
992
1089
  throw err;
@@ -996,18 +1093,15 @@ var QueryClient = class {
996
1093
  * Invalidate queries
997
1094
  */
998
1095
  invalidate = (queryKey) => {
999
- const prefix = this.storage.generateKey(queryKey);
1000
1096
  const normalizedKey = this.normalizeKey(queryKey);
1001
1097
  this.pluginManager.onInvalidate(normalizedKey);
1002
- const allKeys = this.storage.getSnapshot().keys();
1003
- for (const key of allKeys) {
1004
- if (key === prefix || key.startsWith(prefix.slice(0, -1))) {
1005
- const signal2 = this.storage.get(key, false);
1006
- if (signal2) {
1007
- const current = signal2.get();
1008
- if (current) {
1009
- signal2.set({ ...current, isInvalidated: true });
1010
- }
1098
+ const matchingKeys = this.storage.trie.getMatchingKeys(queryKey);
1099
+ for (const key of matchingKeys) {
1100
+ const signal2 = this.storage.get(key, false);
1101
+ if (signal2) {
1102
+ const current = signal2.get();
1103
+ if (current) {
1104
+ signal2.set({ ...current, isInvalidated: true });
1011
1105
  }
1012
1106
  }
1013
1107
  }
@@ -1100,16 +1194,16 @@ var QueryClient = class {
1100
1194
  };
1101
1195
 
1102
1196
  // src/query/context.tsx
1103
- var import_jsx_runtime2 = require("react/jsx-runtime");
1104
- var QueryClientContext = (0, import_react2.createContext)(void 0);
1197
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1198
+ var QueryClientContext = (0, import_react3.createContext)(void 0);
1105
1199
  var QueryClientProvider = ({
1106
1200
  client,
1107
1201
  children
1108
1202
  }) => {
1109
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(QueryClientContext.Provider, { value: client, children: children || null });
1203
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(QueryClientContext.Provider, { value: client, children: children || null });
1110
1204
  };
1111
1205
  var useQueryClient = () => {
1112
- const client = (0, import_react2.useContext)(QueryClientContext);
1206
+ const client = (0, import_react3.useContext)(QueryClientContext);
1113
1207
  if (!client) {
1114
1208
  throw new Error("No QueryClient set, use QueryClientProvider to set one");
1115
1209
  }
@@ -1119,8 +1213,8 @@ var useQueryClient = () => {
1119
1213
  // src/query/useQueryStore.ts
1120
1214
  function useQueryStore() {
1121
1215
  const client = useQueryClient();
1122
- const [cache, setCache] = (0, import_react3.useState)(client.getAll());
1123
- (0, import_react3.useEffect)(() => {
1216
+ const [cache, setCache] = (0, import_react4.useState)(client.getAll());
1217
+ (0, import_react4.useEffect)(() => {
1124
1218
  const interval = setInterval(() => {
1125
1219
  setCache(new Map(client.getAll()));
1126
1220
  }, 500);
@@ -1130,13 +1224,13 @@ function useQueryStore() {
1130
1224
  }
1131
1225
 
1132
1226
  // src/devtools/QueryPanel.tsx
1133
- var import_jsx_runtime3 = require("react/jsx-runtime");
1227
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1134
1228
  function QueryPanel() {
1135
1229
  const cache = useQueryStore();
1136
1230
  const client = useQueryClient();
1137
- const [filter, setFilter] = (0, import_react4.useState)("");
1138
- const entries = (0, import_react4.useMemo)(() => Array.from(cache.entries()), [cache]);
1139
- const filteredEntries = (0, import_react4.useMemo)(() => {
1231
+ const [filter, setFilter] = (0, import_react5.useState)("");
1232
+ const entries = (0, import_react5.useMemo)(() => Array.from(cache.entries()), [cache]);
1233
+ const filteredEntries = (0, import_react5.useMemo)(() => {
1140
1234
  if (!filter) return entries;
1141
1235
  const search = filter.toLowerCase();
1142
1236
  return entries.filter(([_, entry]) => {
@@ -1147,15 +1241,15 @@ function QueryPanel() {
1147
1241
  return JSON.stringify(key).toLowerCase().includes(search);
1148
1242
  });
1149
1243
  }, [entries, filter]);
1150
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
1151
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
1244
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
1245
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1152
1246
  padding: "8px",
1153
1247
  borderBottom: "1px solid #222",
1154
1248
  background: "#0f0f0f",
1155
1249
  display: "flex",
1156
1250
  gap: "8px"
1157
1251
  }, children: [
1158
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1252
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1159
1253
  "input",
1160
1254
  {
1161
1255
  type: "text",
@@ -1174,7 +1268,7 @@ function QueryPanel() {
1174
1268
  }
1175
1269
  }
1176
1270
  ),
1177
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1271
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1178
1272
  "button",
1179
1273
  {
1180
1274
  onClick: () => client.invalidateAll(),
@@ -1191,7 +1285,7 @@ function QueryPanel() {
1191
1285
  }
1192
1286
  )
1193
1287
  ] }),
1194
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
1288
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1195
1289
  flex: 1,
1196
1290
  overflowY: "auto",
1197
1291
  padding: "8px",
@@ -1199,7 +1293,7 @@ function QueryPanel() {
1199
1293
  flexDirection: "column",
1200
1294
  gap: "8px",
1201
1295
  background: "#050505"
1202
- }, children: entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: "20px", textAlign: "center", color: "#444", fontSize: "12px" }, children: "No active queries." }) : filteredEntries.map(([keyHash, entry]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1296
+ }, children: entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { padding: "20px", textAlign: "center", color: "#444", fontSize: "12px" }, children: "No active queries." }) : filteredEntries.map(([keyHash, entry]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1203
1297
  QueryItem,
1204
1298
  {
1205
1299
  entry,
@@ -1211,14 +1305,14 @@ function QueryPanel() {
1211
1305
  ] });
1212
1306
  }
1213
1307
  function QueryItem({ entry, client, isStale }) {
1214
- const [expanded, setExpanded] = (0, import_react4.useState)(false);
1215
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
1308
+ const [expanded, setExpanded] = (0, import_react5.useState)(false);
1309
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1216
1310
  background: "#111",
1217
1311
  borderRadius: "4px",
1218
1312
  border: "1px solid #222",
1219
1313
  overflow: "hidden"
1220
1314
  }, children: [
1221
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1315
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1222
1316
  "div",
1223
1317
  {
1224
1318
  onClick: () => setExpanded(!expanded),
@@ -1231,13 +1325,13 @@ function QueryItem({ entry, client, isStale }) {
1231
1325
  background: expanded ? "#161616" : "transparent"
1232
1326
  },
1233
1327
  children: [
1234
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center", overflow: "hidden" }, children: [
1235
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: {
1328
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center", overflow: "hidden" }, children: [
1329
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: {
1236
1330
  color: isStale ? "#d69e2e" : "#b0fb5d",
1237
1331
  fontSize: "12px",
1238
1332
  fontWeight: "bold"
1239
1333
  }, children: "\u2022" }),
1240
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: {
1334
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: {
1241
1335
  color: "#e0e0e0",
1242
1336
  fontSize: "12px",
1243
1337
  whiteSpace: "nowrap",
@@ -1245,7 +1339,7 @@ function QueryItem({ entry, client, isStale }) {
1245
1339
  textOverflow: "ellipsis"
1246
1340
  }, children: JSON.stringify(entry.key) })
1247
1341
  ] }),
1248
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: {
1342
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: {
1249
1343
  fontSize: "9px",
1250
1344
  color: isStale ? "#d69e2e" : "#b0fb5d",
1251
1345
  padding: "1px 4px",
@@ -1256,13 +1350,13 @@ function QueryItem({ entry, client, isStale }) {
1256
1350
  ]
1257
1351
  }
1258
1352
  ),
1259
- expanded && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
1353
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1260
1354
  padding: "8px",
1261
1355
  borderTop: "1px solid #222",
1262
1356
  background: "#0a0a0a"
1263
1357
  }, children: [
1264
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px", marginBottom: "8px" }, children: [
1265
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1358
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "8px", marginBottom: "8px" }, children: [
1359
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1266
1360
  "button",
1267
1361
  {
1268
1362
  onClick: (e) => {
@@ -1273,7 +1367,7 @@ function QueryItem({ entry, client, isStale }) {
1273
1367
  children: "Invalidate"
1274
1368
  }
1275
1369
  ),
1276
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1370
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1277
1371
  "button",
1278
1372
  {
1279
1373
  onClick: (e) => {
@@ -1285,19 +1379,19 @@ function QueryItem({ entry, client, isStale }) {
1285
1379
  }
1286
1380
  )
1287
1381
  ] }),
1288
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { style: { margin: 0, fontSize: "10px", color: "#a0a0a0", overflowX: "auto", fontFamily: "monospace" }, children: JSON.stringify(entry.data, null, 2) })
1382
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, fontSize: "10px", color: "#a0a0a0", overflowX: "auto", fontFamily: "monospace" }, children: JSON.stringify(entry.data, null, 2) })
1289
1383
  ] })
1290
1384
  ] });
1291
1385
  }
1292
1386
 
1293
1387
  // src/devtools/index.tsx
1294
- var import_jsx_runtime4 = require("react/jsx-runtime");
1388
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1295
1389
  function QuantumDevTools() {
1296
- const [isOpen, setIsOpen] = (0, import_react5.useState)(false);
1297
- const [activeTab, setActiveTab] = (0, import_react5.useState)("queries");
1298
- const [height, setHeight] = (0, import_react5.useState)(400);
1299
- const isResizingRef = (0, import_react5.useRef)(false);
1300
- (0, import_react5.useEffect)(() => {
1390
+ const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
1391
+ const [activeTab, setActiveTab] = (0, import_react6.useState)("queries");
1392
+ const [height, setHeight] = (0, import_react6.useState)(400);
1393
+ const isResizingRef = (0, import_react6.useRef)(false);
1394
+ (0, import_react6.useEffect)(() => {
1301
1395
  const handleMouseMove = (e) => {
1302
1396
  if (!isResizingRef.current) return;
1303
1397
  const newHeight = window.innerHeight - e.clientY;
@@ -1315,7 +1409,7 @@ function QuantumDevTools() {
1315
1409
  };
1316
1410
  }, []);
1317
1411
  if (!isOpen) {
1318
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1412
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1319
1413
  "button",
1320
1414
  {
1321
1415
  onClick: () => setIsOpen(true),
@@ -1340,7 +1434,7 @@ function QuantumDevTools() {
1340
1434
  }
1341
1435
  );
1342
1436
  }
1343
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1437
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1344
1438
  position: "fixed",
1345
1439
  bottom: 0,
1346
1440
  right: 0,
@@ -1353,7 +1447,7 @@ function QuantumDevTools() {
1353
1447
  flexDirection: "column",
1354
1448
  fontFamily: "monospace"
1355
1449
  }, children: [
1356
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1450
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1357
1451
  "div",
1358
1452
  {
1359
1453
  onMouseDown: () => {
@@ -1363,7 +1457,7 @@ function QuantumDevTools() {
1363
1457
  style: { height: "6px", top: "-3px", position: "absolute", width: "100%", cursor: "ns-resize", zIndex: 100 }
1364
1458
  }
1365
1459
  ),
1366
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1460
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1367
1461
  display: "flex",
1368
1462
  justifyContent: "space-between",
1369
1463
  alignItems: "center",
@@ -1371,20 +1465,20 @@ function QuantumDevTools() {
1371
1465
  background: "#111",
1372
1466
  borderBottom: "1px solid #222"
1373
1467
  }, children: [
1374
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "16px", alignItems: "center" }, children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#b0fb5d", fontWeight: "bold" }, children: "Quantum DevTools" }),
1376
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "4px", background: "#000", padding: "2px", borderRadius: "4px" }, children: [
1377
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TabButton, { active: activeTab === "queries", onClick: () => setActiveTab("queries"), children: "Queries" }),
1378
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TabButton, { active: activeTab === "state", onClick: () => setActiveTab("state"), children: "State" })
1468
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "16px", alignItems: "center" }, children: [
1469
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: "#b0fb5d", fontWeight: "bold" }, children: "Quantum DevTools" }),
1470
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "4px", background: "#000", padding: "2px", borderRadius: "4px" }, children: [
1471
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TabButton, { active: activeTab === "queries", onClick: () => setActiveTab("queries"), children: "Queries" }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TabButton, { active: activeTab === "state", onClick: () => setActiveTab("state"), children: "State" })
1379
1473
  ] })
1380
1474
  ] }),
1381
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: () => setIsOpen(false), style: { background: "none", border: "none", color: "#666", cursor: "pointer" }, children: "\xD7" })
1475
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: () => setIsOpen(false), style: { background: "none", border: "none", color: "#666", cursor: "pointer" }, children: "\xD7" })
1382
1476
  ] }),
1383
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: activeTab === "queries" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueryPanel, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "State Panel (Under Construction)" }) })
1477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: activeTab === "queries" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueryPanel, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: "State Panel (Under Construction)" }) })
1384
1478
  ] });
1385
1479
  }
1386
1480
  function TabButton({ active, children, onClick }) {
1387
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1481
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1388
1482
  "button",
1389
1483
  {
1390
1484
  onClick,
@@ -1550,6 +1644,8 @@ var RetryMiddleware = async (ctx, next) => {
1550
1644
  let config;
1551
1645
  if (typeof retryConfigRaw === "number") {
1552
1646
  config = { retries: retryConfigRaw };
1647
+ } else if (typeof retryConfigRaw === "boolean") {
1648
+ config = retryConfigRaw ? { retries: 3 } : { retries: 0 };
1553
1649
  } else if (typeof retryConfigRaw === "object" && retryConfigRaw !== null) {
1554
1650
  config = retryConfigRaw;
1555
1651
  } else {
@@ -1739,7 +1835,7 @@ function getPromiseState(promise) {
1739
1835
  }
1740
1836
 
1741
1837
  // src/query/pagination.ts
1742
- var import_react6 = require("react");
1838
+ var import_react7 = require("react");
1743
1839
  function usePaginatedQuery({
1744
1840
  queryKey,
1745
1841
  queryFn,
@@ -1750,18 +1846,18 @@ function usePaginatedQuery({
1750
1846
  retry
1751
1847
  }) {
1752
1848
  const client = useQueryClient();
1753
- const [page, setPage] = (0, import_react6.useState)(0);
1849
+ const [page, setPage] = (0, import_react7.useState)(0);
1754
1850
  const pageQueryKey = [...queryKey, "page", page];
1755
1851
  const pageQueryKeyHash = JSON.stringify(pageQueryKey);
1756
- const subscribe = (0, import_react6.useCallback)((onStoreChange) => {
1852
+ const subscribe = (0, import_react7.useCallback)((onStoreChange) => {
1757
1853
  const signal2 = client.getSignal(pageQueryKey);
1758
1854
  return signal2.subscribe(() => onStoreChange());
1759
1855
  }, [client, pageQueryKeyHash]);
1760
- const getSnapshot = (0, import_react6.useCallback)(() => {
1856
+ const getSnapshot = (0, import_react7.useCallback)(() => {
1761
1857
  const signal2 = client.getSignal(pageQueryKey);
1762
1858
  return signal2.get();
1763
1859
  }, [client, pageQueryKeyHash]);
1764
- const cacheEntry = (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot);
1860
+ const cacheEntry = (0, import_react7.useSyncExternalStore)(subscribe, getSnapshot);
1765
1861
  const data = cacheEntry?.data;
1766
1862
  const status = cacheEntry?.status || "pending";
1767
1863
  const error = cacheEntry?.error || null;
@@ -1778,15 +1874,15 @@ function usePaginatedQuery({
1778
1874
  }
1779
1875
  }
1780
1876
  const hasPrevious = page > 0;
1781
- const queryFnRef = (0, import_react6.useRef)(queryFn);
1782
- const staleTimeRef = (0, import_react6.useRef)(staleTime);
1783
- const cacheTimeRef = (0, import_react6.useRef)(cacheTime);
1784
- (0, import_react6.useEffect)(() => {
1877
+ const queryFnRef = (0, import_react7.useRef)(queryFn);
1878
+ const staleTimeRef = (0, import_react7.useRef)(staleTime);
1879
+ const cacheTimeRef = (0, import_react7.useRef)(cacheTime);
1880
+ (0, import_react7.useEffect)(() => {
1785
1881
  queryFnRef.current = queryFn;
1786
1882
  staleTimeRef.current = staleTime;
1787
1883
  cacheTimeRef.current = cacheTime;
1788
1884
  });
1789
- const fetchPage = (0, import_react6.useCallback)(async (background = false) => {
1885
+ const fetchPage = (0, import_react7.useCallback)(async (background = false) => {
1790
1886
  if (!enabled) return;
1791
1887
  if (!background) {
1792
1888
  const currentEntry = getSnapshot();
@@ -1805,22 +1901,22 @@ function usePaginatedQuery({
1805
1901
  } catch (err) {
1806
1902
  }
1807
1903
  }, [pageQueryKeyHash, enabled, client, getSnapshot, page]);
1808
- (0, import_react6.useEffect)(() => {
1904
+ (0, import_react7.useEffect)(() => {
1809
1905
  if (enabled) {
1810
1906
  fetchPage();
1811
1907
  }
1812
1908
  }, [fetchPage, enabled]);
1813
- const nextPage = (0, import_react6.useCallback)(() => {
1909
+ const nextPage = (0, import_react7.useCallback)(() => {
1814
1910
  if (hasNext) {
1815
1911
  setPage((p) => p + 1);
1816
1912
  }
1817
1913
  }, [hasNext]);
1818
- const previousPage = (0, import_react6.useCallback)(() => {
1914
+ const previousPage = (0, import_react7.useCallback)(() => {
1819
1915
  if (page > 0) {
1820
1916
  setPage((p) => p - 1);
1821
1917
  }
1822
1918
  }, [page]);
1823
- const refetch = (0, import_react6.useCallback)(async () => {
1919
+ const refetch = (0, import_react7.useCallback)(async () => {
1824
1920
  client.invalidate(pageQueryKey);
1825
1921
  await fetchPage();
1826
1922
  }, [pageQueryKeyHash, fetchPage, client]);
@@ -1840,7 +1936,7 @@ function usePaginatedQuery({
1840
1936
  }
1841
1937
 
1842
1938
  // src/query/useQuery.ts
1843
- var import_react7 = require("react");
1939
+ var import_react8 = require("react");
1844
1940
 
1845
1941
  // src/query/focusManager.ts
1846
1942
  var FocusManager = class {
@@ -1976,7 +2072,7 @@ var QueryObserver = class {
1976
2072
  status: selectorError ? "error" : status,
1977
2073
  refetch: this.refetch
1978
2074
  };
1979
- const isDataEqual = lastResult?.data === nextResult.data || isDeepEqual(lastResult?.data, nextResult.data);
2075
+ const isDataEqual = lastResult?.data === nextResult.data;
1980
2076
  if (lastResult && isDataEqual && lastResult.status === nextResult.status && lastResult.isFetching === nextResult.isFetching && lastResult.isStale === nextResult.isStale && lastResult.error === nextResult.error) {
1981
2077
  return lastResult;
1982
2078
  }
@@ -2098,172 +2194,52 @@ var QueryObserver = class {
2098
2194
  // src/query/useQuery.ts
2099
2195
  function useQuery(options) {
2100
2196
  const client = useQueryClient();
2101
- const [observer] = (0, import_react7.useState)(() => new QueryObserver(client, options));
2102
- (0, import_react7.useEffect)(() => {
2197
+ const [observer] = (0, import_react8.useState)(() => new QueryObserver(client, options));
2198
+ (0, import_react8.useEffect)(() => {
2103
2199
  observer.setOptions(options);
2104
2200
  }, [observer, options]);
2105
- (0, import_react7.useEffect)(() => {
2201
+ (0, import_react8.useEffect)(() => {
2106
2202
  return () => {
2107
2203
  observer.destroy();
2108
2204
  };
2109
2205
  }, [observer]);
2110
- const subscribe = (0, import_react7.useCallback)((onStoreChange) => {
2206
+ const subscribe = (0, import_react8.useCallback)((onStoreChange) => {
2111
2207
  return observer.subscribe(onStoreChange);
2112
2208
  }, [observer]);
2113
- const getSnapshot = (0, import_react7.useCallback)(() => {
2209
+ const getSnapshot = (0, import_react8.useCallback)(() => {
2114
2210
  return observer.getSnapshot();
2115
2211
  }, [observer]);
2116
- const result = (0, import_react7.useSyncExternalStore)(subscribe, getSnapshot);
2212
+ const result = (0, import_react8.useSyncExternalStore)(subscribe, getSnapshot);
2117
2213
  return {
2118
2214
  ...result,
2119
2215
  signal: observer.result$
2120
2216
  };
2121
2217
  }
2122
2218
 
2123
- // src/query/useMutation.ts
2124
- var import_react8 = require("react");
2125
-
2126
- // src/query/mutationObserver.ts
2127
- var generateId = () => {
2128
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
2129
- return crypto.randomUUID();
2130
- }
2131
- return "mutation-" + Date.now() + "-" + Math.random().toString(36).slice(2);
2132
- };
2133
- var MutationObserver = class {
2134
- client;
2135
- options;
2136
- currentMutationId = null;
2137
- // We maintain our own signal for this observer's view of the mutation
2138
- // This ensures we don't miss updates if we switch IDs.
2139
- signal;
2140
- constructor(client, options) {
2141
- this.client = client;
2142
- this.options = options;
2143
- this.signal = createSignal({
2144
- status: "idle",
2145
- data: void 0,
2146
- error: null,
2147
- variables: void 0,
2148
- context: void 0,
2149
- submittedAt: 0
2150
- });
2151
- }
2152
- setOptions(options) {
2153
- this.options = options;
2219
+ // src/query/useSuspenseQuery.ts
2220
+ function useSuspenseQuery(options) {
2221
+ const client = useQueryClient();
2222
+ const signal2 = client.getSignal(options.queryKey);
2223
+ const entry = signal2.get();
2224
+ if (entry?.status === "error") {
2225
+ throw entry.error;
2154
2226
  }
2155
- mutate = (variables) => {
2156
- const id = generateId();
2157
- this.currentMutationId = id;
2158
- this.client.mutationCache.register(id, this.options.mutationKey);
2159
- const pendingState = {
2160
- status: "pending",
2161
- variables,
2162
- submittedAt: Date.now(),
2163
- data: void 0,
2164
- error: null,
2165
- context: void 0
2166
- };
2167
- this.signal.set({
2168
- ...this.signal.get(),
2169
- ...pendingState
2170
- });
2171
- this.client.mutationCache.notify(id, pendingState);
2172
- const unsubscribe = this.client.mutationCache.getSignal(id).subscribe((state) => {
2173
- untracked(() => {
2174
- const current = this.signal.get();
2175
- if (current.status !== state.status || current.data !== state.data || current.error !== state.error) {
2176
- this.signal.set(state);
2177
- }
2178
- });
2179
- });
2180
- return this.executeMutation(id, variables).finally(() => {
2181
- });
2182
- };
2183
- executeMutation = async (id, variables) => {
2184
- const { mutationFn, onMutate, onSuccess, onError, onSettled, invalidatesTags, optimistic, mutationKey } = this.options;
2185
- let context;
2186
- let optimisticSnapshot;
2187
- const notify = (update) => {
2188
- this.client.mutationCache.notify(id, update);
2189
- };
2190
- try {
2191
- if (optimistic) {
2192
- const { queryKey, update } = optimistic;
2193
- const signal2 = this.client.getSignal(queryKey);
2194
- const currentData = signal2.get()?.data;
2195
- optimisticSnapshot = currentData;
2196
- const optimisticData = update(variables, currentData);
2197
- this.client.set(queryKey, optimisticData);
2198
- }
2199
- if (onMutate) {
2200
- context = await onMutate(variables);
2201
- notify({ context });
2202
- }
2203
- const result = await mutationFn(variables);
2204
- notify({ status: "success", data: result });
2205
- if (onSuccess) await onSuccess(result, variables, context);
2206
- if (this.client.invalidateTags && invalidatesTags) {
2207
- this.client.invalidateTags(invalidatesTags);
2208
- }
2209
- if (optimistic) {
2210
- this.client.invalidate(optimistic.queryKey);
2211
- }
2212
- if (onSettled) onSettled(result, null, variables, context);
2213
- return result;
2214
- } catch (error) {
2215
- if (optimistic && optimisticSnapshot !== void 0) {
2216
- this.client.set(optimistic.queryKey, optimisticSnapshot);
2217
- }
2218
- const errorObj = error instanceof Error ? error : new Error(String(error));
2219
- notify({ status: "error", error: errorObj });
2220
- if (onError) onError(errorObj, variables, context);
2221
- if (onSettled) onSettled(void 0, errorObj, variables, context);
2222
- throw error;
2227
+ if (!entry || entry.status === "pending" && entry.data === void 0) {
2228
+ if (entry?.promise) {
2229
+ throw entry.promise;
2223
2230
  }
2224
- };
2225
- reset = () => {
2226
- this.signal.set({
2227
- status: "idle",
2228
- data: void 0,
2229
- error: null,
2230
- variables: void 0,
2231
- context: void 0,
2232
- submittedAt: 0
2231
+ const fetchPromise = client.fetch(options.queryKey, options.queryFn, {
2232
+ retry: options.retry,
2233
+ retryDelay: options.retryDelay,
2234
+ tags: options.tags,
2235
+ schema: options.schema
2233
2236
  });
2234
- this.currentMutationId = null;
2235
- };
2236
- };
2237
-
2238
- // src/query/useMutation.ts
2239
- function useMutation(options) {
2240
- const client = useQueryClient();
2241
- const [observer] = (0, import_react8.useState)(() => new MutationObserver(client, options));
2242
- (0, import_react8.useEffect)(() => {
2243
- observer.setOptions(options);
2244
- }, [observer, options]);
2245
- const state = (0, import_react8.useSyncExternalStore)(
2246
- (0, import_react8.useCallback)((cb) => observer.signal.subscribe(cb), [observer]),
2247
- () => observer.signal.get()
2248
- );
2249
- const mutateAsync = (0, import_react8.useCallback)((variables) => {
2250
- return observer.mutate(variables);
2251
- }, [observer]);
2252
- const mutate = (0, import_react8.useCallback)((variables) => {
2253
- observer.mutate(variables).catch(() => {
2254
- });
2255
- }, [observer]);
2237
+ throw fetchPromise;
2238
+ }
2239
+ const query = useQuery(options);
2256
2240
  return {
2257
- mutate,
2258
- mutateAsync,
2259
- data: state.data,
2260
- error: state.error,
2261
- status: state.status,
2262
- isLoading: state.status === "pending",
2263
- isError: state.status === "error",
2264
- isSuccess: state.status === "success",
2265
- isIdle: state.status === "idle",
2266
- reset: observer.reset
2241
+ ...query,
2242
+ data: query.data
2267
2243
  };
2268
2244
  }
2269
2245
 
@@ -2285,7 +2261,7 @@ var InfiniteQueryObserver = class {
2285
2261
  options$;
2286
2262
  result$;
2287
2263
  unsubscribe = null;
2288
- lastFetchTime = 0;
2264
+ abortController = null;
2289
2265
  constructor(client, options) {
2290
2266
  this.client = client;
2291
2267
  this.options$ = createSignal(options);
@@ -2338,8 +2314,7 @@ var InfiniteQueryObserver = class {
2338
2314
  fetchPreviousPage: this.fetchPreviousPage,
2339
2315
  refetch: this.refetch
2340
2316
  };
2341
- const isDataEqual = lastResult?.data === nextResult.data || isDeepEqual(lastResult?.data, nextResult.data);
2342
- if (lastResult && isDataEqual && lastResult.isFetching === nextResult.isFetching && lastResult.status === nextResult.status && lastResult.hasNextPage === nextResult.hasNextPage && lastResult.hasPreviousPage === nextResult.hasPreviousPage) {
2317
+ 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) {
2343
2318
  return lastResult;
2344
2319
  }
2345
2320
  lastResult = nextResult;
@@ -2351,8 +2326,8 @@ var InfiniteQueryObserver = class {
2351
2326
  const current = this.options$.get();
2352
2327
  if (current === options) return;
2353
2328
  const isKeyEqual = stableHash(current.queryKey) === stableHash(options.queryKey);
2354
- const isConfigEqual = current.enabled === options.enabled && current.staleTime === options.staleTime;
2355
- if (!isKeyEqual || !isConfigEqual || current.getNextPageParam !== options.getNextPageParam || current.getPreviousPageParam !== options.getPreviousPageParam) {
2329
+ const isConfigEqual = current.enabled === options.enabled && current.staleTime === options.staleTime && current.retry === options.retry;
2330
+ if (!isKeyEqual || !isConfigEqual) {
2356
2331
  this.options$.set(options);
2357
2332
  }
2358
2333
  }
@@ -2385,25 +2360,37 @@ var InfiniteQueryObserver = class {
2385
2360
  }
2386
2361
  });
2387
2362
  this.unsubscribe = () => {
2363
+ this.cancel();
2388
2364
  dispose();
2389
2365
  disposeFocus();
2390
2366
  disposeOnline();
2391
2367
  };
2392
2368
  }
2369
+ cancel() {
2370
+ if (this.abortController) {
2371
+ this.abortController.abort();
2372
+ this.abortController = null;
2373
+ }
2374
+ }
2393
2375
  fetchInitial = async (options) => {
2376
+ this.cancel();
2377
+ this.abortController = new AbortController();
2378
+ const signal2 = this.abortController.signal;
2394
2379
  const opts = this.options$.get();
2395
2380
  const infiniteKey = [...opts.queryKey, "__infinite__"];
2396
2381
  try {
2397
2382
  const entrySignal = this.client.getSignal(infiniteKey);
2398
- const data = entrySignal.get()?.data;
2399
- if (data && data.pageParams.length > 0 && !options?.force) {
2400
- const firstParam2 = data.pageParams[0];
2383
+ const currentState = entrySignal.get()?.data;
2384
+ if (currentState && currentState.pageParams.length > 0 && !options?.force) {
2385
+ const firstParam2 = currentState.pageParams[0];
2401
2386
  const firstPage = await opts.queryFn({ pageParam: firstParam2 });
2387
+ if (signal2.aborted) return;
2402
2388
  const latest = entrySignal.get()?.data;
2403
2389
  if (!latest) return;
2404
2390
  const updatedData = {
2405
2391
  ...latest,
2406
2392
  pages: [firstPage, ...latest.pages.slice(1)]
2393
+ // pageParams remain the same
2407
2394
  };
2408
2395
  this.client.set(infiniteKey, updatedData, {
2409
2396
  staleTime: opts.staleTime,
@@ -2413,107 +2400,116 @@ var InfiniteQueryObserver = class {
2413
2400
  }
2414
2401
  const initialParam = opts.initialPageParam;
2415
2402
  const firstParam = initialParam !== void 0 ? initialParam : 0;
2416
- const initialData = await this.client.fetch(infiniteKey, async () => {
2403
+ const initialData = await this.client.fetch(infiniteKey, async (ctx) => {
2417
2404
  const firstPage = await opts.queryFn({ pageParam: firstParam });
2418
2405
  return {
2419
2406
  pages: [firstPage],
2420
2407
  pageParams: [firstParam]
2421
2408
  };
2422
- }, { fetchDirection: "initial", retry: opts.retry });
2423
- this.client.set(infiniteKey, initialData, {
2424
- staleTime: opts.staleTime,
2425
- cacheTime: opts.cacheTime
2409
+ }, {
2410
+ fetchDirection: "initial",
2411
+ retry: opts.retry,
2412
+ signal: signal2
2426
2413
  });
2414
+ if (!signal2.aborted) {
2415
+ this.client.set(infiniteKey, initialData, {
2416
+ staleTime: opts.staleTime,
2417
+ cacheTime: opts.cacheTime
2418
+ });
2419
+ }
2427
2420
  } catch (err) {
2428
- getLogger().error("Initial fetch failed", err);
2421
+ if (!signal2.aborted) {
2422
+ getLogger().error("Initial fetch failed", err);
2423
+ }
2429
2424
  }
2430
2425
  };
2431
2426
  fetchNextPage = async () => {
2432
2427
  const res = this.result$.get();
2433
- const opts = this.options$.get();
2434
2428
  if (!res.hasNextPage || res.isFetching || !res.data) return;
2429
+ this.cancel();
2430
+ this.abortController = new AbortController();
2431
+ const signal2 = this.abortController.signal;
2432
+ const opts = this.options$.get();
2435
2433
  const infiniteKey = [...opts.queryKey, "__infinite__"];
2436
2434
  const lastPage = res.data.pages[res.data.pages.length - 1];
2437
- if (!lastPage) {
2438
- return;
2439
- }
2435
+ if (!lastPage) return;
2440
2436
  const nextPageParam = opts.getNextPageParam?.(lastPage, res.data.pages);
2441
2437
  if (nextPageParam === void 0) return;
2442
2438
  try {
2443
- const updatedData = await this.client.fetch(infiniteKey, async () => {
2439
+ const updatedData = await this.client.fetch(infiniteKey, async (ctx) => {
2444
2440
  const newPage = await opts.queryFn({ pageParam: nextPageParam });
2441
+ if (ctx.signal?.aborted) throw new Error("Aborted");
2445
2442
  const currentData = this.client.getSignal(infiniteKey).get()?.data;
2446
2443
  if (!currentData) throw new Error("Infinite query data missing");
2447
- const updatedParams = [...currentData.pageParams, nextPageParam];
2448
- const nextCursor = opts.getNextPageParam?.(newPage, [...currentData.pages, newPage]);
2449
- if (nextCursor !== void 0) {
2450
- updatedParams.push(nextCursor);
2451
- }
2452
2444
  return {
2453
2445
  pages: [...currentData.pages, newPage],
2454
- pageParams: updatedParams
2446
+ pageParams: [...currentData.pageParams, nextPageParam]
2455
2447
  };
2456
- }, { fetchDirection: "next", retry: opts.retry });
2457
- this.client.set(infiniteKey, updatedData, {
2458
- staleTime: opts.staleTime,
2459
- cacheTime: opts.cacheTime
2448
+ }, {
2449
+ fetchDirection: "next",
2450
+ retry: opts.retry,
2451
+ signal: signal2
2460
2452
  });
2453
+ if (!signal2.aborted) {
2454
+ this.client.set(infiniteKey, updatedData, {
2455
+ staleTime: opts.staleTime,
2456
+ cacheTime: opts.cacheTime
2457
+ });
2458
+ }
2461
2459
  } catch (err) {
2462
- getLogger().error("Fetch next page failed", err);
2460
+ if (!signal2.aborted) {
2461
+ getLogger().error("Fetch next page failed", err);
2462
+ }
2463
2463
  }
2464
2464
  };
2465
2465
  fetchPreviousPage = async () => {
2466
2466
  const res = this.result$.get();
2467
- const opts = this.options$.get();
2468
2467
  if (!res.hasPreviousPage || res.isFetching || !res.data) return;
2468
+ this.cancel();
2469
+ this.abortController = new AbortController();
2470
+ const signal2 = this.abortController.signal;
2471
+ const opts = this.options$.get();
2469
2472
  const infiniteKey = [...opts.queryKey, "__infinite__"];
2470
2473
  const firstPage = res.data.pages[0];
2471
- if (!firstPage) {
2472
- return;
2473
- }
2474
+ if (!firstPage) return;
2474
2475
  const previousPageParam = opts.getPreviousPageParam?.(firstPage, res.data.pages);
2475
2476
  if (previousPageParam === void 0) return;
2476
2477
  try {
2477
- const updatedData = await this.client.fetch(infiniteKey, async () => {
2478
+ const updatedData = await this.client.fetch(infiniteKey, async (ctx) => {
2478
2479
  const newPage = await opts.queryFn({ pageParam: previousPageParam });
2480
+ if (ctx.signal?.aborted) throw new Error("Aborted");
2479
2481
  const currentData = this.client.getSignal(infiniteKey).get()?.data;
2480
2482
  if (!currentData) throw new Error("Infinite query data missing");
2481
2483
  return {
2482
2484
  pages: [newPage, ...currentData.pages],
2483
2485
  pageParams: [previousPageParam, ...currentData.pageParams]
2484
2486
  };
2485
- }, { fetchDirection: "previous", retry: opts.retry });
2486
- this.client.set(infiniteKey, updatedData, {
2487
- staleTime: opts.staleTime,
2488
- cacheTime: opts.cacheTime
2487
+ }, {
2488
+ fetchDirection: "previous",
2489
+ retry: opts.retry,
2490
+ signal: signal2
2489
2491
  });
2492
+ if (!signal2.aborted) {
2493
+ this.client.set(infiniteKey, updatedData, {
2494
+ staleTime: opts.staleTime,
2495
+ cacheTime: opts.cacheTime
2496
+ });
2497
+ }
2490
2498
  } catch (err) {
2491
- getLogger().error("Fetch previous page failed", err);
2499
+ if (!signal2.aborted) {
2500
+ getLogger().error("Fetch previous page failed", err);
2501
+ }
2492
2502
  }
2493
2503
  };
2494
2504
  refetch = async () => {
2505
+ this.cancel();
2495
2506
  const opts = this.options$.get();
2496
2507
  const infiniteKey = [...opts.queryKey, "__infinite__"];
2497
2508
  this.client.invalidate(infiniteKey);
2498
- const initialParam = opts.initialPageParam;
2499
- const firstParam = initialParam !== void 0 ? initialParam : 0;
2500
- try {
2501
- const initialData = await this.client.fetch(infiniteKey, async () => {
2502
- const firstPage = await opts.queryFn({ pageParam: firstParam });
2503
- return {
2504
- pages: [firstPage],
2505
- pageParams: [firstParam]
2506
- };
2507
- }, { fetchDirection: "initial", retry: opts.retry });
2508
- this.client.set(infiniteKey, initialData, {
2509
- staleTime: opts.staleTime,
2510
- cacheTime: opts.cacheTime
2511
- });
2512
- } catch (err) {
2513
- getLogger().error("Refetch failed", err);
2514
- }
2509
+ await this.fetchInitial({ force: true });
2515
2510
  };
2516
2511
  destroy() {
2512
+ this.cancel();
2517
2513
  if (this.unsubscribe) this.unsubscribe();
2518
2514
  }
2519
2515
  };
@@ -2565,7 +2561,7 @@ function hydrate(client, state) {
2565
2561
  }
2566
2562
 
2567
2563
  // src/query/HydrationBoundary.tsx
2568
- var import_jsx_runtime5 = require("react/jsx-runtime");
2564
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2569
2565
  function HydrationBoundary({ state, children }) {
2570
2566
  const client = useQueryClient();
2571
2567
  const hydratedRef = (0, import_react10.useRef)(false);
@@ -2573,34 +2569,7 @@ function HydrationBoundary({ state, children }) {
2573
2569
  hydrate(client, state);
2574
2570
  hydratedRef.current = true;
2575
2571
  }
2576
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
2577
- }
2578
-
2579
- // src/query/useSuspenseQuery.ts
2580
- function useSuspenseQuery(options) {
2581
- const client = useQueryClient();
2582
- const signal2 = client.getSignal(options.queryKey);
2583
- const entry = signal2.get();
2584
- const shouldSuspend = !entry || entry.status === "pending" && entry.data === void 0;
2585
- if (shouldSuspend) {
2586
- const fetchPromise = client.fetch(
2587
- options.queryKey,
2588
- (ctx) => options.queryFn({ ...ctx, signal: void 0 }),
2589
- { signal: void 0 }
2590
- ).then((data) => {
2591
- client.set(options.queryKey, data);
2592
- return data;
2593
- });
2594
- throw fetchPromise;
2595
- }
2596
- if (entry?.status === "error") {
2597
- throw entry.error;
2598
- }
2599
- const query = useQuery(options);
2600
- return {
2601
- ...query,
2602
- data: query.data
2603
- };
2572
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
2604
2573
  }
2605
2574
 
2606
2575
  // src/query/useQuerySignal.ts
@@ -2683,9 +2652,12 @@ function useCombinedQueries(queries, client) {
2683
2652
  // Annotate the CommonJS export names for ESM import in node:
2684
2653
  0 && (module.exports = {
2685
2654
  HydrationBoundary,
2655
+ Match,
2656
+ MutationCache,
2686
2657
  QuantumDevTools,
2687
2658
  QueryClient,
2688
2659
  QueryClientProvider,
2660
+ QueryMatch,
2689
2661
  SignalValue,
2690
2662
  atom,
2691
2663
  createHttpClient,
@@ -2699,7 +2671,6 @@ function useCombinedQueries(queries, client) {
2699
2671
  unwrapPromise,
2700
2672
  useCombinedQueries,
2701
2673
  useInfiniteQuery,
2702
- useMutation,
2703
2674
  usePaginatedQuery,
2704
2675
  useQueries,
2705
2676
  useQuery,