@braine/quantum-query 1.2.6 → 1.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -21,302 +21,34 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  HydrationBoundary: () => HydrationBoundary,
24
- QueryCache: () => QueryCache,
24
+ QueryClient: () => QueryClient,
25
25
  QueryClientProvider: () => QueryClientProvider,
26
- computed: () => computed,
26
+ SignalValue: () => SignalValue,
27
+ atom: () => atom,
27
28
  createHttpClient: () => createHttpClient,
28
- createState: () => createState,
29
- defineModel: () => defineModel,
30
29
  dehydrate: () => dehydrate,
31
30
  enableDevTools: () => enableDevTools,
32
- fromSignal: () => fromSignal,
33
31
  getPromiseState: () => getPromiseState,
34
32
  handlePromise: () => handlePromise,
35
33
  hydrate: () => hydrate,
36
34
  isPromise: () => isPromise,
37
35
  scheduleUpdate: () => scheduleUpdate,
38
- subscribe: () => subscribe,
39
- toSignal: () => toSignal,
40
36
  unwrapPromise: () => unwrapPromise,
41
37
  useInfiniteQuery: () => useInfiniteQuery,
42
38
  useMutation: () => useMutation,
43
39
  usePaginatedQuery: () => usePaginatedQuery,
44
40
  useQuery: () => useQuery,
41
+ useQuery$: () => useQuery$,
45
42
  useQueryClient: () => useQueryClient,
46
- useStore: () => useStore,
43
+ useQueryStore: () => useQueryStore,
47
44
  useSuspenseQuery: () => useSuspenseQuery
48
45
  });
49
46
  module.exports = __toCommonJS(index_exports);
50
47
 
51
- // src/core/scheduler.ts
52
- var pending = /* @__PURE__ */ new Set();
53
- var timer = null;
54
- function flush() {
55
- timer = null;
56
- const tasks = [...pending];
57
- pending.clear();
58
- tasks.forEach((task) => task());
59
- }
60
- function scheduleUpdate(callback) {
61
- pending.add(callback);
62
- if (!timer) {
63
- timer = Promise.resolve().then(flush);
64
- }
65
- }
66
-
67
- // src/core/asyncUtils.ts
68
- var PROMISE_CACHE = /* @__PURE__ */ new WeakMap();
69
- var PROMISE_STATUS = /* @__PURE__ */ new WeakMap();
70
- var PROMISE_ERROR = /* @__PURE__ */ new WeakMap();
71
- function isPromise(value) {
72
- return !!value && typeof value.then === "function";
73
- }
74
- function handlePromise(promise, triggerUpdate) {
75
- if (PROMISE_STATUS.has(promise)) return;
76
- PROMISE_STATUS.set(promise, "pending");
77
- promise.then(
78
- (value) => {
79
- PROMISE_STATUS.set(promise, "fulfilled");
80
- PROMISE_CACHE.set(promise, value);
81
- triggerUpdate();
82
- },
83
- (error) => {
84
- PROMISE_STATUS.set(promise, "rejected");
85
- PROMISE_ERROR.set(promise, error);
86
- triggerUpdate();
87
- }
88
- );
89
- }
90
- function unwrapPromise(promise) {
91
- const status = PROMISE_STATUS.get(promise);
92
- if (status === "fulfilled") {
93
- return PROMISE_CACHE.get(promise);
94
- } else if (status === "rejected") {
95
- throw PROMISE_ERROR.get(promise);
96
- } else {
97
- throw promise;
98
- }
99
- }
100
- function getPromiseState(promise) {
101
- return {
102
- status: PROMISE_STATUS.get(promise) || "pending",
103
- value: PROMISE_CACHE.get(promise),
104
- error: PROMISE_ERROR.get(promise)
105
- };
106
- }
107
-
108
- // src/core/proxy.ts
109
- var LISTENERS = /* @__PURE__ */ new WeakMap();
110
- var PROXIES = /* @__PURE__ */ new WeakMap();
111
- var PROXY_TO_TARGET = /* @__PURE__ */ new WeakMap();
112
- var activeListener = null;
113
- function setActiveListener(listener) {
114
- activeListener = listener;
115
- }
116
- function getActiveListener() {
117
- return activeListener;
118
- }
119
- var GLOBAL_LISTENERS = /* @__PURE__ */ new WeakMap();
120
- function subscribe(store, callback) {
121
- const target = PROXY_TO_TARGET.get(store) || store;
122
- let listeners = GLOBAL_LISTENERS.get(target);
123
- if (!listeners) {
124
- listeners = /* @__PURE__ */ new Set();
125
- GLOBAL_LISTENERS.set(target, listeners);
126
- }
127
- listeners.add(callback);
128
- return () => listeners?.delete(callback);
129
- }
130
- var handler = {
131
- get(target, prop, receiver) {
132
- if (activeListener) {
133
- let listeners = LISTENERS.get(target);
134
- if (!listeners) {
135
- listeners = /* @__PURE__ */ new Set();
136
- LISTENERS.set(target, listeners);
137
- }
138
- listeners.add(activeListener);
139
- }
140
- const value = Reflect.get(target, prop, receiver);
141
- if (isPromise(value)) {
142
- return unwrapPromise(value);
143
- }
144
- if (typeof value === "object" && value !== null) {
145
- return createState(value);
146
- }
147
- return value;
148
- },
149
- set(target, prop, value, receiver) {
150
- const oldValue = Reflect.get(target, prop, receiver);
151
- if (Object.is(oldValue, value)) return true;
152
- if (isPromise(value)) {
153
- const trigger = () => {
154
- const listeners2 = LISTENERS.get(target);
155
- if (listeners2) listeners2.forEach((l) => l());
156
- };
157
- handlePromise(value, trigger);
158
- }
159
- const result = Reflect.set(target, prop, value, receiver);
160
- const listeners = LISTENERS.get(target);
161
- if (listeners) {
162
- listeners.forEach((l) => l());
163
- }
164
- const globals = GLOBAL_LISTENERS.get(target);
165
- if (globals) {
166
- globals.forEach((cb) => cb(target, prop, value));
167
- }
168
- return result;
169
- },
170
- deleteProperty(target, prop) {
171
- const result = Reflect.deleteProperty(target, prop);
172
- const listeners = LISTENERS.get(target);
173
- if (listeners) {
174
- listeners.forEach((l) => l());
175
- }
176
- return result;
177
- }
178
- };
179
- function createState(initialState) {
180
- if (PROXIES.has(initialState)) {
181
- return PROXIES.get(initialState);
182
- }
183
- const proxy = new Proxy(initialState, handler);
184
- PROXIES.set(initialState, proxy);
185
- PROXY_TO_TARGET.set(proxy, initialState);
186
- return proxy;
187
- }
188
-
189
- // src/core/model.ts
190
- function debounce(fn, ms) {
191
- let timeout;
192
- return (...args) => {
193
- clearTimeout(timeout);
194
- timeout = setTimeout(() => fn(...args), ms);
195
- };
196
- }
197
- function defineModel(def) {
198
- const target = def.state;
199
- if (def.actions) {
200
- for (const [key, fn] of Object.entries(def.actions)) {
201
- target[key] = fn;
202
- }
203
- }
204
- if (def.computed) {
205
- for (const [key, getter] of Object.entries(def.computed)) {
206
- if (typeof getter === "function") {
207
- Object.defineProperty(target, key, {
208
- get: function() {
209
- return getter.call(this);
210
- },
211
- enumerable: true,
212
- configurable: true
213
- });
214
- }
215
- }
216
- }
217
- const proxy = createState(target);
218
- if (def.persist) {
219
- const { key, storage = "local", paths, debug } = def.persist;
220
- let engine = null;
221
- if (typeof storage === "string") {
222
- if (typeof window !== "undefined") {
223
- engine = storage === "local" ? window.localStorage : window.sessionStorage;
224
- }
225
- } else {
226
- engine = storage;
227
- }
228
- if (engine) {
229
- const hydrate2 = () => {
230
- const process = (stored) => {
231
- try {
232
- if (stored) {
233
- const parsed = JSON.parse(stored);
234
- Object.assign(proxy, parsed);
235
- if (debug) console.log(`[Quantum] Hydrated '${key}'`, parsed);
236
- }
237
- } catch (err) {
238
- if (debug) console.error(`[Quantum] Hydration Failed for '${key}'`, err);
239
- }
240
- };
241
- try {
242
- const result = engine.getItem(key);
243
- if (result instanceof Promise) {
244
- result.then(process);
245
- } else {
246
- process(result);
247
- }
248
- } catch (err) {
249
- if (debug) console.error(`[Quantum] Storage Access Failed`, err);
250
- }
251
- };
252
- hydrate2();
253
- const save = debounce(async () => {
254
- try {
255
- let stateToSave;
256
- if (paths) {
257
- stateToSave = {};
258
- for (const p of paths) {
259
- stateToSave[p] = proxy[p];
260
- }
261
- } else {
262
- stateToSave = {};
263
- const keys = Object.keys(def.state);
264
- for (const k of keys) {
265
- stateToSave[k] = proxy[k];
266
- }
267
- }
268
- const serialized = JSON.stringify(stateToSave);
269
- await engine.setItem(key, serialized);
270
- if (debug) console.log(`[Quantum] Saved '${key}'`);
271
- } catch (err) {
272
- }
273
- }, 100);
274
- subscribe(proxy, () => {
275
- save();
276
- });
277
- }
278
- }
279
- return proxy;
280
- }
281
-
282
- // src/react/autoHook.ts
283
- var import_react = require("react");
284
- function useStore(store) {
285
- const versionRef = (0, import_react.useRef)(0);
286
- const notifyRef = (0, import_react.useRef)(void 0);
287
- const listener = (0, import_react.useCallback)(() => {
288
- versionRef.current++;
289
- if (notifyRef.current) {
290
- notifyRef.current();
291
- }
292
- }, []);
293
- const subscribe2 = (0, import_react.useCallback)((onStoreChange) => {
294
- notifyRef.current = onStoreChange;
295
- return () => {
296
- notifyRef.current = void 0;
297
- };
298
- }, []);
299
- const getSnapshot = (0, import_react.useCallback)(() => versionRef.current, []);
300
- (0, import_react.useSyncExternalStore)(subscribe2, getSnapshot, getSnapshot);
301
- const proxy = new Proxy(store, {
302
- get(target, prop, receiver) {
303
- const prev = getActiveListener();
304
- setActiveListener(listener);
305
- try {
306
- return Reflect.get(target, prop, receiver);
307
- } finally {
308
- setActiveListener(prev);
309
- }
310
- }
311
- });
312
- return proxy;
313
- }
314
-
315
- // src/addon/signals.ts
48
+ // src/signals.ts
316
49
  var import_signals_core = require("@preact/signals-core");
317
50
  function createSignal(initialValue, options) {
318
51
  const s = (0, import_signals_core.signal)(initialValue);
319
- let unsubscribeActive;
320
52
  let subscriberCount = 0;
321
53
  return {
322
54
  get: () => s.value,
@@ -338,9 +70,122 @@ function createSignal(initialValue, options) {
338
70
  options?.onInactive?.();
339
71
  }
340
72
  };
341
- }
73
+ },
74
+ isWatched: () => subscriberCount > 0
342
75
  };
343
76
  }
77
+ function computed(fn) {
78
+ const c = (0, import_signals_core.computed)(fn);
79
+ let subscriberCount = 0;
80
+ return {
81
+ get: () => c.value,
82
+ set: () => {
83
+ throw new Error("[Quantum] Cannot set a computed signal directly.");
84
+ },
85
+ subscribe: (fn2) => {
86
+ subscriberCount++;
87
+ const dispose = (0, import_signals_core.effect)(() => {
88
+ fn2(c.value);
89
+ });
90
+ return () => {
91
+ dispose();
92
+ subscriberCount--;
93
+ };
94
+ },
95
+ isWatched: () => subscriberCount > 0
96
+ };
97
+ }
98
+ function effect(fn) {
99
+ return (0, import_signals_core.effect)(fn);
100
+ }
101
+ function untracked(fn) {
102
+ return (0, import_signals_core.untracked)(fn);
103
+ }
104
+
105
+ // src/store/model.ts
106
+ function atom(initialValue, options) {
107
+ const s = createSignal(initialValue);
108
+ if (options?.key) {
109
+ setupPersistence(s, options);
110
+ }
111
+ return s;
112
+ }
113
+ function setupPersistence(s, options) {
114
+ const { key, storage = "local", debug } = options;
115
+ if (!key) return;
116
+ let engine = null;
117
+ if (typeof storage === "string") {
118
+ if (typeof window !== "undefined") {
119
+ engine = storage === "local" ? window.localStorage : window.sessionStorage;
120
+ }
121
+ } else {
122
+ engine = storage;
123
+ }
124
+ if (!engine) return;
125
+ try {
126
+ const stored = engine.getItem(key);
127
+ const applyValue = (val) => {
128
+ try {
129
+ const parsed = JSON.parse(val);
130
+ const validated = options.validate ? options.validate(parsed) : parsed;
131
+ s.set(validated);
132
+ if (debug) console.log(`[Quantum] Hydrated atom '${key}'`);
133
+ } catch (e) {
134
+ if (debug) console.error(`[Quantum] Hydration validation failed for '${key}'`, e);
135
+ }
136
+ };
137
+ if (stored instanceof Promise) {
138
+ stored.then((val) => {
139
+ if (val) applyValue(val);
140
+ });
141
+ } else if (stored) {
142
+ applyValue(stored);
143
+ }
144
+ } catch (err) {
145
+ if (debug) console.error(`[Quantum] Hydration error`, err);
146
+ }
147
+ s.subscribe((value) => {
148
+ try {
149
+ const serialized = JSON.stringify(value);
150
+ engine.setItem(key, serialized);
151
+ if (debug) console.log(`[Quantum] Saved atom '${key}'`);
152
+ } catch (err) {
153
+ if (debug) console.error(`[Quantum] Save error`, err);
154
+ }
155
+ });
156
+ }
157
+
158
+ // src/react/SignalValue.tsx
159
+ var import_react = require("react");
160
+ var import_jsx_runtime = require("react/jsx-runtime");
161
+ function SignalValue({ signal: signal2, render, children }) {
162
+ const [value, setValue] = (0, import_react.useState)(() => signal2.get());
163
+ (0, import_react.useEffect)(() => {
164
+ const unsubscribe = signal2.subscribe((newValue) => {
165
+ setValue(newValue);
166
+ });
167
+ return () => unsubscribe();
168
+ }, [signal2]);
169
+ const renderer = render || children;
170
+ if (!renderer) return null;
171
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: renderer(value) });
172
+ }
173
+
174
+ // src/store/scheduler.ts
175
+ var pending = /* @__PURE__ */ new Set();
176
+ var timer = null;
177
+ function flush() {
178
+ timer = null;
179
+ const tasks = [...pending];
180
+ pending.clear();
181
+ tasks.forEach((task) => task());
182
+ }
183
+ function scheduleUpdate(callback) {
184
+ pending.add(callback);
185
+ if (!timer) {
186
+ timer = Promise.resolve().then(flush);
187
+ }
188
+ }
344
189
 
345
190
  // src/devtools/registry.ts
346
191
  var stores = createSignal([]);
@@ -354,30 +199,10 @@ function registerStore(store, name = "Store") {
354
199
  // src/middleware/devtools.ts
355
200
  function enableDevTools(store, name = "Store") {
356
201
  registerStore(store, name);
357
- if (typeof window === "undefined" || !window.__REDUX_DEVTOOLS_EXTENSION__) return;
358
- const devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect({ name });
359
- devTools.init(store);
360
- subscribe(store, (target, prop, value) => {
361
- devTools.send({ type: `SET_${String(prop)}`, payload: value }, store);
362
- });
363
- }
364
-
365
- // src/core/computed.ts
366
- function computed(fn) {
367
- let value;
368
- let dirty = true;
369
- return {
370
- get value() {
371
- if (dirty) {
372
- value = fn();
373
- dirty = false;
374
- }
375
- return value;
376
- }
377
- };
202
+ console.warn("DevTools for Signals are WIP");
378
203
  }
379
204
 
380
- // src/addon/clientTypes.ts
205
+ // src/clientTypes.ts
381
206
  var HttpError = class extends Error {
382
207
  constructor(status, message) {
383
208
  super(message);
@@ -386,7 +211,7 @@ var HttpError = class extends Error {
386
211
  }
387
212
  };
388
213
 
389
- // src/addon/middleware/types.ts
214
+ // src/middleware/types.ts
390
215
  function compose(middleware) {
391
216
  return (ctx, next) => {
392
217
  let index = -1;
@@ -405,7 +230,7 @@ function compose(middleware) {
405
230
  };
406
231
  }
407
232
 
408
- // src/addon/middleware/dedupe.ts
233
+ // src/middleware/dedupe.ts
409
234
  var DedupeMiddleware = async (ctx, next) => {
410
235
  if (ctx.req.method !== "GET") {
411
236
  return next(ctx);
@@ -431,10 +256,10 @@ var DedupeMiddleware = async (ctx, next) => {
431
256
  }
432
257
  };
433
258
 
434
- // src/addon/middleware/cache.ts
259
+ // src/middleware/cache.ts
435
260
  var CacheMiddleware = async (ctx, next) => {
436
261
  const { method, url } = ctx.req;
437
- const { cache: cacheConfig } = ctx.config;
262
+ const cacheConfig = typeof ctx.config.cache === "object" ? ctx.config.cache : void 0;
438
263
  if (method !== "GET" || !cacheConfig?.ttl || cacheConfig.force) {
439
264
  return next(ctx);
440
265
  }
@@ -467,7 +292,7 @@ var CacheMiddleware = async (ctx, next) => {
467
292
  return response;
468
293
  };
469
294
 
470
- // src/addon/middleware/auth.ts
295
+ // src/middleware/auth.ts
471
296
  var AuthMiddleware = async (ctx, next) => {
472
297
  const { auth } = ctx.client.config;
473
298
  if (auth && auth.getToken && !ctx.req.headers.get("Authorization")) {
@@ -512,7 +337,7 @@ var AuthMiddleware = async (ctx, next) => {
512
337
  return response;
513
338
  };
514
339
 
515
- // src/addon/middleware/fetch.ts
340
+ // src/middleware/fetch.ts
516
341
  var FetchMiddleware = async (ctx) => {
517
342
  return fetch(ctx.req);
518
343
  };
@@ -550,7 +375,7 @@ var RetryMiddleware = async (ctx, next) => {
550
375
  return attempt(0);
551
376
  };
552
377
 
553
- // src/addon/httpClient.ts
378
+ // src/httpClient.ts
554
379
  function createHttpClient(config) {
555
380
  const cache = /* @__PURE__ */ new Map();
556
381
  const inflight = /* @__PURE__ */ new Map();
@@ -585,15 +410,17 @@ function createHttpClient(config) {
585
410
  controller.abort();
586
411
  });
587
412
  }
413
+ const { cache: _c, schema: _s, timeout: _t, retry: _r, ...fetchOptions } = options;
588
414
  let req = new Request(url, {
589
- ...options,
415
+ ...fetchOptions,
590
416
  headers,
591
417
  signal: controller.signal
592
418
  });
593
419
  if (config.interceptors?.request) {
594
420
  const newConfig = await config.interceptors.request({ ...options, headers: Object.fromEntries(headers) });
421
+ const { cache: _nc, schema: _ns, timeout: _nt, retry: _nr, ...newFetchOptions } = newConfig;
595
422
  req = new Request(url, {
596
- ...newConfig,
423
+ ...newFetchOptions,
597
424
  signal: controller.signal
598
425
  });
599
426
  }
@@ -634,8 +461,9 @@ function createHttpClient(config) {
634
461
  if (options.schema.parse) return options.schema.parse(data);
635
462
  if (options.schema.validateSync) return options.schema.validateSync(data);
636
463
  } catch (error) {
637
- if (error.errors || error.name === "ZodError" || error.name === "ValidationError") {
638
- throw new Error(`Validation Error: ${JSON.stringify(error.errors || error.message)}`);
464
+ const err = error;
465
+ if (err.errors || err.name === "ZodError" || err.name === "ValidationError") {
466
+ throw new Error(`Validation Error: ${JSON.stringify(err.errors || err.message)}`);
639
467
  }
640
468
  throw error;
641
469
  }
@@ -665,56 +493,168 @@ function createHttpClient(config) {
665
493
  return client;
666
494
  }
667
495
 
668
- // src/addon/query/utils.ts
669
- function stableHash(value) {
670
- if (value === null || typeof value !== "object") {
671
- return String(value);
496
+ // src/store/asyncUtils.ts
497
+ var PROMISE_CACHE = /* @__PURE__ */ new WeakMap();
498
+ var PROMISE_STATUS = /* @__PURE__ */ new WeakMap();
499
+ var PROMISE_ERROR = /* @__PURE__ */ new WeakMap();
500
+ function isPromise(value) {
501
+ return !!value && typeof value.then === "function";
502
+ }
503
+ function handlePromise(promise, triggerUpdate) {
504
+ if (PROMISE_STATUS.has(promise)) return;
505
+ PROMISE_STATUS.set(promise, "pending");
506
+ promise.then(
507
+ (value) => {
508
+ PROMISE_STATUS.set(promise, "fulfilled");
509
+ PROMISE_CACHE.set(promise, value);
510
+ triggerUpdate();
511
+ },
512
+ (error) => {
513
+ PROMISE_STATUS.set(promise, "rejected");
514
+ PROMISE_ERROR.set(promise, error);
515
+ triggerUpdate();
516
+ }
517
+ );
518
+ }
519
+ function unwrapPromise(promise) {
520
+ const status = PROMISE_STATUS.get(promise);
521
+ if (status === "fulfilled") {
522
+ return PROMISE_CACHE.get(promise);
523
+ } else if (status === "rejected") {
524
+ throw PROMISE_ERROR.get(promise);
525
+ } else {
526
+ throw promise;
527
+ }
528
+ }
529
+ function getPromiseState(promise) {
530
+ return {
531
+ status: PROMISE_STATUS.get(promise) || "pending",
532
+ value: PROMISE_CACHE.get(promise),
533
+ error: PROMISE_ERROR.get(promise)
534
+ };
535
+ }
536
+
537
+ // src/query/utils.ts
538
+ function stableHash(value, depth = 0) {
539
+ if (depth > 15) {
540
+ throw new Error("[Quantum] Query key is too deeply nested. Max depth is 15.");
541
+ }
542
+ if (value === null) return "null";
543
+ if (value === void 0) return "undefined";
544
+ if (typeof value !== "object") {
545
+ const strValue = String(value);
546
+ if (strValue.length > 1e3) {
547
+ return `${typeof value}:[large-string:${strValue.slice(0, 10)}...]`;
548
+ }
549
+ return `${typeof value}:${strValue}`;
672
550
  }
673
551
  if (Array.isArray(value)) {
674
- return "[" + value.map(stableHash).join(",") + "]";
552
+ return `array:[${value.map((v) => stableHash(v, depth + 1)).join(",")}]`;
675
553
  }
676
554
  const keys = Object.keys(value).sort();
677
- return "{" + keys.map((key) => `${key}:${stableHash(value[key])}`).join(",") + "}";
555
+ return `object:{${keys.map((key) => `${key}:${stableHash(value[key], depth + 1)}`).join(",")}}`;
556
+ }
557
+ function isDeepEqual(a, b) {
558
+ if (a === b) return true;
559
+ if (a && b && typeof a === "object" && typeof b === "object") {
560
+ const objA = a;
561
+ const objB = b;
562
+ if (objA.constructor !== objB.constructor) return false;
563
+ let length, i, keys;
564
+ if (Array.isArray(a)) {
565
+ const arrA = a;
566
+ const arrB = b;
567
+ length = arrA.length;
568
+ if (length !== arrB.length) return false;
569
+ for (i = length; i-- !== 0; ) {
570
+ if (!isDeepEqual(arrA[i], arrB[i])) return false;
571
+ }
572
+ return true;
573
+ }
574
+ if (objA.valueOf !== Object.prototype.valueOf) return objA.valueOf() === objB.valueOf();
575
+ if (objA.toString !== Object.prototype.toString) return objA.toString() === objB.toString();
576
+ keys = Object.keys(objA);
577
+ length = keys.length;
578
+ if (length !== Object.keys(objB).length) return false;
579
+ for (const key of keys) {
580
+ if (!Object.prototype.hasOwnProperty.call(objB, key)) return false;
581
+ }
582
+ for (const key of keys) {
583
+ if (!isDeepEqual(objA[key], objB[key])) return false;
584
+ }
585
+ return true;
586
+ }
587
+ return a !== a && b !== b;
678
588
  }
679
589
 
680
- // src/addon/query/queryStorage.ts
590
+ // src/query/queryStorage.ts
681
591
  var QueryStorage = class {
592
+ // Tracks access order (least to most recent)
682
593
  // Default configuration
683
- constructor(defaultStaleTime = 0, defaultCacheTime = 5 * 60 * 1e3) {
594
+ constructor(defaultStaleTime = 0, defaultCacheTime = 5 * 60 * 1e3, maxSize = 100) {
684
595
  this.defaultStaleTime = defaultStaleTime;
685
596
  this.defaultCacheTime = defaultCacheTime;
597
+ this.maxSize = maxSize;
686
598
  }
687
599
  signals = /* @__PURE__ */ new Map();
688
600
  gcTimers = /* @__PURE__ */ new Map();
601
+ lruOrder = /* @__PURE__ */ new Set();
689
602
  generateKey(queryKey) {
690
603
  const key = Array.isArray(queryKey) ? stableHash(queryKey) : stableHash([queryKey.key, queryKey.params]);
691
604
  return key;
692
605
  }
693
606
  get(key, autoCreate = true) {
694
607
  let signal2 = this.signals.get(key);
608
+ if (signal2) {
609
+ this.touch(key);
610
+ }
695
611
  if (!signal2 && autoCreate) {
696
612
  const newSignal = createSignal(void 0, {
697
613
  onActive: () => {
698
614
  this.cancelGC(key);
699
615
  },
700
616
  onInactive: () => {
701
- const entry = this.signals.get(key)?.get();
702
- const cacheTime = entry?.cacheTime ?? this.defaultCacheTime;
617
+ const currentEntry = this.signals.get(key)?.get();
618
+ const cacheTime = currentEntry?.cacheTime ?? this.defaultCacheTime;
703
619
  this.scheduleGC(key, cacheTime);
704
620
  }
705
621
  });
706
622
  this.signals.set(key, newSignal);
623
+ this.touch(key);
624
+ if (!newSignal.isWatched()) {
625
+ this.scheduleGC(key, this.defaultCacheTime);
626
+ }
627
+ this.enforceMaxSize();
707
628
  signal2 = newSignal;
708
629
  }
709
- if (!signal2) return void 0;
710
630
  return signal2;
711
631
  }
632
+ tagIndex = /* @__PURE__ */ new Map();
712
633
  set(key, entry) {
713
- const signal2 = this.signals.get(key);
634
+ this.touch(key);
635
+ const oldEntry = this.signals.get(key)?.get();
636
+ if (oldEntry?.tags) {
637
+ for (const tag of oldEntry.tags) {
638
+ const set = this.tagIndex.get(tag);
639
+ if (set) {
640
+ set.delete(key);
641
+ if (set.size === 0) this.tagIndex.delete(tag);
642
+ }
643
+ }
644
+ }
645
+ if (entry.tags) {
646
+ for (const tag of entry.tags) {
647
+ if (!this.tagIndex.has(tag)) {
648
+ this.tagIndex.set(tag, /* @__PURE__ */ new Set());
649
+ }
650
+ this.tagIndex.get(tag).add(key);
651
+ }
652
+ }
653
+ let signal2 = this.signals.get(key);
714
654
  if (signal2) {
715
655
  signal2.set(entry);
716
656
  } else {
717
- this.signals.set(key, createSignal(entry, {
657
+ const newSignal = createSignal(entry, {
718
658
  onActive: () => {
719
659
  this.cancelGC(key);
720
660
  },
@@ -723,15 +663,50 @@ var QueryStorage = class {
723
663
  const cacheTime = entry2?.cacheTime ?? this.defaultCacheTime;
724
664
  this.scheduleGC(key, cacheTime);
725
665
  }
726
- }));
666
+ });
667
+ this.signals.set(key, newSignal);
668
+ if (!newSignal.isWatched()) {
669
+ this.scheduleGC(key, entry.cacheTime ?? this.defaultCacheTime);
670
+ }
671
+ this.enforceMaxSize();
727
672
  }
728
673
  }
729
674
  delete(key) {
675
+ const entry = this.signals.get(key)?.get();
676
+ if (entry?.tags) {
677
+ for (const tag of entry.tags) {
678
+ const set = this.tagIndex.get(tag);
679
+ if (set) {
680
+ set.delete(key);
681
+ if (set.size === 0) this.tagIndex.delete(tag);
682
+ }
683
+ }
684
+ }
730
685
  this.signals.delete(key);
686
+ this.lruOrder.delete(key);
731
687
  this.cancelGC(key);
732
688
  }
689
+ touch(key) {
690
+ this.lruOrder.delete(key);
691
+ this.lruOrder.add(key);
692
+ }
693
+ enforceMaxSize() {
694
+ if (this.signals.size <= this.maxSize) return;
695
+ for (const key of this.lruOrder) {
696
+ const signal2 = this.signals.get(key);
697
+ if (signal2 && !signal2.isWatched()) {
698
+ this.delete(key);
699
+ if (this.signals.size <= this.maxSize) break;
700
+ }
701
+ }
702
+ }
703
+ getKeysByTag(tag) {
704
+ return this.tagIndex.get(tag);
705
+ }
733
706
  clear() {
734
707
  this.signals.clear();
708
+ this.tagIndex.clear();
709
+ this.lruOrder.clear();
735
710
  this.gcTimers.forEach((timer2) => clearTimeout(timer2));
736
711
  this.gcTimers.clear();
737
712
  }
@@ -746,11 +721,19 @@ var QueryStorage = class {
746
721
  getStats() {
747
722
  return {
748
723
  size: this.signals.size,
749
- keys: Array.from(this.signals.keys())
724
+ keys: Array.from(this.signals.keys()),
725
+ tags: this.tagIndex.size
750
726
  };
751
727
  }
752
728
  getSnapshot() {
753
- return this.signals;
729
+ const snapshot = /* @__PURE__ */ new Map();
730
+ for (const [key, signal2] of this.signals.entries()) {
731
+ const value = signal2.get();
732
+ if (value) {
733
+ snapshot.set(key, value);
734
+ }
735
+ }
736
+ return snapshot;
754
737
  }
755
738
  // --- GC Logic ---
756
739
  scheduleGC(key, delay2) {
@@ -770,7 +753,7 @@ var QueryStorage = class {
770
753
  }
771
754
  };
772
755
 
773
- // src/addon/query/remotes.ts
756
+ // src/query/remotes.ts
774
757
  var QueryRemotes = class {
775
758
  deduplicationCache = /* @__PURE__ */ new Map();
776
759
  async fetch(key, fn, options) {
@@ -833,7 +816,7 @@ var QueryRemotes = class {
833
816
  }
834
817
  };
835
818
 
836
- // src/addon/query/mutationCache.ts
819
+ // src/query/mutationCache.ts
837
820
  var MutationCache = class {
838
821
  // Map<ID, Signal> - Stores state for every unique mutation execution
839
822
  mutations = /* @__PURE__ */ new Map();
@@ -912,9 +895,13 @@ var MutationCache = class {
912
895
  };
913
896
  };
914
897
 
915
- // src/addon/query/pluginManager.ts
898
+ // src/query/pluginManager.ts
916
899
  var PluginManager = class {
917
900
  plugins = [];
901
+ client;
902
+ setClient(client) {
903
+ this.client = client;
904
+ }
918
905
  add(plugin) {
919
906
  this.plugins.push(plugin);
920
907
  }
@@ -935,8 +922,16 @@ var PluginManager = class {
935
922
  }
936
923
  };
937
924
 
938
- // src/addon/query/queryCache.ts
939
- var QueryCache = class {
925
+ // src/query/plugins/validation.ts
926
+ function validateWithSchema(data, schema) {
927
+ if (!schema) {
928
+ return data;
929
+ }
930
+ return schema.parse(data);
931
+ }
932
+
933
+ // src/query/queryClient.ts
934
+ var QueryClient = class {
940
935
  // Components
941
936
  storage;
942
937
  remotes;
@@ -947,11 +942,18 @@ var QueryCache = class {
947
942
  // Config defaults
948
943
  defaultStaleTime;
949
944
  defaultCacheTime;
945
+ defaultSchema;
950
946
  constructor(config) {
951
947
  this.defaultStaleTime = config?.defaultStaleTime ?? 0;
952
948
  this.defaultCacheTime = config?.defaultCacheTime ?? 5 * 60 * 1e3;
953
- this.storage = new QueryStorage(this.defaultStaleTime, this.defaultCacheTime);
949
+ this.defaultSchema = config?.defaultSchema;
950
+ this.storage = new QueryStorage(
951
+ this.defaultStaleTime,
952
+ this.defaultCacheTime,
953
+ config?.maxCacheSize
954
+ );
954
955
  this.remotes = new QueryRemotes();
956
+ this.pluginManager.setClient(this);
955
957
  }
956
958
  // --- FACADE API ---
957
959
  /**
@@ -962,7 +964,7 @@ var QueryCache = class {
962
964
  const signal2 = this.storage.get(key, false);
963
965
  if (!signal2) return void 0;
964
966
  const entry = signal2.get();
965
- if (!entry) return void 0;
967
+ if (!this.isCacheEntry(entry)) return void 0;
966
968
  const now = Date.now();
967
969
  const age = now - entry.timestamp;
968
970
  if (age > entry.cacheTime) {
@@ -1017,18 +1019,18 @@ var QueryCache = class {
1017
1019
  const direction = options?.fetchDirection || "initial";
1018
1020
  const signal2 = this.storage.get(key, true);
1019
1021
  const currentEntry = signal2.get();
1022
+ const mergedTags = options?.tags ?? currentEntry?.tags;
1020
1023
  this.storage.set(key, {
1021
1024
  data: currentEntry?.data,
1022
1025
  status: currentEntry?.status || "pending",
1023
1026
  error: null,
1024
1027
  isFetching: true,
1025
- // Mark fetching
1026
1028
  fetchDirection: direction,
1027
1029
  timestamp: currentEntry?.timestamp || Date.now(),
1028
1030
  staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
1029
1031
  cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
1030
1032
  key: queryKey,
1031
- tags: currentEntry?.tags
1033
+ tags: mergedTags
1032
1034
  });
1033
1035
  this.pluginManager.onFetchStart(normalizedKey);
1034
1036
  try {
@@ -1037,21 +1039,40 @@ var QueryCache = class {
1037
1039
  retry: options?.retry,
1038
1040
  retryDelay: options?.retryDelay
1039
1041
  });
1040
- this.pluginManager.onFetchSuccess(normalizedKey, data);
1041
- return data;
1042
+ this.storage.set(key, {
1043
+ data,
1044
+ status: "success",
1045
+ error: null,
1046
+ isFetching: false,
1047
+ isInvalidated: void 0,
1048
+ // Clear invalidation on success
1049
+ fetchDirection: "idle",
1050
+ timestamp: Date.now(),
1051
+ staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
1052
+ cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
1053
+ key: queryKey,
1054
+ tags: mergedTags
1055
+ });
1056
+ const schema = options?.schema || this.defaultSchema;
1057
+ const validatedData = validateWithSchema(data, schema);
1058
+ this.pluginManager.onFetchSuccess(normalizedKey, validatedData);
1059
+ return validatedData;
1042
1060
  } catch (error) {
1043
- const current = signal2.get();
1044
- if (current) {
1045
- this.storage.set(key, {
1046
- ...current,
1047
- status: "error",
1048
- error,
1049
- isFetching: false,
1050
- fetchDirection: "idle"
1051
- });
1052
- }
1053
- this.pluginManager.onFetchError(normalizedKey, error);
1054
- throw error;
1061
+ const err = error instanceof Error ? error : new Error(String(error));
1062
+ this.storage.set(key, {
1063
+ data: currentEntry?.data,
1064
+ status: "error",
1065
+ error: err,
1066
+ isFetching: false,
1067
+ fetchDirection: "idle",
1068
+ timestamp: currentEntry?.timestamp || Date.now(),
1069
+ staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
1070
+ cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
1071
+ key: queryKey,
1072
+ tags: mergedTags
1073
+ });
1074
+ this.pluginManager.onFetchError(normalizedKey, err);
1075
+ throw err;
1055
1076
  }
1056
1077
  };
1057
1078
  /**
@@ -1076,12 +1097,17 @@ var QueryCache = class {
1076
1097
  };
1077
1098
  invalidateTags = (tags) => {
1078
1099
  const tagsToInvalidate = new Set(tags);
1079
- const snapshot = this.storage.getSnapshot();
1080
- for (const [key, signal2] of snapshot.entries()) {
1081
- const entry = signal2.get();
1082
- if (entry && entry.tags) {
1083
- if (entry.tags.some((tag) => tagsToInvalidate.has(tag))) {
1084
- signal2.set({ ...entry, isInvalidated: true });
1100
+ for (const tag of tagsToInvalidate) {
1101
+ const keys = this.storage.getKeysByTag(tag);
1102
+ if (keys) {
1103
+ for (const key of keys) {
1104
+ const signal2 = this.storage.get(key, false);
1105
+ if (signal2) {
1106
+ const current = signal2.get();
1107
+ if (current) {
1108
+ signal2.set({ ...current, isInvalidated: true });
1109
+ }
1110
+ }
1085
1111
  }
1086
1112
  }
1087
1113
  }
@@ -1114,8 +1140,9 @@ var QueryCache = class {
1114
1140
  // For Hydration
1115
1141
  getSnapshot = () => this.storage.getSnapshot();
1116
1142
  invalidateAll = () => {
1117
- for (const key of this.storage.getSnapshot().keys()) {
1118
- const signal2 = this.storage.get(key);
1143
+ const snapshot = this.storage.getSnapshot();
1144
+ for (const key of snapshot.keys()) {
1145
+ const signal2 = this.storage.get(key, false);
1119
1146
  const entry = signal2?.get();
1120
1147
  if (entry) {
1121
1148
  signal2?.set({ ...entry, isInvalidated: true });
@@ -1125,20 +1152,30 @@ var QueryCache = class {
1125
1152
  normalizeKey(queryKey) {
1126
1153
  return Array.isArray(queryKey) ? queryKey : [queryKey.key, queryKey.params];
1127
1154
  }
1155
+ isCacheEntry(entry) {
1156
+ return entry !== null && typeof entry === "object" && "status" in entry && "timestamp" in entry;
1157
+ }
1158
+ // --- DEBUGGER API (For DevTools) ---
1159
+ debugSet = (key, data) => {
1160
+ this.set(key, data);
1161
+ };
1162
+ debugInvalidate = (key) => {
1163
+ this.invalidate(key);
1164
+ };
1128
1165
  };
1129
1166
 
1130
- // src/addon/query/pagination.ts
1167
+ // src/query/pagination.ts
1131
1168
  var import_react3 = require("react");
1132
1169
 
1133
- // src/addon/query/context.tsx
1170
+ // src/query/context.tsx
1134
1171
  var import_react2 = require("react");
1135
- var import_jsx_runtime = require("react/jsx-runtime");
1172
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1136
1173
  var QueryClientContext = (0, import_react2.createContext)(void 0);
1137
1174
  var QueryClientProvider = ({
1138
1175
  client,
1139
1176
  children
1140
1177
  }) => {
1141
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(QueryClientContext.Provider, { value: client, children });
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(QueryClientContext.Provider, { value: client, children: children || null });
1142
1179
  };
1143
1180
  var useQueryClient = () => {
1144
1181
  const client = (0, import_react2.useContext)(QueryClientContext);
@@ -1148,7 +1185,7 @@ var useQueryClient = () => {
1148
1185
  return client;
1149
1186
  };
1150
1187
 
1151
- // src/addon/query/pagination.ts
1188
+ // src/query/pagination.ts
1152
1189
  function usePaginatedQuery({
1153
1190
  queryKey,
1154
1191
  queryFn,
@@ -1162,7 +1199,7 @@ function usePaginatedQuery({
1162
1199
  const [page, setPage] = (0, import_react3.useState)(0);
1163
1200
  const pageQueryKey = [...queryKey, "page", page];
1164
1201
  const pageQueryKeyHash = JSON.stringify(pageQueryKey);
1165
- const subscribe2 = (0, import_react3.useCallback)((onStoreChange) => {
1202
+ const subscribe = (0, import_react3.useCallback)((onStoreChange) => {
1166
1203
  const signal2 = client.getSignal(pageQueryKey);
1167
1204
  return signal2.subscribe(() => onStoreChange());
1168
1205
  }, [client, pageQueryKeyHash]);
@@ -1170,7 +1207,7 @@ function usePaginatedQuery({
1170
1207
  const signal2 = client.getSignal(pageQueryKey);
1171
1208
  return signal2.get();
1172
1209
  }, [client, pageQueryKeyHash]);
1173
- const cacheEntry = (0, import_react3.useSyncExternalStore)(subscribe2, getSnapshot);
1210
+ const cacheEntry = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot);
1174
1211
  const data = cacheEntry?.data;
1175
1212
  const status = cacheEntry?.status || "pending";
1176
1213
  const error = cacheEntry?.error || null;
@@ -1183,7 +1220,7 @@ function usePaginatedQuery({
1183
1220
  if (Array.isArray(data)) {
1184
1221
  hasNext = data.length === pageSize;
1185
1222
  } else if (typeof data === "object" && "hasMore" in data) {
1186
- hasNext = data.hasMore;
1223
+ hasNext = !!data.hasMore;
1187
1224
  }
1188
1225
  }
1189
1226
  const hasPrevious = page > 0;
@@ -1248,289 +1285,263 @@ function usePaginatedQuery({
1248
1285
  };
1249
1286
  }
1250
1287
 
1251
- // src/addon/query/useQuery.ts
1288
+ // src/query/useQuery.ts
1252
1289
  var import_react4 = require("react");
1253
1290
 
1254
- // src/addon/query/plugins/validation.ts
1255
- function validateWithSchema(data, schema) {
1256
- if (!schema) {
1257
- return data;
1291
+ // src/query/focusManager.ts
1292
+ var FocusManager = class {
1293
+ listeners = /* @__PURE__ */ new Set();
1294
+ focused = true;
1295
+ unsubscribe = null;
1296
+ constructor() {
1297
+ if (typeof window !== "undefined" && window.addEventListener) {
1298
+ const handleFocus = () => {
1299
+ this.focused = true;
1300
+ this.onFocus();
1301
+ };
1302
+ const handleBlur = () => {
1303
+ this.focused = false;
1304
+ };
1305
+ window.addEventListener("focus", handleFocus, false);
1306
+ window.addEventListener("visibilitychange", handleFocus, false);
1307
+ window.addEventListener("blur", handleBlur, false);
1308
+ this.unsubscribe = () => {
1309
+ window.removeEventListener("focus", handleFocus);
1310
+ window.removeEventListener("visibilitychange", handleFocus);
1311
+ window.removeEventListener("blur", handleBlur);
1312
+ };
1313
+ }
1258
1314
  }
1259
- return schema.parse(data);
1260
- }
1315
+ onFocus() {
1316
+ this.listeners.forEach((listener) => listener());
1317
+ }
1318
+ subscribe(listener) {
1319
+ this.listeners.add(listener);
1320
+ return () => this.listeners.delete(listener);
1321
+ }
1322
+ isFocused() {
1323
+ return this.focused;
1324
+ }
1325
+ setFocused(focused) {
1326
+ this.focused = focused;
1327
+ if (focused) this.onFocus();
1328
+ }
1329
+ };
1330
+ var focusManager = new FocusManager();
1331
+
1332
+ // src/query/onlineManager.ts
1333
+ var OnlineManager = class {
1334
+ listeners = /* @__PURE__ */ new Set();
1335
+ online = true;
1336
+ constructor() {
1337
+ if (typeof window !== "undefined" && window.addEventListener) {
1338
+ window.addEventListener("online", () => this.setOnline(true), false);
1339
+ window.addEventListener("offline", () => this.setOnline(false), false);
1340
+ this.online = navigator.onLine;
1341
+ }
1342
+ }
1343
+ setOnline(online) {
1344
+ this.online = online;
1345
+ this.listeners.forEach((listener) => listener(online));
1346
+ }
1347
+ subscribe(listener) {
1348
+ this.listeners.add(listener);
1349
+ return () => this.listeners.delete(listener);
1350
+ }
1351
+ isOnline() {
1352
+ return this.online;
1353
+ }
1354
+ };
1355
+ var onlineManager = new OnlineManager();
1261
1356
 
1262
- // src/addon/query/queryObserver.ts
1357
+ // src/query/queryObserver.ts
1263
1358
  var QueryObserver = class {
1264
1359
  client;
1265
- options;
1266
- queryKeyHash;
1267
- signal;
1268
- listeners = /* @__PURE__ */ new Set();
1269
- // Internal state management
1360
+ // Reactive Inputs
1361
+ options$;
1362
+ // Reactive Outputs
1363
+ result$;
1364
+ // Internal
1365
+ unsubscribe = null;
1366
+ gcUnsubscribe = null;
1270
1367
  abortController = null;
1271
1368
  intervalParams = { id: null };
1272
- unsubscribeSignal = null;
1273
- // Derived state cache to ensure referential stability where possible
1274
- currentResult;
1275
1369
  constructor(client, options) {
1276
1370
  this.client = client;
1277
- this.options = options;
1278
- this.queryKeyHash = stableHash(options.queryKey);
1279
- this.signal = client.getSignal(options.queryKey);
1280
- }
1281
- setOptions(options) {
1282
- const prevOptions = this.options;
1283
- this.options = options;
1284
- const newHash = stableHash(options.queryKey);
1285
- if (newHash !== this.queryKeyHash) {
1286
- this.queryKeyHash = newHash;
1287
- this.updateSignal();
1288
- this.checkAndFetch();
1289
- } else {
1290
- if (options.enabled && !prevOptions.enabled) {
1291
- this.checkAndFetch();
1371
+ this.options$ = createSignal(options);
1372
+ let lastResult = null;
1373
+ this.result$ = computed(() => {
1374
+ const opts = this.options$.get();
1375
+ const queryKey = opts.queryKey;
1376
+ const cacheSignal = this.client.getSignal(queryKey);
1377
+ const entry = cacheSignal.get();
1378
+ const data = entry?.data;
1379
+ const status = entry?.status || "pending";
1380
+ const error = entry?.error || null;
1381
+ const isFetching = entry?.isFetching || false;
1382
+ const staleTime = opts.staleTime ?? 0;
1383
+ const now = Date.now();
1384
+ const dataTimestamp = entry?.timestamp;
1385
+ const diff = dataTimestamp ? now - dataTimestamp : -1;
1386
+ const isTimeStale = dataTimestamp ? diff > staleTime : true;
1387
+ const isStale = entry?.isInvalidated || isTimeStale;
1388
+ const isError = status === "error";
1389
+ const isSuccess = status === "success";
1390
+ const isPending = status === "pending";
1391
+ const isLoading = data === void 0 && isFetching;
1392
+ let finalData;
1393
+ if (data !== void 0) {
1394
+ try {
1395
+ finalData = opts.select ? opts.select(data) : data;
1396
+ } catch (e) {
1397
+ return {
1398
+ ...lastResult ?? {},
1399
+ status: "error",
1400
+ error: e,
1401
+ isError: true
1402
+ };
1403
+ }
1292
1404
  }
1293
- }
1294
- if (options.refetchInterval !== prevOptions.refetchInterval) {
1295
- this.setupInterval();
1296
- }
1297
- }
1298
- subscribe(listener) {
1299
- this.listeners.add(listener);
1300
- if (this.listeners.size === 1) {
1301
- this.init();
1302
- }
1303
- return () => {
1304
- this.listeners.delete(listener);
1305
- if (this.listeners.size === 0) {
1306
- this.destroy();
1405
+ const nextResult = {
1406
+ data: finalData,
1407
+ isLoading,
1408
+ isError,
1409
+ isSuccess,
1410
+ isPending,
1411
+ isFetching,
1412
+ isStale,
1413
+ error,
1414
+ status,
1415
+ refetch: this.refetch
1416
+ };
1417
+ const isDataEqual = lastResult?.data === nextResult.data || isDeepEqual(lastResult?.data, nextResult.data);
1418
+ if (lastResult && isDataEqual && lastResult.status === nextResult.status && lastResult.isFetching === nextResult.isFetching && lastResult.isStale === nextResult.isStale && lastResult.error === nextResult.error) {
1419
+ return lastResult;
1307
1420
  }
1308
- };
1309
- }
1310
- init() {
1311
- this.updateSignal();
1312
- this.setupGlobalListeners();
1313
- this.setupInterval();
1314
- this.checkAndFetch();
1421
+ lastResult = nextResult;
1422
+ return nextResult;
1423
+ });
1424
+ this.initSideEffects();
1315
1425
  }
1316
- destroy() {
1317
- this.cleanupGlobalListeners();
1318
- this.cleanupInterval();
1319
- if (this.unsubscribeSignal) {
1320
- this.unsubscribeSignal();
1321
- this.unsubscribeSignal = null;
1322
- }
1323
- if (this.abortController) {
1324
- this.abortController.abort();
1426
+ setOptions(options) {
1427
+ const current = this.options$.get();
1428
+ if (current === options) return;
1429
+ const isKeyEqual = stableHash(current.queryKey) === stableHash(options.queryKey);
1430
+ const isConfigEqual = current.enabled === options.enabled && current.staleTime === options.staleTime && current.cacheTime === options.cacheTime && current.refetchInterval === options.refetchInterval && current.retry === options.retry;
1431
+ if (!isKeyEqual || !isConfigEqual || current.select !== options.select) {
1432
+ this.options$.set(options);
1325
1433
  }
1326
1434
  }
1327
- updateSignal() {
1328
- if (this.unsubscribeSignal) this.unsubscribeSignal();
1329
- this.signal = this.client.getSignal(this.options.queryKey);
1330
- this.unsubscribeSignal = this.signal.subscribe(() => {
1331
- this.notify();
1435
+ subscribe(listener) {
1436
+ const unsub = this.result$.subscribe(() => {
1437
+ listener();
1332
1438
  });
1333
- }
1334
- computeResult() {
1335
- const entry = this.signal.get();
1336
- const data = entry?.data;
1337
- const status = entry?.status || "pending";
1338
- const error = entry?.error || null;
1339
- const isFetching = entry?.isFetching || false;
1340
- const dataTimestamp = entry?.timestamp;
1341
- const staleTime = this.options.staleTime ?? 0;
1342
- const isStale = entry?.isInvalidated || (dataTimestamp ? Date.now() - dataTimestamp > staleTime : true);
1343
- const isError = status === "error";
1344
- const isLoading = data === void 0;
1345
- const nextResult = {
1346
- data,
1347
- isLoading,
1348
- isError,
1349
- isFetching,
1350
- isStale,
1351
- error,
1352
- status,
1353
- refetch: this.refetch
1354
- };
1355
- if (this.currentResult && this.shallowEqual(this.currentResult, nextResult)) {
1356
- return this.currentResult;
1357
- }
1358
- this.currentResult = nextResult;
1359
- return nextResult;
1439
+ return unsub;
1360
1440
  }
1361
1441
  getSnapshot = () => {
1362
- if (!this.currentResult) {
1363
- return this.computeResult();
1364
- }
1365
- return this.currentResult;
1442
+ return this.result$.get();
1366
1443
  };
1367
- shallowEqual(objA, objB) {
1368
- if (Object.is(objA, objB)) return true;
1369
- if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) return false;
1370
- const recordA = objA;
1371
- const recordB = objB;
1372
- const keysA = Object.keys(recordA);
1373
- const keysB = Object.keys(recordB);
1374
- if (keysA.length !== keysB.length) return false;
1375
- for (const key of keysA) {
1376
- if (!Object.prototype.hasOwnProperty.call(recordB, key) || !Object.is(recordA[key], recordB[key])) {
1377
- return false;
1378
- }
1379
- }
1380
- return true;
1381
- }
1382
- notify() {
1383
- this.computeResult();
1384
- this.listeners.forEach((l) => l());
1385
- this.checkAndFetch();
1386
- }
1387
- // --- Fetch Logic ---
1388
- fetch = async (background = false) => {
1389
- if (this.options.enabled === false) return;
1390
- if (this.abortController) this.abortController.abort();
1391
- this.abortController = new AbortController();
1392
- const signal2 = this.abortController.signal;
1393
- try {
1394
- let result = await this.client.fetch(
1395
- this.options.queryKey,
1396
- (ctx) => this.options.queryFn(ctx),
1397
- { signal: signal2, retry: this.options.retry, retryDelay: this.options.retryDelay }
1398
- );
1399
- try {
1400
- result = validateWithSchema(result, this.options.schema);
1401
- } catch (validationErr) {
1402
- const current = this.signal.get();
1403
- this.signal.set({
1404
- ...current,
1405
- status: "error",
1406
- error: validationErr,
1407
- isFetching: false,
1408
- data: void 0
1409
- });
1410
- return;
1444
+ initSideEffects() {
1445
+ const disposeEffect = effect(() => {
1446
+ const opts = this.options$.get();
1447
+ const res = this.result$.get();
1448
+ if (opts.enabled !== false) {
1449
+ if (res.isLoading && !res.isFetching && !res.isError) {
1450
+ untracked(() => this.fetch());
1451
+ } else if (res.isStale && !res.isFetching && !res.isError) {
1452
+ untracked(() => this.fetch());
1453
+ }
1411
1454
  }
1412
- this.client.set(this.options.queryKey, result, {
1413
- staleTime: this.options.staleTime,
1414
- cacheTime: this.options.cacheTime,
1415
- tags: this.options.tags
1455
+ });
1456
+ const disposeGC = effect(() => {
1457
+ const opts = this.options$.get();
1458
+ const signal2 = this.client.getSignal(opts.queryKey);
1459
+ const unsub = signal2.subscribe(() => {
1416
1460
  });
1417
- } catch (err) {
1418
- if (err instanceof Error && err.name === "AbortError") return;
1419
- if (err instanceof Error && err.name !== "AbortError") {
1461
+ return () => unsub();
1462
+ });
1463
+ const disposeFocus = focusManager.subscribe(() => {
1464
+ const opts = this.options$.get();
1465
+ if (opts.enabled !== false && opts.refetchOnWindowFocus !== false) {
1466
+ this.fetch();
1420
1467
  }
1421
- }
1422
- };
1423
- checkAndFetch() {
1424
- if (this.options.enabled === false) return;
1425
- const snapshot = this.getSnapshot();
1426
- if (snapshot.isLoading && !snapshot.isFetching && !snapshot.isError) {
1427
- this.fetch();
1428
- } else if (snapshot.isStale && !snapshot.isFetching && !snapshot.isError) {
1429
- this.fetch();
1430
- }
1468
+ });
1469
+ const disposeOnline = onlineManager.subscribe((isOnline) => {
1470
+ const opts = this.options$.get();
1471
+ if (isOnline && opts.enabled !== false && opts.refetchOnReconnect !== false) {
1472
+ this.fetch();
1473
+ }
1474
+ });
1475
+ this.unsubscribe = () => {
1476
+ disposeEffect();
1477
+ disposeGC();
1478
+ disposeFocus();
1479
+ disposeOnline();
1480
+ };
1431
1481
  }
1432
1482
  refetch = async () => {
1433
- this.client.invalidate(this.options.queryKey);
1483
+ const opts = this.options$.get();
1484
+ this.client.invalidate(opts.queryKey);
1434
1485
  await this.fetch();
1435
1486
  };
1436
- // --- Background Refetching ---
1437
- setupInterval() {
1438
- this.cleanupInterval();
1439
- if (this.options.enabled !== false && this.options.refetchInterval) {
1440
- this.intervalParams.id = setInterval(() => {
1441
- this.fetch(true);
1442
- }, this.options.refetchInterval);
1443
- }
1444
- }
1445
- cleanupInterval() {
1446
- if (this.intervalParams.id) {
1447
- clearInterval(this.intervalParams.id);
1448
- this.intervalParams.id = null;
1449
- }
1450
- }
1451
- onFocus = () => {
1452
- if (this.options.refetchOnWindowFocus) {
1453
- const snapshot = this.getSnapshot();
1454
- if (snapshot.isStale && !snapshot.isFetching) {
1455
- this.fetch(true);
1456
- }
1487
+ fetch = async (background = false) => {
1488
+ const opts = this.options$.get();
1489
+ if (opts.enabled === false) return;
1490
+ if (this.abortController) {
1491
+ this.abortController.abort();
1457
1492
  }
1458
- };
1459
- onOnline = () => {
1460
- if (this.options.refetchOnReconnect) {
1461
- const snapshot = this.getSnapshot();
1462
- if (snapshot.isStale && !snapshot.isFetching) {
1463
- this.fetch(true);
1464
- }
1493
+ this.abortController = new AbortController();
1494
+ const signal2 = this.abortController.signal;
1495
+ try {
1496
+ await this.client.fetch(
1497
+ opts.queryKey,
1498
+ async (ctx) => {
1499
+ const data = await opts.queryFn(ctx);
1500
+ if (opts.schema) {
1501
+ return validateWithSchema(data, opts.schema);
1502
+ }
1503
+ return data;
1504
+ },
1505
+ { signal: signal2, retry: opts.retry, retryDelay: opts.retryDelay, tags: opts.tags }
1506
+ );
1507
+ } catch (e) {
1465
1508
  }
1466
1509
  };
1467
- setupGlobalListeners() {
1468
- if (typeof window !== "undefined") {
1469
- window.addEventListener("focus", this.onFocus);
1470
- window.addEventListener("online", this.onOnline);
1471
- }
1472
- }
1473
- cleanupGlobalListeners() {
1474
- if (typeof window !== "undefined") {
1475
- window.removeEventListener("focus", this.onFocus);
1476
- window.removeEventListener("online", this.onOnline);
1477
- }
1510
+ destroy() {
1511
+ if (this.unsubscribe) this.unsubscribe();
1512
+ if (this.abortController) this.abortController.abort();
1478
1513
  }
1479
1514
  };
1480
1515
 
1481
- // src/addon/query/useQuery.ts
1516
+ // src/query/useQuery.ts
1482
1517
  function useQuery(options) {
1483
1518
  const client = useQueryClient();
1484
1519
  const [observer] = (0, import_react4.useState)(() => new QueryObserver(client, options));
1485
1520
  (0, import_react4.useEffect)(() => {
1486
1521
  observer.setOptions(options);
1487
1522
  }, [observer, options]);
1488
- const subscribe2 = (0, import_react4.useCallback)((onStoreChange) => {
1523
+ (0, import_react4.useEffect)(() => {
1524
+ return () => {
1525
+ observer.destroy();
1526
+ };
1527
+ }, [observer]);
1528
+ const subscribe = (0, import_react4.useCallback)((onStoreChange) => {
1489
1529
  return observer.subscribe(onStoreChange);
1490
1530
  }, [observer]);
1491
- const select = options?.select;
1492
- const selectRef = (0, import_react4.useRef)(select);
1493
- selectRef.current = select;
1494
- const memoRef = (0, import_react4.useRef)({ entry: void 0, selected: void 0 });
1495
- const getSnapshotWithSelector = (0, import_react4.useCallback)(() => {
1496
- const entry = observer.getSnapshot();
1497
- if (entry === memoRef.current.entry) {
1498
- return memoRef.current.selected;
1499
- }
1500
- let processedResult;
1501
- if (!entry) {
1502
- processedResult = void 0;
1503
- } else {
1504
- if (selectRef.current && entry.data !== void 0) {
1505
- processedResult = { ...entry, data: selectRef.current(entry.data) };
1506
- } else {
1507
- processedResult = entry;
1508
- }
1509
- }
1510
- memoRef.current = { entry, selected: processedResult };
1511
- return processedResult;
1531
+ const getSnapshot = (0, import_react4.useCallback)(() => {
1532
+ return observer.getSnapshot();
1512
1533
  }, [observer]);
1513
- const result = (0, import_react4.useSyncExternalStore)(subscribe2, getSnapshotWithSelector);
1514
- const status = result?.status || "pending";
1515
- const computedResult = {
1516
- ...result,
1517
- isPending: status === "pending",
1518
- isSuccess: status === "success",
1519
- isError: status === "error"
1520
- };
1521
- const typedResult = computedResult;
1522
- const signal2 = client.getSignal(options.queryKey);
1534
+ const result = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot);
1523
1535
  return {
1524
- ...typedResult,
1525
- signal: signal2
1526
- // Keep signal as T (source)
1536
+ ...result,
1537
+ signal: observer.result$
1527
1538
  };
1528
1539
  }
1529
1540
 
1530
- // src/addon/query/useMutation.ts
1541
+ // src/query/useMutation.ts
1531
1542
  var import_react5 = require("react");
1532
1543
 
1533
- // src/addon/query/mutationObserver.ts
1544
+ // src/query/mutationObserver.ts
1534
1545
  var generateId = () => {
1535
1546
  if (typeof crypto !== "undefined" && crypto.randomUUID) {
1536
1547
  return crypto.randomUUID();
@@ -1618,8 +1629,7 @@ var MutationObserver = class {
1618
1629
  return result;
1619
1630
  } catch (error) {
1620
1631
  if (optimistic && optimisticSnapshot !== void 0) {
1621
- const queryCache = this.client;
1622
- queryCache.set(optimistic.queryKey, optimisticSnapshot);
1632
+ this.client.set(optimistic.queryKey, optimisticSnapshot);
1623
1633
  }
1624
1634
  notify({ status: "error", error });
1625
1635
  if (onError) onError(error, variables, context);
@@ -1633,13 +1643,14 @@ var MutationObserver = class {
1633
1643
  data: void 0,
1634
1644
  error: null,
1635
1645
  variables: void 0,
1646
+ context: void 0,
1636
1647
  submittedAt: 0
1637
1648
  });
1638
1649
  this.currentMutationId = null;
1639
1650
  };
1640
1651
  };
1641
1652
 
1642
- // src/addon/query/useMutation.ts
1653
+ // src/query/useMutation.ts
1643
1654
  function useMutation(options) {
1644
1655
  const client = useQueryClient();
1645
1656
  const [observer] = (0, import_react5.useState)(() => new MutationObserver(client, options));
@@ -1671,10 +1682,10 @@ function useMutation(options) {
1671
1682
  };
1672
1683
  }
1673
1684
 
1674
- // src/addon/query/infiniteQuery.ts
1685
+ // src/query/infiniteQuery.ts
1675
1686
  var import_react6 = require("react");
1676
1687
 
1677
- // src/addon/query/plugins/logger.ts
1688
+ // src/query/plugins/logger.ts
1678
1689
  var consoleLogger = {
1679
1690
  log: console.log,
1680
1691
  warn: console.warn,
@@ -1683,133 +1694,166 @@ var consoleLogger = {
1683
1694
  var currentLogger = consoleLogger;
1684
1695
  var getLogger = () => currentLogger;
1685
1696
 
1686
- // src/addon/query/infiniteQuery.ts
1687
- function useInfiniteQuery({
1688
- queryKey,
1689
- queryFn,
1690
- getNextPageParam,
1691
- getPreviousPageParam,
1692
- initialPageParam,
1693
- staleTime = 0,
1694
- cacheTime = 5 * 60 * 1e3,
1695
- enabled = true,
1696
- retry
1697
- }) {
1698
- const client = useQueryClient();
1699
- const queryKeyHash = stableHash(queryKey);
1700
- const infiniteQueryKey = (0, import_react6.useMemo)(() => [...queryKey, "__infinite__"], [queryKeyHash]);
1701
- const subscribe2 = (0, import_react6.useCallback)((onStoreChange) => {
1702
- const signal2 = client.getSignal(infiniteQueryKey);
1703
- return signal2.subscribe(() => onStoreChange());
1704
- }, [client, infiniteQueryKey]);
1705
- const getSnapshot = (0, import_react6.useCallback)(() => {
1706
- const signal2 = client.getSignal(infiniteQueryKey);
1707
- return signal2.get();
1708
- }, [client, queryKeyHash]);
1709
- const cacheEntry = (0, import_react6.useSyncExternalStore)(subscribe2, getSnapshot);
1710
- const data = cacheEntry?.data;
1711
- const isFetching = cacheEntry?.isFetching || false;
1712
- const fetchDirection = cacheEntry?.fetchDirection || "idle";
1713
- const status = cacheEntry?.status || "pending";
1714
- const error = cacheEntry?.error || null;
1715
- const timestamp = cacheEntry?.timestamp || 0;
1716
- const isInvalidated = cacheEntry?.isInvalidated || false;
1717
- let hasNextPage = false;
1718
- let hasPreviousPage = false;
1719
- if (data && data.pages.length > 0) {
1720
- if (getNextPageParam) {
1721
- const lastPage = data.pages[data.pages.length - 1];
1722
- hasNextPage = getNextPageParam(lastPage, data.pages) !== void 0;
1723
- }
1724
- if (getPreviousPageParam) {
1725
- const firstPage = data.pages[0];
1726
- hasPreviousPage = getPreviousPageParam(firstPage, data.pages) !== void 0;
1727
- }
1697
+ // src/query/infiniteQueryObserver.ts
1698
+ var InfiniteQueryObserver = class {
1699
+ client;
1700
+ options$;
1701
+ result$;
1702
+ unsubscribe = null;
1703
+ lastFetchTime = 0;
1704
+ constructor(client, options) {
1705
+ this.client = client;
1706
+ this.options$ = createSignal(options);
1707
+ const infiniteQueryKey = computed(() => {
1708
+ const opts = this.options$.get();
1709
+ return [...opts.queryKey, "__infinite__"];
1710
+ });
1711
+ let lastResult = null;
1712
+ this.result$ = computed(() => {
1713
+ const opts = this.options$.get();
1714
+ const key = infiniteQueryKey.get();
1715
+ const cacheSignal = this.client.getSignal(key);
1716
+ const entry = cacheSignal.get();
1717
+ const data = entry?.data;
1718
+ const isFetching = entry?.isFetching || false;
1719
+ const fetchDirection = entry?.fetchDirection || "idle";
1720
+ const status = entry?.status || "pending";
1721
+ const error = entry?.error || null;
1722
+ let hasNextPage = false;
1723
+ let hasPreviousPage = false;
1724
+ if (data && data.pages.length > 0) {
1725
+ if (opts.getNextPageParam) {
1726
+ const lastPage = data.pages[data.pages.length - 1];
1727
+ hasNextPage = opts.getNextPageParam(lastPage, data.pages) !== void 0;
1728
+ }
1729
+ if (opts.getPreviousPageParam) {
1730
+ const firstPage = data.pages[0];
1731
+ hasPreviousPage = opts.getPreviousPageParam(firstPage, data.pages) !== void 0;
1732
+ }
1733
+ }
1734
+ const isFetchingNextPage = isFetching && fetchDirection === "next";
1735
+ const isFetchingPreviousPage = isFetching && fetchDirection === "previous";
1736
+ const isLoading = data === void 0 && isFetching;
1737
+ const nextResult = {
1738
+ data,
1739
+ isFetching,
1740
+ isFetchingNextPage,
1741
+ isFetchingPreviousPage,
1742
+ isLoading,
1743
+ isError: status === "error",
1744
+ hasNextPage,
1745
+ hasPreviousPage,
1746
+ error,
1747
+ status,
1748
+ fetchNextPage: this.fetchNextPage,
1749
+ fetchPreviousPage: this.fetchPreviousPage,
1750
+ refetch: this.refetch
1751
+ };
1752
+ const isDataEqual = lastResult?.data === nextResult.data || isDeepEqual(lastResult?.data, nextResult.data);
1753
+ if (lastResult && isDataEqual && lastResult.isFetching === nextResult.isFetching && lastResult.status === nextResult.status && lastResult.hasNextPage === nextResult.hasNextPage && lastResult.hasPreviousPage === nextResult.hasPreviousPage) {
1754
+ return lastResult;
1755
+ }
1756
+ lastResult = nextResult;
1757
+ return nextResult;
1758
+ });
1759
+ this.initSideEffects();
1728
1760
  }
1729
- const isFetchingNextPage = isFetching && fetchDirection === "next";
1730
- const isFetchingPreviousPage = isFetching && fetchDirection === "previous";
1731
- const isLoading = data === void 0 && isFetching;
1732
- const isError = status === "error";
1733
- const queryFnRef = (0, import_react6.useRef)(queryFn);
1734
- const getNextPageParamRef = (0, import_react6.useRef)(getNextPageParam);
1735
- const getPreviousPageParamRef = (0, import_react6.useRef)(getPreviousPageParam);
1736
- const initialPageParamRef = (0, import_react6.useRef)(initialPageParam);
1737
- const staleTimeRef = (0, import_react6.useRef)(staleTime);
1738
- const cacheTimeRef = (0, import_react6.useRef)(cacheTime);
1739
- (0, import_react6.useEffect)(() => {
1740
- queryFnRef.current = queryFn;
1741
- getNextPageParamRef.current = getNextPageParam;
1742
- getPreviousPageParamRef.current = getPreviousPageParam;
1743
- initialPageParamRef.current = initialPageParam;
1744
- staleTimeRef.current = staleTime;
1745
- cacheTimeRef.current = cacheTime;
1746
- });
1747
- (0, import_react6.useEffect)(() => {
1748
- if (!enabled) return;
1749
- if (data && !isInvalidated && Date.now() - timestamp <= staleTime) return;
1750
- if (isFetching) return;
1751
- const doInitialFetch = async () => {
1752
- try {
1753
- if (data && data.pageParams.length > 0) {
1754
- const updatedPages = [];
1755
- const updatedParams = [];
1756
- let param = data.pageParams[0];
1757
- updatedParams.push(param);
1758
- const limit = data.pages.length;
1759
- const fetchedData = await client.fetch(infiniteQueryKey, async () => {
1760
- for (let i = 0; i < limit; i++) {
1761
- const page = await queryFnRef.current({ pageParam: param });
1762
- updatedPages.push(page);
1763
- if (i < limit - 1) {
1764
- const next = getNextPageParamRef.current?.(page, updatedPages);
1765
- if (next === void 0) break;
1766
- param = next;
1767
- updatedParams.push(param);
1768
- }
1769
- }
1770
- return {
1771
- pages: updatedPages,
1772
- pageParams: updatedParams
1773
- };
1774
- }, { fetchDirection: "initial", retry });
1775
- client.set(infiniteQueryKey, fetchedData, {
1776
- staleTime: staleTimeRef.current,
1777
- cacheTime: cacheTimeRef.current
1778
- });
1779
- return;
1761
+ setOptions(options) {
1762
+ const current = this.options$.get();
1763
+ if (current === options) return;
1764
+ const isKeyEqual = stableHash(current.queryKey) === stableHash(options.queryKey);
1765
+ const isConfigEqual = current.enabled === options.enabled && current.staleTime === options.staleTime;
1766
+ if (!isKeyEqual || !isConfigEqual || current.getNextPageParam !== options.getNextPageParam || current.getPreviousPageParam !== options.getPreviousPageParam) {
1767
+ this.options$.set(options);
1768
+ }
1769
+ }
1770
+ initSideEffects() {
1771
+ const dispose = effect(() => {
1772
+ const opts = this.options$.get();
1773
+ const res = this.result$.get();
1774
+ if (opts.enabled !== false) {
1775
+ const infiniteKey = [...opts.queryKey, "__infinite__"];
1776
+ const entry = this.client.getSignal(infiniteKey).get();
1777
+ const staleTime = opts.staleTime ?? 0;
1778
+ const now = Date.now();
1779
+ const timestamp = entry?.timestamp || 0;
1780
+ const isStale = entry?.isInvalidated || entry?.data && now - timestamp > staleTime;
1781
+ if ((!entry?.data || isStale) && !res.isFetching && !res.isError) {
1782
+ untracked(() => this.fetchInitial());
1780
1783
  }
1781
- const initialParam = initialPageParamRef.current;
1782
- const firstParam = initialParam !== void 0 ? initialParam : 0;
1783
- const initialData = await client.fetch(infiniteQueryKey, async () => {
1784
- const firstPage = await queryFnRef.current({ pageParam: firstParam });
1785
- return {
1786
- pages: [firstPage],
1787
- pageParams: [firstParam]
1788
- };
1789
- }, { fetchDirection: "initial", retry });
1790
- client.set(infiniteQueryKey, initialData, {
1791
- staleTime: staleTimeRef.current,
1792
- cacheTime: cacheTimeRef.current
1793
- });
1794
- } catch (err) {
1795
- getLogger().error("Initial fetch failed", err);
1796
1784
  }
1785
+ });
1786
+ const disposeFocus = focusManager.subscribe(() => {
1787
+ const opts = this.options$.get();
1788
+ if (opts.enabled !== false && opts.refetchOnWindowFocus !== false) {
1789
+ this.fetchInitial();
1790
+ }
1791
+ });
1792
+ const disposeOnline = onlineManager.subscribe((isOnline) => {
1793
+ const opts = this.options$.get();
1794
+ if (isOnline && opts.enabled !== false && opts.refetchOnReconnect !== false) {
1795
+ this.fetchInitial();
1796
+ }
1797
+ });
1798
+ this.unsubscribe = () => {
1799
+ dispose();
1800
+ disposeFocus();
1801
+ disposeOnline();
1797
1802
  };
1798
- doInitialFetch();
1799
- }, [enabled, data === void 0, isInvalidated, staleTime, timestamp]);
1800
- const fetchNextPage = (0, import_react6.useCallback)(async () => {
1801
- if (!hasNextPage || isFetching || !data) return;
1802
- const lastPage = data.pages[data.pages.length - 1];
1803
- const nextPageParam = getNextPageParamRef.current?.(lastPage, data.pages);
1803
+ }
1804
+ fetchInitial = async (options) => {
1805
+ const opts = this.options$.get();
1806
+ const infiniteKey = [...opts.queryKey, "__infinite__"];
1807
+ try {
1808
+ const entrySignal = this.client.getSignal(infiniteKey);
1809
+ const data = entrySignal.get()?.data;
1810
+ if (data && data.pageParams.length > 0 && !options?.force) {
1811
+ const firstParam2 = data.pageParams[0];
1812
+ const firstPage = await opts.queryFn({ pageParam: firstParam2 });
1813
+ const latest = entrySignal.get()?.data;
1814
+ if (!latest) return;
1815
+ const updatedData = {
1816
+ ...latest,
1817
+ pages: [firstPage, ...latest.pages.slice(1)]
1818
+ };
1819
+ this.client.set(infiniteKey, updatedData, {
1820
+ staleTime: opts.staleTime,
1821
+ cacheTime: opts.cacheTime
1822
+ });
1823
+ return;
1824
+ }
1825
+ const initialParam = opts.initialPageParam;
1826
+ const firstParam = initialParam !== void 0 ? initialParam : 0;
1827
+ const initialData = await this.client.fetch(infiniteKey, async () => {
1828
+ const firstPage = await opts.queryFn({ pageParam: firstParam });
1829
+ return {
1830
+ pages: [firstPage],
1831
+ pageParams: [firstParam]
1832
+ };
1833
+ }, { fetchDirection: "initial", retry: opts.retry });
1834
+ this.client.set(infiniteKey, initialData, {
1835
+ staleTime: opts.staleTime,
1836
+ cacheTime: opts.cacheTime
1837
+ });
1838
+ } catch (err) {
1839
+ getLogger().error("Initial fetch failed", err);
1840
+ }
1841
+ };
1842
+ fetchNextPage = async () => {
1843
+ const res = this.result$.get();
1844
+ const opts = this.options$.get();
1845
+ if (!res.hasNextPage || res.isFetching || !res.data) return;
1846
+ const infiniteKey = [...opts.queryKey, "__infinite__"];
1847
+ const lastPage = res.data.pages[res.data.pages.length - 1];
1848
+ const nextPageParam = opts.getNextPageParam?.(lastPage, res.data.pages);
1804
1849
  if (nextPageParam === void 0) return;
1805
1850
  try {
1806
- const updatedData = await client.fetch(infiniteQueryKey, async ({ signal: signal2 }) => {
1807
- const newPage = await queryFnRef.current({ pageParam: nextPageParam });
1808
- const currentEntry = client.getSignal(infiniteQueryKey).get();
1809
- const currentData = currentEntry?.data;
1810
- if (!currentData) throw new Error("Infinite query data missing during fetchNextPage");
1811
- const nextCursor = getNextPageParamRef.current?.(newPage, [...currentData.pages, newPage]);
1851
+ const updatedData = await this.client.fetch(infiniteKey, async () => {
1852
+ const newPage = await opts.queryFn({ pageParam: nextPageParam });
1853
+ const currentData = this.client.getSignal(infiniteKey).get()?.data;
1854
+ if (!currentData) throw new Error("Infinite query data missing");
1812
1855
  const updatedParams = [...currentData.pageParams, nextPageParam];
1856
+ const nextCursor = opts.getNextPageParam?.(newPage, [...currentData.pages, newPage]);
1813
1857
  if (nextCursor !== void 0) {
1814
1858
  updatedParams.push(nextCursor);
1815
1859
  }
@@ -1817,77 +1861,86 @@ function useInfiniteQuery({
1817
1861
  pages: [...currentData.pages, newPage],
1818
1862
  pageParams: updatedParams
1819
1863
  };
1820
- }, {
1821
- fetchDirection: "next",
1822
- retry
1823
- });
1824
- client.set(infiniteQueryKey, updatedData, {
1825
- staleTime: staleTimeRef.current,
1826
- cacheTime: cacheTimeRef.current
1864
+ }, { fetchDirection: "next", retry: opts.retry });
1865
+ this.client.set(infiniteKey, updatedData, {
1866
+ staleTime: opts.staleTime,
1867
+ cacheTime: opts.cacheTime
1827
1868
  });
1828
1869
  } catch (err) {
1829
1870
  getLogger().error("Fetch next page failed", err);
1830
1871
  }
1831
- }, [hasNextPage, isFetching, data, client, JSON.stringify(infiniteQueryKey)]);
1832
- const fetchPreviousPage = (0, import_react6.useCallback)(async () => {
1833
- if (!hasPreviousPage || isFetching || !data) return;
1834
- const firstPage = data.pages[0];
1835
- const previousPageParam = getPreviousPageParamRef.current?.(firstPage, data.pages);
1872
+ };
1873
+ fetchPreviousPage = async () => {
1874
+ const res = this.result$.get();
1875
+ const opts = this.options$.get();
1876
+ if (!res.hasPreviousPage || res.isFetching || !res.data) return;
1877
+ const infiniteKey = [...opts.queryKey, "__infinite__"];
1878
+ const firstPage = res.data.pages[0];
1879
+ const previousPageParam = opts.getPreviousPageParam?.(firstPage, res.data.pages);
1836
1880
  if (previousPageParam === void 0) return;
1837
1881
  try {
1838
- const updatedData = await client.fetch(infiniteQueryKey, async () => {
1839
- const newPage = await queryFnRef.current({ pageParam: previousPageParam });
1840
- const currentEntry = client.getSignal(infiniteQueryKey).get();
1841
- const currentData = currentEntry?.data;
1842
- if (!currentData) throw new Error("Infinite query data missing during fetchPreviousPage");
1882
+ const updatedData = await this.client.fetch(infiniteKey, async () => {
1883
+ const newPage = await opts.queryFn({ pageParam: previousPageParam });
1884
+ const currentData = this.client.getSignal(infiniteKey).get()?.data;
1885
+ if (!currentData) throw new Error("Infinite query data missing");
1843
1886
  return {
1844
1887
  pages: [newPage, ...currentData.pages],
1845
1888
  pageParams: [previousPageParam, ...currentData.pageParams]
1846
1889
  };
1847
- }, { fetchDirection: "previous", retry });
1848
- client.set(infiniteQueryKey, updatedData, {
1849
- staleTime: staleTimeRef.current,
1850
- cacheTime: cacheTimeRef.current
1890
+ }, { fetchDirection: "previous", retry: opts.retry });
1891
+ this.client.set(infiniteKey, updatedData, {
1892
+ staleTime: opts.staleTime,
1893
+ cacheTime: opts.cacheTime
1851
1894
  });
1852
1895
  } catch (err) {
1853
1896
  getLogger().error("Fetch previous page failed", err);
1854
1897
  }
1855
- }, [hasPreviousPage, isFetching, data, client, JSON.stringify(infiniteQueryKey)]);
1856
- const refetch = (0, import_react6.useCallback)(async () => {
1857
- client.invalidate(infiniteQueryKey);
1858
- }, [client, JSON.stringify(infiniteQueryKey)]);
1859
- return {
1860
- data,
1861
- fetchNextPage,
1862
- fetchPreviousPage,
1863
- hasNextPage,
1864
- hasPreviousPage,
1865
- isFetching,
1866
- isFetchingNextPage,
1867
- isFetchingPreviousPage,
1868
- isLoading,
1869
- isError,
1870
- error,
1871
- refetch
1872
1898
  };
1899
+ refetch = async () => {
1900
+ const opts = this.options$.get();
1901
+ const infiniteKey = [...opts.queryKey, "__infinite__"];
1902
+ this.client.invalidate(infiniteKey);
1903
+ await this.fetchInitial({ force: true });
1904
+ };
1905
+ destroy() {
1906
+ if (this.unsubscribe) this.unsubscribe();
1907
+ }
1908
+ };
1909
+
1910
+ // src/query/infiniteQuery.ts
1911
+ function useInfiniteQuery(options) {
1912
+ const client = useQueryClient();
1913
+ const [observer] = (0, import_react6.useState)(() => new InfiniteQueryObserver(client, options));
1914
+ (0, import_react6.useEffect)(() => {
1915
+ observer.setOptions(options);
1916
+ }, [observer, options]);
1917
+ (0, import_react6.useEffect)(() => {
1918
+ return () => {
1919
+ observer.destroy();
1920
+ };
1921
+ }, [observer]);
1922
+ const subscribe = (0, import_react6.useCallback)((onStoreChange) => {
1923
+ return observer.result$.subscribe(() => onStoreChange());
1924
+ }, [observer]);
1925
+ const getSnapshot = (0, import_react6.useCallback)(() => {
1926
+ return observer.result$.get();
1927
+ }, [observer]);
1928
+ return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot);
1873
1929
  }
1874
1930
 
1875
- // src/addon/query/HydrationBoundary.tsx
1931
+ // src/query/HydrationBoundary.tsx
1876
1932
  var import_react7 = require("react");
1877
1933
 
1878
- // src/addon/query/hydration.ts
1934
+ // src/query/hydration.ts
1879
1935
  function dehydrate(client) {
1880
1936
  const queries = [];
1881
1937
  const snapshot = client.getSnapshot();
1882
- snapshot.forEach((signal2, hash) => {
1883
- const state = signal2.get();
1884
- if (state) {
1885
- queries.push({
1886
- queryKey: state.key,
1887
- queryHash: hash,
1888
- state
1889
- });
1890
- }
1938
+ snapshot.forEach((state, hash) => {
1939
+ queries.push({
1940
+ queryKey: state.key,
1941
+ queryHash: hash,
1942
+ state
1943
+ });
1891
1944
  });
1892
1945
  return { queries };
1893
1946
  }
@@ -1899,8 +1952,8 @@ function hydrate(client, state) {
1899
1952
  });
1900
1953
  }
1901
1954
 
1902
- // src/addon/query/HydrationBoundary.tsx
1903
- var import_jsx_runtime2 = require("react/jsx-runtime");
1955
+ // src/query/HydrationBoundary.tsx
1956
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1904
1957
  function HydrationBoundary({ state, children }) {
1905
1958
  const client = useQueryClient();
1906
1959
  const hydratedRef = (0, import_react7.useRef)(false);
@@ -1908,10 +1961,10 @@ function HydrationBoundary({ state, children }) {
1908
1961
  hydrate(client, state);
1909
1962
  hydratedRef.current = true;
1910
1963
  }
1911
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
1964
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
1912
1965
  }
1913
1966
 
1914
- // src/addon/query/useSuspenseQuery.ts
1967
+ // src/query/useSuspenseQuery.ts
1915
1968
  function useSuspenseQuery(options) {
1916
1969
  const client = useQueryClient();
1917
1970
  const signal2 = client.getSignal(options.queryKey);
@@ -1920,8 +1973,7 @@ function useSuspenseQuery(options) {
1920
1973
  if (shouldSuspend) {
1921
1974
  const fetchPromise = client.fetch(
1922
1975
  options.queryKey,
1923
- // @ts-ignore
1924
- (ctx) => options.queryFn(ctx),
1976
+ (ctx) => options.queryFn({ ...ctx, signal: void 0 }),
1925
1977
  { signal: void 0 }
1926
1978
  ).then((data) => {
1927
1979
  client.set(options.queryKey, data);
@@ -1939,73 +1991,60 @@ function useSuspenseQuery(options) {
1939
1991
  };
1940
1992
  }
1941
1993
 
1942
- // src/core/bridge.ts
1943
- function fromSignal(signal2) {
1944
- const initial = signal2.get();
1945
- const isObject = typeof initial === "object" && initial !== null;
1946
- const target = isObject ? initial : { value: initial };
1947
- const proxy = createState(target);
1948
- signal2.subscribe((newValue) => {
1949
- if (typeof newValue === "object" && newValue !== null) {
1950
- Object.assign(proxy, newValue);
1951
- } else {
1952
- proxy.value = newValue;
1953
- }
1954
- });
1955
- return proxy;
1994
+ // src/query/useQueryStore.ts
1995
+ var import_react8 = require("react");
1996
+ function useQueryStore() {
1997
+ const client = useQueryClient();
1998
+ const [cache, setCache] = (0, import_react8.useState)(client.getAll());
1999
+ (0, import_react8.useEffect)(() => {
2000
+ const interval = setInterval(() => {
2001
+ setCache(new Map(client.getAll()));
2002
+ }, 500);
2003
+ return () => clearInterval(interval);
2004
+ }, [client]);
2005
+ return cache;
1956
2006
  }
1957
- function toSignal(selector) {
1958
- const s = createSignal(void 0);
1959
- let isComputing = false;
1960
- const onDependencyChange = () => {
1961
- if (isComputing) return;
1962
- run();
1963
- };
1964
- const run = () => {
1965
- isComputing = true;
1966
- setActiveListener(onDependencyChange);
1967
- try {
1968
- const value = selector();
1969
- s.set(value);
1970
- } finally {
1971
- setActiveListener(null);
1972
- isComputing = false;
1973
- }
1974
- };
1975
- run();
1976
- return {
1977
- get: s.get,
1978
- set: () => {
1979
- throw new Error("Cannot set a read-only bridge signal");
1980
- },
1981
- subscribe: s.subscribe
1982
- };
2007
+
2008
+ // src/query/useQuerySignal.ts
2009
+ var import_react9 = require("react");
2010
+ function useQuery$(options) {
2011
+ const client = useQueryClient();
2012
+ const [observer] = (0, import_react9.useState)(() => new QueryObserver(client, options));
2013
+ (0, import_react9.useEffect)(() => {
2014
+ observer.setOptions(options);
2015
+ }, [observer, options.enabled, options.staleTime, options.cacheTime, options.queryKey, options.refetchInterval]);
2016
+ (0, import_react9.useEffect)(() => {
2017
+ const unsubscribe = observer.subscribe(() => {
2018
+ });
2019
+ return () => {
2020
+ unsubscribe();
2021
+ observer.destroy();
2022
+ };
2023
+ }, [observer]);
2024
+ return observer.result$;
1983
2025
  }
1984
2026
  // Annotate the CommonJS export names for ESM import in node:
1985
2027
  0 && (module.exports = {
1986
2028
  HydrationBoundary,
1987
- QueryCache,
2029
+ QueryClient,
1988
2030
  QueryClientProvider,
1989
- computed,
2031
+ SignalValue,
2032
+ atom,
1990
2033
  createHttpClient,
1991
- createState,
1992
- defineModel,
1993
2034
  dehydrate,
1994
2035
  enableDevTools,
1995
- fromSignal,
1996
2036
  getPromiseState,
1997
2037
  handlePromise,
1998
2038
  hydrate,
1999
2039
  isPromise,
2000
2040
  scheduleUpdate,
2001
- subscribe,
2002
- toSignal,
2003
2041
  unwrapPromise,
2004
2042
  useInfiniteQuery,
2005
2043
  useMutation,
2006
2044
  usePaginatedQuery,
2007
2045
  useQuery,
2046
+ useQuery$,
2008
2047
  useQueryClient,
2009
- useStore,
2048
+ useQueryStore,
2010
2049
  useSuspenseQuery
2011
2050
  });