@braine/quantum-query 1.2.5 → 1.2.6
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/README.md +95 -1
- package/dist/index.cjs +1166 -1055
- package/dist/index.d.cts +186 -129
- package/dist/index.d.ts +186 -129
- package/dist/index.js +1157 -1048
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -176,7 +176,7 @@ function defineModel(def) {
|
|
|
176
176
|
engine = storage;
|
|
177
177
|
}
|
|
178
178
|
if (engine) {
|
|
179
|
-
const
|
|
179
|
+
const hydrate2 = () => {
|
|
180
180
|
const process = (stored) => {
|
|
181
181
|
try {
|
|
182
182
|
if (stored) {
|
|
@@ -199,7 +199,7 @@ function defineModel(def) {
|
|
|
199
199
|
if (debug) console.error(`[Quantum] Storage Access Failed`, err);
|
|
200
200
|
}
|
|
201
201
|
};
|
|
202
|
-
|
|
202
|
+
hydrate2();
|
|
203
203
|
const save = debounce(async () => {
|
|
204
204
|
try {
|
|
205
205
|
let stateToSave;
|
|
@@ -262,8 +262,48 @@ function useStore(store) {
|
|
|
262
262
|
return proxy;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
// src/addon/signals.ts
|
|
266
|
+
import { signal, computed as preactComputed, effect, batch } from "@preact/signals-core";
|
|
267
|
+
function createSignal(initialValue, options) {
|
|
268
|
+
const s = signal(initialValue);
|
|
269
|
+
let unsubscribeActive;
|
|
270
|
+
let subscriberCount = 0;
|
|
271
|
+
return {
|
|
272
|
+
get: () => s.value,
|
|
273
|
+
set: (newValue) => {
|
|
274
|
+
s.value = newValue;
|
|
275
|
+
},
|
|
276
|
+
subscribe: (fn) => {
|
|
277
|
+
if (subscriberCount === 0) {
|
|
278
|
+
options?.onActive?.();
|
|
279
|
+
}
|
|
280
|
+
subscriberCount++;
|
|
281
|
+
const dispose = effect(() => {
|
|
282
|
+
fn(s.value);
|
|
283
|
+
});
|
|
284
|
+
return () => {
|
|
285
|
+
dispose();
|
|
286
|
+
subscriberCount--;
|
|
287
|
+
if (subscriberCount === 0) {
|
|
288
|
+
options?.onInactive?.();
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/devtools/registry.ts
|
|
296
|
+
var stores = createSignal([]);
|
|
297
|
+
function registerStore(store, name = "Store") {
|
|
298
|
+
const current = stores.get();
|
|
299
|
+
if (!current.find((s) => s.store === store)) {
|
|
300
|
+
stores.set([...current, { name, store }]);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
265
304
|
// src/middleware/devtools.ts
|
|
266
305
|
function enableDevTools(store, name = "Store") {
|
|
306
|
+
registerStore(store, name);
|
|
267
307
|
if (typeof window === "undefined" || !window.__REDUX_DEVTOOLS_EXTENSION__) return;
|
|
268
308
|
const devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect({ name });
|
|
269
309
|
devTools.init(store);
|
|
@@ -428,9 +468,15 @@ var FetchMiddleware = async (ctx) => {
|
|
|
428
468
|
};
|
|
429
469
|
var delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
430
470
|
var RetryMiddleware = async (ctx, next) => {
|
|
431
|
-
const
|
|
432
|
-
if (!
|
|
433
|
-
|
|
471
|
+
const retryConfigRaw = ctx.config.retry;
|
|
472
|
+
if (!retryConfigRaw) return next(ctx);
|
|
473
|
+
let config;
|
|
474
|
+
if (typeof retryConfigRaw === "number") {
|
|
475
|
+
config = { retries: retryConfigRaw };
|
|
476
|
+
} else {
|
|
477
|
+
config = retryConfigRaw;
|
|
478
|
+
}
|
|
479
|
+
const { retries = 0, baseDelay = 1e3, maxDelay = 3e3 } = config;
|
|
434
480
|
const attempt = async (count) => {
|
|
435
481
|
try {
|
|
436
482
|
const response = await next(ctx);
|
|
@@ -443,7 +489,7 @@ var RetryMiddleware = async (ctx, next) => {
|
|
|
443
489
|
return response;
|
|
444
490
|
} catch (err) {
|
|
445
491
|
if (count < retries) {
|
|
446
|
-
if (err.name === "AbortError") throw err;
|
|
492
|
+
if (err instanceof Error && err.name === "AbortError") throw err;
|
|
447
493
|
const d = Math.min(baseDelay * 2 ** count, maxDelay);
|
|
448
494
|
await delay(d);
|
|
449
495
|
return attempt(count + 1);
|
|
@@ -581,319 +627,548 @@ function stableHash(value) {
|
|
|
581
627
|
return "{" + keys.map((key) => `${key}:${stableHash(value[key])}`).join(",") + "}";
|
|
582
628
|
}
|
|
583
629
|
|
|
584
|
-
// src/addon/
|
|
585
|
-
var
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
630
|
+
// src/addon/query/queryStorage.ts
|
|
631
|
+
var QueryStorage = class {
|
|
632
|
+
// Default configuration
|
|
633
|
+
constructor(defaultStaleTime = 0, defaultCacheTime = 5 * 60 * 1e3) {
|
|
634
|
+
this.defaultStaleTime = defaultStaleTime;
|
|
635
|
+
this.defaultCacheTime = defaultCacheTime;
|
|
636
|
+
}
|
|
637
|
+
signals = /* @__PURE__ */ new Map();
|
|
638
|
+
gcTimers = /* @__PURE__ */ new Map();
|
|
639
|
+
generateKey(queryKey) {
|
|
640
|
+
const key = Array.isArray(queryKey) ? stableHash(queryKey) : stableHash([queryKey.key, queryKey.params]);
|
|
641
|
+
return key;
|
|
642
|
+
}
|
|
643
|
+
get(key, autoCreate = true) {
|
|
644
|
+
let signal2 = this.signals.get(key);
|
|
645
|
+
if (!signal2 && autoCreate) {
|
|
646
|
+
const newSignal = createSignal(void 0, {
|
|
647
|
+
onActive: () => {
|
|
648
|
+
this.cancelGC(key);
|
|
649
|
+
},
|
|
650
|
+
onInactive: () => {
|
|
651
|
+
const entry = this.signals.get(key)?.get();
|
|
652
|
+
const cacheTime = entry?.cacheTime ?? this.defaultCacheTime;
|
|
653
|
+
this.scheduleGC(key, cacheTime);
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
this.signals.set(key, newSignal);
|
|
657
|
+
signal2 = newSignal;
|
|
607
658
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
const currentValue = this.value;
|
|
611
|
-
this.subscribers.forEach((fn) => fn(currentValue));
|
|
659
|
+
if (!signal2) return void 0;
|
|
660
|
+
return signal2;
|
|
612
661
|
}
|
|
613
|
-
|
|
614
|
-
this.
|
|
615
|
-
|
|
616
|
-
|
|
662
|
+
set(key, entry) {
|
|
663
|
+
const signal2 = this.signals.get(key);
|
|
664
|
+
if (signal2) {
|
|
665
|
+
signal2.set(entry);
|
|
666
|
+
} else {
|
|
667
|
+
this.signals.set(key, createSignal(entry, {
|
|
668
|
+
onActive: () => {
|
|
669
|
+
this.cancelGC(key);
|
|
670
|
+
},
|
|
671
|
+
onInactive: () => {
|
|
672
|
+
const entry2 = this.signals.get(key)?.get();
|
|
673
|
+
const cacheTime = entry2?.cacheTime ?? this.defaultCacheTime;
|
|
674
|
+
this.scheduleGC(key, cacheTime);
|
|
675
|
+
}
|
|
676
|
+
}));
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
delete(key) {
|
|
680
|
+
this.signals.delete(key);
|
|
681
|
+
this.cancelGC(key);
|
|
682
|
+
}
|
|
683
|
+
clear() {
|
|
684
|
+
this.signals.clear();
|
|
685
|
+
this.gcTimers.forEach((timer2) => clearTimeout(timer2));
|
|
686
|
+
this.gcTimers.clear();
|
|
687
|
+
}
|
|
688
|
+
getAll() {
|
|
689
|
+
const map = /* @__PURE__ */ new Map();
|
|
690
|
+
for (const [key, signal2] of this.signals.entries()) {
|
|
691
|
+
const val = signal2.get();
|
|
692
|
+
if (val) map.set(key, val);
|
|
693
|
+
}
|
|
694
|
+
return map;
|
|
695
|
+
}
|
|
696
|
+
getStats() {
|
|
697
|
+
return {
|
|
698
|
+
size: this.signals.size,
|
|
699
|
+
keys: Array.from(this.signals.keys())
|
|
617
700
|
};
|
|
618
|
-
}
|
|
701
|
+
}
|
|
702
|
+
getSnapshot() {
|
|
703
|
+
return this.signals;
|
|
704
|
+
}
|
|
705
|
+
// --- GC Logic ---
|
|
706
|
+
scheduleGC(key, delay2) {
|
|
707
|
+
if (this.gcTimers.has(key)) {
|
|
708
|
+
clearTimeout(this.gcTimers.get(key));
|
|
709
|
+
}
|
|
710
|
+
const timer2 = setTimeout(() => {
|
|
711
|
+
this.delete(key);
|
|
712
|
+
}, delay2);
|
|
713
|
+
this.gcTimers.set(key, timer2);
|
|
714
|
+
}
|
|
715
|
+
cancelGC(key) {
|
|
716
|
+
if (this.gcTimers.has(key)) {
|
|
717
|
+
clearTimeout(this.gcTimers.get(key));
|
|
718
|
+
this.gcTimers.delete(key);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
619
721
|
};
|
|
620
|
-
function createSignal(initialValue) {
|
|
621
|
-
return new SignalImpl(initialValue);
|
|
622
|
-
}
|
|
623
722
|
|
|
624
|
-
// src/addon/query/
|
|
625
|
-
var
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
this.
|
|
723
|
+
// src/addon/query/remotes.ts
|
|
724
|
+
var QueryRemotes = class {
|
|
725
|
+
deduplicationCache = /* @__PURE__ */ new Map();
|
|
726
|
+
async fetch(key, fn, options) {
|
|
727
|
+
if (this.deduplicationCache.has(key)) {
|
|
728
|
+
return this.deduplicationCache.get(key);
|
|
729
|
+
}
|
|
730
|
+
const promise = this.executeWithRetry(fn, options);
|
|
731
|
+
this.deduplicationCache.set(key, promise);
|
|
732
|
+
try {
|
|
733
|
+
const result = await promise;
|
|
734
|
+
this.deduplicationCache.delete(key);
|
|
735
|
+
return result;
|
|
736
|
+
} catch (error) {
|
|
737
|
+
this.deduplicationCache.delete(key);
|
|
738
|
+
throw error;
|
|
636
739
|
}
|
|
637
740
|
}
|
|
741
|
+
async executeWithRetry(fn, options) {
|
|
742
|
+
const maxRetries = this.resolveRetry(options?.retry);
|
|
743
|
+
let attempt = 0;
|
|
744
|
+
while (true) {
|
|
745
|
+
attempt++;
|
|
746
|
+
try {
|
|
747
|
+
return await fn({ signal: options?.signal });
|
|
748
|
+
} catch (error) {
|
|
749
|
+
if (attempt > maxRetries || options?.signal && options.signal.aborted) {
|
|
750
|
+
throw error;
|
|
751
|
+
}
|
|
752
|
+
let delay2 = 1e3 * 2 ** (attempt - 1);
|
|
753
|
+
if (options?.retryDelay) {
|
|
754
|
+
delay2 = typeof options.retryDelay === "number" ? options.retryDelay : options.retryDelay(attempt - 1);
|
|
755
|
+
}
|
|
756
|
+
delay2 = Math.min(delay2, 3e4);
|
|
757
|
+
await this.wait(delay2, options?.signal);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
resolveRetry(retry) {
|
|
762
|
+
if (typeof retry === "number") return retry;
|
|
763
|
+
if (retry === false) return 0;
|
|
764
|
+
return 3;
|
|
765
|
+
}
|
|
766
|
+
wait(ms, signal2) {
|
|
767
|
+
return new Promise((resolve, reject) => {
|
|
768
|
+
if (signal2?.aborted) return reject(new Error("Aborted"));
|
|
769
|
+
const timer2 = setTimeout(() => {
|
|
770
|
+
cleanup();
|
|
771
|
+
resolve();
|
|
772
|
+
}, ms);
|
|
773
|
+
const onAbort = () => {
|
|
774
|
+
cleanup();
|
|
775
|
+
reject(new Error("Aborted"));
|
|
776
|
+
};
|
|
777
|
+
const cleanup = () => {
|
|
778
|
+
clearTimeout(timer2);
|
|
779
|
+
signal2?.removeEventListener("abort", onAbort);
|
|
780
|
+
};
|
|
781
|
+
signal2?.addEventListener("abort", onAbort);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
// src/addon/query/mutationCache.ts
|
|
787
|
+
var MutationCache = class {
|
|
788
|
+
// Map<ID, Signal> - Stores state for every unique mutation execution
|
|
789
|
+
mutations = /* @__PURE__ */ new Map();
|
|
790
|
+
// Map<KeyHash, Set<ID>> - Index to find mutations by key
|
|
791
|
+
mutationKeys = /* @__PURE__ */ new Map();
|
|
792
|
+
/**
|
|
793
|
+
* Get or Create a Signal for a specific mutation instance (ID)
|
|
794
|
+
*/
|
|
795
|
+
getSignal = (id) => {
|
|
796
|
+
let signal2 = this.mutations.get(id);
|
|
797
|
+
if (!signal2) {
|
|
798
|
+
const initialState = {
|
|
799
|
+
data: void 0,
|
|
800
|
+
error: null,
|
|
801
|
+
variables: void 0,
|
|
802
|
+
context: void 0,
|
|
803
|
+
status: "idle",
|
|
804
|
+
submittedAt: 0
|
|
805
|
+
};
|
|
806
|
+
signal2 = createSignal(initialState);
|
|
807
|
+
this.mutations.set(id, signal2);
|
|
808
|
+
}
|
|
809
|
+
return signal2;
|
|
810
|
+
};
|
|
811
|
+
/**
|
|
812
|
+
* Register a mutation ID with a Key (for tracking shared keys)
|
|
813
|
+
*/
|
|
814
|
+
register = (id, key) => {
|
|
815
|
+
if (!key) return;
|
|
816
|
+
const hash = stableHash(key);
|
|
817
|
+
if (!this.mutationKeys.has(hash)) {
|
|
818
|
+
this.mutationKeys.set(hash, /* @__PURE__ */ new Set());
|
|
819
|
+
}
|
|
820
|
+
this.mutationKeys.get(hash).add(id);
|
|
821
|
+
};
|
|
822
|
+
/**
|
|
823
|
+
* Unregister cleanup
|
|
824
|
+
*/
|
|
825
|
+
unregister = (id, key) => {
|
|
826
|
+
if (!key) return;
|
|
827
|
+
const hash = stableHash(key);
|
|
828
|
+
const set = this.mutationKeys.get(hash);
|
|
829
|
+
if (set) {
|
|
830
|
+
set.delete(id);
|
|
831
|
+
if (set.size === 0) {
|
|
832
|
+
this.mutationKeys.delete(hash);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
this.mutations.delete(id);
|
|
836
|
+
};
|
|
837
|
+
notify = (id, state) => {
|
|
838
|
+
const signal2 = this.getSignal(id);
|
|
839
|
+
const current = signal2.get();
|
|
840
|
+
signal2.set({ ...current, ...state });
|
|
841
|
+
};
|
|
638
842
|
/**
|
|
639
|
-
*
|
|
843
|
+
* Get number of mutations currently pending
|
|
640
844
|
*/
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
845
|
+
isMutating = (filters) => {
|
|
846
|
+
let count = 0;
|
|
847
|
+
if (filters?.mutationKey) {
|
|
848
|
+
const hash = stableHash(filters.mutationKey);
|
|
849
|
+
const ids = this.mutationKeys.get(hash);
|
|
850
|
+
if (!ids) return 0;
|
|
851
|
+
for (const id of ids) {
|
|
852
|
+
if (this.mutations.get(id)?.get().status === "pending") {
|
|
853
|
+
count++;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
} else {
|
|
857
|
+
for (const signal2 of this.mutations.values()) {
|
|
858
|
+
if (signal2.get().status === "pending") count++;
|
|
859
|
+
}
|
|
644
860
|
}
|
|
645
|
-
return
|
|
861
|
+
return count;
|
|
646
862
|
};
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
// src/addon/query/pluginManager.ts
|
|
866
|
+
var PluginManager = class {
|
|
867
|
+
plugins = [];
|
|
868
|
+
add(plugin) {
|
|
869
|
+
this.plugins.push(plugin);
|
|
870
|
+
}
|
|
871
|
+
onFetchStart(queryKey) {
|
|
872
|
+
this.plugins.forEach((p) => p.onFetchStart?.(queryKey));
|
|
873
|
+
}
|
|
874
|
+
onFetchSuccess(queryKey, data) {
|
|
875
|
+
this.plugins.forEach((p) => p.onFetchSuccess?.(queryKey, data));
|
|
876
|
+
}
|
|
877
|
+
onFetchError(queryKey, error) {
|
|
878
|
+
this.plugins.forEach((p) => p.onFetchError?.(queryKey, error));
|
|
879
|
+
}
|
|
880
|
+
onInvalidate(queryKey) {
|
|
881
|
+
this.plugins.forEach((p) => p.onInvalidate?.(queryKey));
|
|
882
|
+
}
|
|
883
|
+
onQueryUpdated(queryKey, data) {
|
|
884
|
+
this.plugins.forEach((p) => p.onQueryUpdated?.(queryKey, data));
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
// src/addon/query/queryCache.ts
|
|
889
|
+
var QueryCache = class {
|
|
890
|
+
// Components
|
|
891
|
+
storage;
|
|
892
|
+
remotes;
|
|
893
|
+
// Mutation Cache
|
|
894
|
+
mutationCache = new MutationCache();
|
|
895
|
+
// Plugins
|
|
896
|
+
pluginManager = new PluginManager();
|
|
897
|
+
// Config defaults
|
|
898
|
+
defaultStaleTime;
|
|
899
|
+
defaultCacheTime;
|
|
900
|
+
constructor(config) {
|
|
901
|
+
this.defaultStaleTime = config?.defaultStaleTime ?? 0;
|
|
902
|
+
this.defaultCacheTime = config?.defaultCacheTime ?? 5 * 60 * 1e3;
|
|
903
|
+
this.storage = new QueryStorage(this.defaultStaleTime, this.defaultCacheTime);
|
|
904
|
+
this.remotes = new QueryRemotes();
|
|
905
|
+
}
|
|
906
|
+
// --- FACADE API ---
|
|
647
907
|
/**
|
|
648
|
-
* Get data
|
|
908
|
+
* Get data from storage
|
|
649
909
|
*/
|
|
650
910
|
get = (queryKey) => {
|
|
651
|
-
const key = this.generateKey(queryKey);
|
|
652
|
-
const
|
|
653
|
-
if (!
|
|
654
|
-
const entry =
|
|
911
|
+
const key = this.storage.generateKey(queryKey);
|
|
912
|
+
const signal2 = this.storage.get(key, false);
|
|
913
|
+
if (!signal2) return void 0;
|
|
914
|
+
const entry = signal2.get();
|
|
655
915
|
if (!entry) return void 0;
|
|
656
916
|
const now = Date.now();
|
|
657
917
|
const age = now - entry.timestamp;
|
|
658
918
|
if (age > entry.cacheTime) {
|
|
659
|
-
this.
|
|
919
|
+
this.storage.delete(key);
|
|
660
920
|
return void 0;
|
|
661
921
|
}
|
|
662
922
|
return entry.data;
|
|
663
923
|
};
|
|
664
924
|
/**
|
|
665
|
-
* Get Signal for
|
|
666
|
-
* Automatically creates a signal if one doesn't exist
|
|
925
|
+
* Get Signal for reactivity (used by hooks)
|
|
667
926
|
*/
|
|
668
927
|
getSignal = (queryKey) => {
|
|
669
|
-
const key = this.generateKey(queryKey);
|
|
670
|
-
|
|
671
|
-
if (!signal) {
|
|
672
|
-
signal = createSignal(void 0);
|
|
673
|
-
this.signals.set(key, signal);
|
|
674
|
-
}
|
|
675
|
-
return signal;
|
|
676
|
-
};
|
|
677
|
-
/**
|
|
678
|
-
* Check if data is stale
|
|
679
|
-
*/
|
|
680
|
-
isStale = (queryKey) => {
|
|
681
|
-
const key = this.generateKey(queryKey);
|
|
682
|
-
const signal = this.signals.get(key);
|
|
683
|
-
if (!signal) return true;
|
|
684
|
-
const entry = signal.get();
|
|
685
|
-
if (!entry) return true;
|
|
686
|
-
const now = Date.now();
|
|
687
|
-
const age = now - entry.timestamp;
|
|
688
|
-
return age > entry.staleTime;
|
|
928
|
+
const key = this.storage.generateKey(queryKey);
|
|
929
|
+
return this.storage.get(key, true);
|
|
689
930
|
};
|
|
690
931
|
/**
|
|
691
|
-
* Set
|
|
932
|
+
* Set data manually (Optimistic updates / Prefetch)
|
|
692
933
|
*/
|
|
693
934
|
set = (queryKey, data, options) => {
|
|
694
|
-
const key = this.generateKey(queryKey);
|
|
935
|
+
const key = this.storage.generateKey(queryKey);
|
|
695
936
|
const entry = {
|
|
696
937
|
data,
|
|
938
|
+
status: "success",
|
|
939
|
+
error: null,
|
|
940
|
+
isFetching: false,
|
|
941
|
+
fetchDirection: "idle",
|
|
697
942
|
timestamp: Date.now(),
|
|
698
|
-
staleTime: options?.staleTime
|
|
699
|
-
cacheTime: options?.cacheTime
|
|
700
|
-
key:
|
|
943
|
+
staleTime: options?.staleTime ?? this.defaultStaleTime,
|
|
944
|
+
cacheTime: options?.cacheTime ?? this.defaultCacheTime,
|
|
945
|
+
key: queryKey,
|
|
946
|
+
tags: options?.tags
|
|
701
947
|
};
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
} else {
|
|
706
|
-
this.signals.set(key, createSignal(entry));
|
|
707
|
-
}
|
|
708
|
-
const normalizedKey = Array.isArray(queryKey) ? queryKey : [queryKey.key, queryKey.params];
|
|
709
|
-
this.plugins.forEach((p) => p.onQueryUpdated?.(normalizedKey, data));
|
|
948
|
+
this.storage.set(key, entry);
|
|
949
|
+
const normalizedKey = this.normalizeKey(queryKey);
|
|
950
|
+
this.pluginManager.onQueryUpdated(normalizedKey, data);
|
|
710
951
|
};
|
|
711
|
-
// --- DEDUPLICATION ---
|
|
712
|
-
deduplicationCache = /* @__PURE__ */ new Map();
|
|
713
|
-
// --- MIDDLEWARE / PLUGINS ---
|
|
714
|
-
plugins = [];
|
|
715
952
|
/**
|
|
716
|
-
*
|
|
953
|
+
* Restore cache entry (Hydration)
|
|
717
954
|
*/
|
|
718
|
-
|
|
719
|
-
this.
|
|
720
|
-
|
|
955
|
+
restore = (queryKey, entry) => {
|
|
956
|
+
const key = this.storage.generateKey(queryKey);
|
|
957
|
+
this.storage.set(key, entry);
|
|
958
|
+
const normalizedKey = this.normalizeKey(queryKey);
|
|
959
|
+
this.pluginManager.onQueryUpdated(normalizedKey, entry.data);
|
|
721
960
|
};
|
|
722
961
|
/**
|
|
723
|
-
* Fetch data
|
|
724
|
-
* If a request for the same key is already in flight, returns the existing promise.
|
|
962
|
+
* Fetch data (Orchestration)
|
|
725
963
|
*/
|
|
726
|
-
fetch = async (queryKey, fn) => {
|
|
727
|
-
const key = this.generateKey(queryKey);
|
|
728
|
-
const normalizedKey =
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
this.
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
(
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
964
|
+
fetch = async (queryKey, fn, options) => {
|
|
965
|
+
const key = this.storage.generateKey(queryKey);
|
|
966
|
+
const normalizedKey = this.normalizeKey(queryKey);
|
|
967
|
+
const direction = options?.fetchDirection || "initial";
|
|
968
|
+
const signal2 = this.storage.get(key, true);
|
|
969
|
+
const currentEntry = signal2.get();
|
|
970
|
+
this.storage.set(key, {
|
|
971
|
+
data: currentEntry?.data,
|
|
972
|
+
status: currentEntry?.status || "pending",
|
|
973
|
+
error: null,
|
|
974
|
+
isFetching: true,
|
|
975
|
+
// Mark fetching
|
|
976
|
+
fetchDirection: direction,
|
|
977
|
+
timestamp: currentEntry?.timestamp || Date.now(),
|
|
978
|
+
staleTime: currentEntry?.staleTime ?? this.defaultStaleTime,
|
|
979
|
+
cacheTime: currentEntry?.cacheTime ?? this.defaultCacheTime,
|
|
980
|
+
key: queryKey,
|
|
981
|
+
tags: currentEntry?.tags
|
|
982
|
+
});
|
|
983
|
+
this.pluginManager.onFetchStart(normalizedKey);
|
|
984
|
+
try {
|
|
985
|
+
const data = await this.remotes.fetch(key, fn, {
|
|
986
|
+
signal: options?.signal,
|
|
987
|
+
retry: options?.retry,
|
|
988
|
+
retryDelay: options?.retryDelay
|
|
989
|
+
});
|
|
990
|
+
this.pluginManager.onFetchSuccess(normalizedKey, data);
|
|
991
|
+
return data;
|
|
992
|
+
} catch (error) {
|
|
993
|
+
const current = signal2.get();
|
|
994
|
+
if (current) {
|
|
995
|
+
this.storage.set(key, {
|
|
996
|
+
...current,
|
|
997
|
+
status: "error",
|
|
998
|
+
error,
|
|
999
|
+
isFetching: false,
|
|
1000
|
+
fetchDirection: "idle"
|
|
1001
|
+
});
|
|
743
1002
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
return promise;
|
|
747
|
-
};
|
|
748
|
-
/**
|
|
749
|
-
* Invalidate all queries
|
|
750
|
-
*/
|
|
751
|
-
invalidateAll = () => {
|
|
752
|
-
for (const key of this.signals.keys()) {
|
|
753
|
-
this.signals.get(key)?.set(void 0);
|
|
1003
|
+
this.pluginManager.onFetchError(normalizedKey, error);
|
|
1004
|
+
throw error;
|
|
754
1005
|
}
|
|
755
1006
|
};
|
|
756
1007
|
/**
|
|
757
|
-
*
|
|
758
|
-
*/
|
|
759
|
-
remove = (queryKey) => {
|
|
760
|
-
const key = this.generateKey(queryKey);
|
|
761
|
-
this.signals.delete(key);
|
|
762
|
-
};
|
|
763
|
-
/**
|
|
764
|
-
* Invalidate queries matching the key prefix
|
|
765
|
-
* Marks them as undefined to trigger refetches without breaking subscriptions
|
|
1008
|
+
* Invalidate queries
|
|
766
1009
|
*/
|
|
767
1010
|
invalidate = (queryKey) => {
|
|
768
|
-
const prefix = this.generateKey(queryKey);
|
|
769
|
-
const normalizedKey =
|
|
770
|
-
this.
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
if (
|
|
774
|
-
|
|
1011
|
+
const prefix = this.storage.generateKey(queryKey);
|
|
1012
|
+
const normalizedKey = this.normalizeKey(queryKey);
|
|
1013
|
+
this.pluginManager.onInvalidate(normalizedKey);
|
|
1014
|
+
const allKeys = this.storage.getSnapshot().keys();
|
|
1015
|
+
for (const key of allKeys) {
|
|
1016
|
+
if (key === prefix || key.startsWith(prefix.slice(0, -1))) {
|
|
1017
|
+
const signal2 = this.storage.get(key, false);
|
|
1018
|
+
if (signal2) {
|
|
1019
|
+
const current = signal2.get();
|
|
1020
|
+
if (current) {
|
|
1021
|
+
signal2.set({ ...current, isInvalidated: true });
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
775
1024
|
}
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
invalidateTags = (tags) => {
|
|
1028
|
+
const tagsToInvalidate = new Set(tags);
|
|
1029
|
+
const snapshot = this.storage.getSnapshot();
|
|
1030
|
+
for (const [key, signal2] of snapshot.entries()) {
|
|
1031
|
+
const entry = signal2.get();
|
|
1032
|
+
if (entry && entry.tags) {
|
|
1033
|
+
if (entry.tags.some((tag) => tagsToInvalidate.has(tag))) {
|
|
1034
|
+
signal2.set({ ...entry, isInvalidated: true });
|
|
1035
|
+
}
|
|
781
1036
|
}
|
|
782
1037
|
}
|
|
783
1038
|
};
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
this.signals.clear();
|
|
1039
|
+
// --- Helpers ---
|
|
1040
|
+
use = (plugin) => {
|
|
1041
|
+
this.pluginManager.add(plugin);
|
|
1042
|
+
return this;
|
|
789
1043
|
};
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
1044
|
+
isStale = (queryKey) => {
|
|
1045
|
+
const key = this.storage.generateKey(queryKey);
|
|
1046
|
+
const signal2 = this.storage.get(key);
|
|
1047
|
+
const entry = signal2?.get();
|
|
1048
|
+
if (!entry) return true;
|
|
1049
|
+
if (entry.isInvalidated) return true;
|
|
1050
|
+
return Date.now() - entry.timestamp > entry.staleTime;
|
|
1051
|
+
};
|
|
1052
|
+
getAll = () => this.storage.getAll();
|
|
1053
|
+
snapshot = () => this.storage.getSnapshot();
|
|
1054
|
+
clear = () => this.storage.clear();
|
|
1055
|
+
remove = (key) => this.storage.delete(this.storage.generateKey(key));
|
|
1056
|
+
// Restored Methods
|
|
793
1057
|
prefetch = (queryKey, data, options) => {
|
|
794
1058
|
this.set(queryKey, data, options);
|
|
795
1059
|
};
|
|
796
|
-
/**
|
|
797
|
-
* Garbage collection - remove expired entries
|
|
798
|
-
*/
|
|
799
|
-
startGarbageCollection = () => {
|
|
800
|
-
this.gcInterval = setInterval(() => {
|
|
801
|
-
const now = Date.now();
|
|
802
|
-
for (const [key, signal] of this.signals.entries()) {
|
|
803
|
-
const entry = signal.get();
|
|
804
|
-
if (!entry) continue;
|
|
805
|
-
const age = now - entry.timestamp;
|
|
806
|
-
if (age > entry.cacheTime) {
|
|
807
|
-
this.signals.delete(key);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}, 60 * 1e3);
|
|
811
|
-
};
|
|
812
|
-
/**
|
|
813
|
-
* Stop garbage collection
|
|
814
|
-
*/
|
|
815
1060
|
destroy = () => {
|
|
816
|
-
|
|
817
|
-
clearInterval(this.gcInterval);
|
|
818
|
-
this.gcInterval = null;
|
|
819
|
-
}
|
|
820
|
-
this.clear();
|
|
1061
|
+
this.storage.clear();
|
|
821
1062
|
};
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
* Get all entries (wrapper for DevTools)
|
|
833
|
-
*/
|
|
834
|
-
getAll = () => {
|
|
835
|
-
const map = /* @__PURE__ */ new Map();
|
|
836
|
-
for (const [key, signal] of this.signals.entries()) {
|
|
837
|
-
const val = signal.get();
|
|
838
|
-
if (val) map.set(key, val);
|
|
1063
|
+
getStats = () => this.storage.getStats();
|
|
1064
|
+
// For Hydration
|
|
1065
|
+
getSnapshot = () => this.storage.getSnapshot();
|
|
1066
|
+
invalidateAll = () => {
|
|
1067
|
+
for (const key of this.storage.getSnapshot().keys()) {
|
|
1068
|
+
const signal2 = this.storage.get(key);
|
|
1069
|
+
const entry = signal2?.get();
|
|
1070
|
+
if (entry) {
|
|
1071
|
+
signal2?.set({ ...entry, isInvalidated: true });
|
|
1072
|
+
}
|
|
839
1073
|
}
|
|
840
|
-
return map;
|
|
841
1074
|
};
|
|
1075
|
+
normalizeKey(queryKey) {
|
|
1076
|
+
return Array.isArray(queryKey) ? queryKey : [queryKey.key, queryKey.params];
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
// src/addon/query/pagination.ts
|
|
1081
|
+
import { useState, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
1082
|
+
|
|
1083
|
+
// src/addon/query/context.tsx
|
|
1084
|
+
import { createContext, useContext } from "react";
|
|
1085
|
+
import { jsx } from "react/jsx-runtime";
|
|
1086
|
+
var QueryClientContext = createContext(void 0);
|
|
1087
|
+
var QueryClientProvider = ({
|
|
1088
|
+
client,
|
|
1089
|
+
children
|
|
1090
|
+
}) => {
|
|
1091
|
+
return /* @__PURE__ */ jsx(QueryClientContext.Provider, { value: client, children });
|
|
1092
|
+
};
|
|
1093
|
+
var useQueryClient = () => {
|
|
1094
|
+
const client = useContext(QueryClientContext);
|
|
1095
|
+
if (!client) {
|
|
1096
|
+
throw new Error("No QueryClient set, use QueryClientProvider to set one");
|
|
1097
|
+
}
|
|
1098
|
+
return client;
|
|
842
1099
|
};
|
|
843
|
-
var queryCache = new QueryCache();
|
|
844
1100
|
|
|
845
1101
|
// src/addon/query/pagination.ts
|
|
846
|
-
import { useState, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
847
1102
|
function usePaginatedQuery({
|
|
848
1103
|
queryKey,
|
|
849
1104
|
queryFn,
|
|
850
1105
|
pageSize = 20,
|
|
851
1106
|
staleTime,
|
|
852
1107
|
cacheTime,
|
|
853
|
-
enabled = true
|
|
1108
|
+
enabled = true,
|
|
1109
|
+
retry
|
|
854
1110
|
}) {
|
|
1111
|
+
const client = useQueryClient();
|
|
855
1112
|
const [page, setPage] = useState(0);
|
|
856
|
-
const [
|
|
857
|
-
const
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
1113
|
+
const pageQueryKey = [...queryKey, "page", page];
|
|
1114
|
+
const pageQueryKeyHash = JSON.stringify(pageQueryKey);
|
|
1115
|
+
const subscribe2 = useCallback2((onStoreChange) => {
|
|
1116
|
+
const signal2 = client.getSignal(pageQueryKey);
|
|
1117
|
+
return signal2.subscribe(() => onStoreChange());
|
|
1118
|
+
}, [client, pageQueryKeyHash]);
|
|
1119
|
+
const getSnapshot = useCallback2(() => {
|
|
1120
|
+
const signal2 = client.getSignal(pageQueryKey);
|
|
1121
|
+
return signal2.get();
|
|
1122
|
+
}, [client, pageQueryKeyHash]);
|
|
1123
|
+
const cacheEntry = useSyncExternalStore2(subscribe2, getSnapshot);
|
|
1124
|
+
const data = cacheEntry?.data;
|
|
1125
|
+
const status = cacheEntry?.status || "pending";
|
|
1126
|
+
const error = cacheEntry?.error || null;
|
|
1127
|
+
const isFetching = cacheEntry?.isFetching || false;
|
|
1128
|
+
const dataTimestamp = cacheEntry?.timestamp;
|
|
1129
|
+
const isError = status === "error";
|
|
1130
|
+
const isLoading = data === void 0 && (isFetching || status === "pending");
|
|
1131
|
+
let hasNext = true;
|
|
1132
|
+
if (data) {
|
|
1133
|
+
if (Array.isArray(data)) {
|
|
1134
|
+
hasNext = data.length === pageSize;
|
|
1135
|
+
} else if (typeof data === "object" && "hasMore" in data) {
|
|
1136
|
+
hasNext = data.hasMore;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
const hasPrevious = page > 0;
|
|
861
1140
|
const queryFnRef = useRef2(queryFn);
|
|
1141
|
+
const staleTimeRef = useRef2(staleTime);
|
|
1142
|
+
const cacheTimeRef = useRef2(cacheTime);
|
|
862
1143
|
useEffect2(() => {
|
|
863
1144
|
queryFnRef.current = queryFn;
|
|
1145
|
+
staleTimeRef.current = staleTime;
|
|
1146
|
+
cacheTimeRef.current = cacheTime;
|
|
864
1147
|
});
|
|
865
|
-
const
|
|
866
|
-
const fetchPage = useCallback2(async (pageNum) => {
|
|
1148
|
+
const fetchPage = useCallback2(async (background = false) => {
|
|
867
1149
|
if (!enabled) return;
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
return;
|
|
1150
|
+
if (!background) {
|
|
1151
|
+
const currentEntry = getSnapshot();
|
|
1152
|
+
if (currentEntry && Date.now() - currentEntry.timestamp <= (staleTimeRef.current || 0)) {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
874
1155
|
}
|
|
875
1156
|
try {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
setHasNext(result.length === pageSize);
|
|
884
|
-
} else if (result && typeof result === "object" && "hasMore" in result) {
|
|
885
|
-
setHasNext(result.hasMore);
|
|
886
|
-
}
|
|
887
|
-
setIsLoading(false);
|
|
1157
|
+
const result = await client.fetch(pageQueryKey, async () => {
|
|
1158
|
+
return await queryFnRef.current(page);
|
|
1159
|
+
}, { retry });
|
|
1160
|
+
client.set(pageQueryKey, result, {
|
|
1161
|
+
staleTime: staleTimeRef.current,
|
|
1162
|
+
cacheTime: cacheTimeRef.current
|
|
1163
|
+
});
|
|
888
1164
|
} catch (err) {
|
|
889
|
-
setIsError(true);
|
|
890
|
-
setError(err);
|
|
891
|
-
setIsLoading(false);
|
|
892
1165
|
}
|
|
893
|
-
}, [
|
|
1166
|
+
}, [pageQueryKeyHash, enabled, client, getSnapshot, page]);
|
|
894
1167
|
useEffect2(() => {
|
|
895
|
-
|
|
896
|
-
|
|
1168
|
+
if (enabled) {
|
|
1169
|
+
fetchPage();
|
|
1170
|
+
}
|
|
1171
|
+
}, [fetchPage, enabled]);
|
|
897
1172
|
const nextPage = useCallback2(() => {
|
|
898
1173
|
if (hasNext) {
|
|
899
1174
|
setPage((p) => p + 1);
|
|
@@ -905,9 +1180,9 @@ function usePaginatedQuery({
|
|
|
905
1180
|
}
|
|
906
1181
|
}, [page]);
|
|
907
1182
|
const refetch = useCallback2(async () => {
|
|
908
|
-
|
|
909
|
-
await fetchPage(
|
|
910
|
-
}, [
|
|
1183
|
+
client.invalidate(pageQueryKey);
|
|
1184
|
+
await fetchPage();
|
|
1185
|
+
}, [pageQueryKeyHash, fetchPage, client]);
|
|
911
1186
|
return {
|
|
912
1187
|
data,
|
|
913
1188
|
isLoading,
|
|
@@ -918,313 +1193,447 @@ function usePaginatedQuery({
|
|
|
918
1193
|
nextPage,
|
|
919
1194
|
previousPage,
|
|
920
1195
|
hasNext,
|
|
921
|
-
hasPrevious
|
|
1196
|
+
hasPrevious,
|
|
922
1197
|
refetch
|
|
923
1198
|
};
|
|
924
1199
|
}
|
|
925
1200
|
|
|
926
1201
|
// src/addon/query/useQuery.ts
|
|
927
|
-
import { useEffect as useEffect3, useCallback as useCallback3,
|
|
1202
|
+
import { useState as useState2, useEffect as useEffect3, useCallback as useCallback3, useSyncExternalStore as useSyncExternalStore3, useRef as useRef3 } from "react";
|
|
928
1203
|
|
|
929
|
-
// src/addon/query/
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
}) => {
|
|
937
|
-
return /* @__PURE__ */ jsx(QueryClientContext.Provider, { value: client, children });
|
|
938
|
-
};
|
|
939
|
-
var useQueryClient = () => {
|
|
940
|
-
const client = useContext(QueryClientContext);
|
|
941
|
-
return client || queryCache;
|
|
942
|
-
};
|
|
1204
|
+
// src/addon/query/plugins/validation.ts
|
|
1205
|
+
function validateWithSchema(data, schema) {
|
|
1206
|
+
if (!schema) {
|
|
1207
|
+
return data;
|
|
1208
|
+
}
|
|
1209
|
+
return schema.parse(data);
|
|
1210
|
+
}
|
|
943
1211
|
|
|
944
|
-
// src/addon/query/
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1212
|
+
// src/addon/query/queryObserver.ts
|
|
1213
|
+
var QueryObserver = class {
|
|
1214
|
+
client;
|
|
1215
|
+
options;
|
|
1216
|
+
queryKeyHash;
|
|
1217
|
+
signal;
|
|
1218
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1219
|
+
// Internal state management
|
|
1220
|
+
abortController = null;
|
|
1221
|
+
intervalParams = { id: null };
|
|
1222
|
+
unsubscribeSignal = null;
|
|
1223
|
+
// Derived state cache to ensure referential stability where possible
|
|
1224
|
+
currentResult;
|
|
1225
|
+
constructor(client, options) {
|
|
1226
|
+
this.client = client;
|
|
1227
|
+
this.options = options;
|
|
1228
|
+
this.queryKeyHash = stableHash(options.queryKey);
|
|
1229
|
+
this.signal = client.getSignal(options.queryKey);
|
|
1230
|
+
}
|
|
1231
|
+
setOptions(options) {
|
|
1232
|
+
const prevOptions = this.options;
|
|
1233
|
+
this.options = options;
|
|
1234
|
+
const newHash = stableHash(options.queryKey);
|
|
1235
|
+
if (newHash !== this.queryKeyHash) {
|
|
1236
|
+
this.queryKeyHash = newHash;
|
|
1237
|
+
this.updateSignal();
|
|
1238
|
+
this.checkAndFetch();
|
|
1239
|
+
} else {
|
|
1240
|
+
if (options.enabled && !prevOptions.enabled) {
|
|
1241
|
+
this.checkAndFetch();
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
if (options.refetchInterval !== prevOptions.refetchInterval) {
|
|
1245
|
+
this.setupInterval();
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
subscribe(listener) {
|
|
1249
|
+
this.listeners.add(listener);
|
|
1250
|
+
if (this.listeners.size === 1) {
|
|
1251
|
+
this.init();
|
|
1252
|
+
}
|
|
1253
|
+
return () => {
|
|
1254
|
+
this.listeners.delete(listener);
|
|
1255
|
+
if (this.listeners.size === 0) {
|
|
1256
|
+
this.destroy();
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
init() {
|
|
1261
|
+
this.updateSignal();
|
|
1262
|
+
this.setupGlobalListeners();
|
|
1263
|
+
this.setupInterval();
|
|
1264
|
+
this.checkAndFetch();
|
|
1265
|
+
}
|
|
1266
|
+
destroy() {
|
|
1267
|
+
this.cleanupGlobalListeners();
|
|
1268
|
+
this.cleanupInterval();
|
|
1269
|
+
if (this.unsubscribeSignal) {
|
|
1270
|
+
this.unsubscribeSignal();
|
|
1271
|
+
this.unsubscribeSignal = null;
|
|
1272
|
+
}
|
|
1273
|
+
if (this.abortController) {
|
|
1274
|
+
this.abortController.abort();
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
updateSignal() {
|
|
1278
|
+
if (this.unsubscribeSignal) this.unsubscribeSignal();
|
|
1279
|
+
this.signal = this.client.getSignal(this.options.queryKey);
|
|
1280
|
+
this.unsubscribeSignal = this.signal.subscribe(() => {
|
|
1281
|
+
this.notify();
|
|
962
1282
|
});
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
const
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
error
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
if (!
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1283
|
+
}
|
|
1284
|
+
computeResult() {
|
|
1285
|
+
const entry = this.signal.get();
|
|
1286
|
+
const data = entry?.data;
|
|
1287
|
+
const status = entry?.status || "pending";
|
|
1288
|
+
const error = entry?.error || null;
|
|
1289
|
+
const isFetching = entry?.isFetching || false;
|
|
1290
|
+
const dataTimestamp = entry?.timestamp;
|
|
1291
|
+
const staleTime = this.options.staleTime ?? 0;
|
|
1292
|
+
const isStale = entry?.isInvalidated || (dataTimestamp ? Date.now() - dataTimestamp > staleTime : true);
|
|
1293
|
+
const isError = status === "error";
|
|
1294
|
+
const isLoading = data === void 0;
|
|
1295
|
+
const nextResult = {
|
|
1296
|
+
data,
|
|
1297
|
+
isLoading,
|
|
1298
|
+
isError,
|
|
1299
|
+
isFetching,
|
|
1300
|
+
isStale,
|
|
1301
|
+
error,
|
|
1302
|
+
status,
|
|
1303
|
+
refetch: this.refetch
|
|
1304
|
+
};
|
|
1305
|
+
if (this.currentResult && this.shallowEqual(this.currentResult, nextResult)) {
|
|
1306
|
+
return this.currentResult;
|
|
1307
|
+
}
|
|
1308
|
+
this.currentResult = nextResult;
|
|
1309
|
+
return nextResult;
|
|
1310
|
+
}
|
|
1311
|
+
getSnapshot = () => {
|
|
1312
|
+
if (!this.currentResult) {
|
|
1313
|
+
return this.computeResult();
|
|
1314
|
+
}
|
|
1315
|
+
return this.currentResult;
|
|
1316
|
+
};
|
|
1317
|
+
shallowEqual(objA, objB) {
|
|
1318
|
+
if (Object.is(objA, objB)) return true;
|
|
1319
|
+
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) return false;
|
|
1320
|
+
const recordA = objA;
|
|
1321
|
+
const recordB = objB;
|
|
1322
|
+
const keysA = Object.keys(recordA);
|
|
1323
|
+
const keysB = Object.keys(recordB);
|
|
1324
|
+
if (keysA.length !== keysB.length) return false;
|
|
1325
|
+
for (const key of keysA) {
|
|
1326
|
+
if (!Object.prototype.hasOwnProperty.call(recordB, key) || !Object.is(recordA[key], recordB[key])) {
|
|
1327
|
+
return false;
|
|
996
1328
|
}
|
|
997
1329
|
}
|
|
1330
|
+
return true;
|
|
1331
|
+
}
|
|
1332
|
+
notify() {
|
|
1333
|
+
this.computeResult();
|
|
1334
|
+
this.listeners.forEach((l) => l());
|
|
1335
|
+
this.checkAndFetch();
|
|
1336
|
+
}
|
|
1337
|
+
// --- Fetch Logic ---
|
|
1338
|
+
fetch = async (background = false) => {
|
|
1339
|
+
if (this.options.enabled === false) return;
|
|
1340
|
+
if (this.abortController) this.abortController.abort();
|
|
1341
|
+
this.abortController = new AbortController();
|
|
1342
|
+
const signal2 = this.abortController.signal;
|
|
998
1343
|
try {
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1344
|
+
let result = await this.client.fetch(
|
|
1345
|
+
this.options.queryKey,
|
|
1346
|
+
(ctx) => this.options.queryFn(ctx),
|
|
1347
|
+
{ signal: signal2, retry: this.options.retry, retryDelay: this.options.retryDelay }
|
|
1348
|
+
);
|
|
1349
|
+
try {
|
|
1350
|
+
result = validateWithSchema(result, this.options.schema);
|
|
1351
|
+
} catch (validationErr) {
|
|
1352
|
+
const current = this.signal.get();
|
|
1353
|
+
this.signal.set({
|
|
1354
|
+
...current,
|
|
1355
|
+
status: "error",
|
|
1356
|
+
error: validationErr,
|
|
1357
|
+
isFetching: false,
|
|
1358
|
+
data: void 0
|
|
1359
|
+
});
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
this.client.set(this.options.queryKey, result, {
|
|
1363
|
+
staleTime: this.options.staleTime,
|
|
1364
|
+
cacheTime: this.options.cacheTime,
|
|
1365
|
+
tags: this.options.tags
|
|
1009
1366
|
});
|
|
1010
|
-
client.set(key, result, { staleTime, cacheTime });
|
|
1011
|
-
dispatch({ type: "FETCH_SUCCESS" });
|
|
1012
1367
|
} catch (err) {
|
|
1013
|
-
if (err.name === "AbortError") return;
|
|
1014
|
-
|
|
1368
|
+
if (err instanceof Error && err.name === "AbortError") return;
|
|
1369
|
+
if (err instanceof Error && err.name !== "AbortError") {
|
|
1370
|
+
}
|
|
1015
1371
|
}
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1372
|
+
};
|
|
1373
|
+
checkAndFetch() {
|
|
1374
|
+
if (this.options.enabled === false) return;
|
|
1375
|
+
const snapshot = this.getSnapshot();
|
|
1376
|
+
if (snapshot.isLoading && !snapshot.isFetching && !snapshot.isError) {
|
|
1377
|
+
this.fetch();
|
|
1378
|
+
} else if (snapshot.isStale && !snapshot.isFetching && !snapshot.isError) {
|
|
1379
|
+
this.fetch();
|
|
1020
1380
|
}
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1381
|
+
}
|
|
1382
|
+
refetch = async () => {
|
|
1383
|
+
this.client.invalidate(this.options.queryKey);
|
|
1384
|
+
await this.fetch();
|
|
1385
|
+
};
|
|
1386
|
+
// --- Background Refetching ---
|
|
1387
|
+
setupInterval() {
|
|
1388
|
+
this.cleanupInterval();
|
|
1389
|
+
if (this.options.enabled !== false && this.options.refetchInterval) {
|
|
1390
|
+
this.intervalParams.id = setInterval(() => {
|
|
1391
|
+
this.fetch(true);
|
|
1392
|
+
}, this.options.refetchInterval);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
cleanupInterval() {
|
|
1396
|
+
if (this.intervalParams.id) {
|
|
1397
|
+
clearInterval(this.intervalParams.id);
|
|
1398
|
+
this.intervalParams.id = null;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
onFocus = () => {
|
|
1402
|
+
if (this.options.refetchOnWindowFocus) {
|
|
1403
|
+
const snapshot = this.getSnapshot();
|
|
1404
|
+
if (snapshot.isStale && !snapshot.isFetching) {
|
|
1405
|
+
this.fetch(true);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
onOnline = () => {
|
|
1410
|
+
if (this.options.refetchOnReconnect) {
|
|
1411
|
+
const snapshot = this.getSnapshot();
|
|
1412
|
+
if (snapshot.isStale && !snapshot.isFetching) {
|
|
1413
|
+
this.fetch(true);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
setupGlobalListeners() {
|
|
1418
|
+
if (typeof window !== "undefined") {
|
|
1419
|
+
window.addEventListener("focus", this.onFocus);
|
|
1420
|
+
window.addEventListener("online", this.onOnline);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
cleanupGlobalListeners() {
|
|
1424
|
+
if (typeof window !== "undefined") {
|
|
1425
|
+
window.removeEventListener("focus", this.onFocus);
|
|
1426
|
+
window.removeEventListener("online", this.onOnline);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
};
|
|
1430
|
+
|
|
1431
|
+
// src/addon/query/useQuery.ts
|
|
1432
|
+
function useQuery(options) {
|
|
1433
|
+
const client = useQueryClient();
|
|
1434
|
+
const [observer] = useState2(() => new QueryObserver(client, options));
|
|
1039
1435
|
useEffect3(() => {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1436
|
+
observer.setOptions(options);
|
|
1437
|
+
}, [observer, options]);
|
|
1438
|
+
const subscribe2 = useCallback3((onStoreChange) => {
|
|
1439
|
+
return observer.subscribe(onStoreChange);
|
|
1440
|
+
}, [observer]);
|
|
1441
|
+
const select = options?.select;
|
|
1442
|
+
const selectRef = useRef3(select);
|
|
1443
|
+
selectRef.current = select;
|
|
1444
|
+
const memoRef = useRef3({ entry: void 0, selected: void 0 });
|
|
1445
|
+
const getSnapshotWithSelector = useCallback3(() => {
|
|
1446
|
+
const entry = observer.getSnapshot();
|
|
1447
|
+
if (entry === memoRef.current.entry) {
|
|
1448
|
+
return memoRef.current.selected;
|
|
1449
|
+
}
|
|
1450
|
+
let processedResult;
|
|
1451
|
+
if (!entry) {
|
|
1452
|
+
processedResult = void 0;
|
|
1453
|
+
} else {
|
|
1454
|
+
if (selectRef.current && entry.data !== void 0) {
|
|
1455
|
+
processedResult = { ...entry, data: selectRef.current(entry.data) };
|
|
1456
|
+
} else {
|
|
1457
|
+
processedResult = entry;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
memoRef.current = { entry, selected: processedResult };
|
|
1461
|
+
return processedResult;
|
|
1462
|
+
}, [observer]);
|
|
1463
|
+
const result = useSyncExternalStore3(subscribe2, getSnapshotWithSelector);
|
|
1464
|
+
const status = result?.status || "pending";
|
|
1465
|
+
const computedResult = {
|
|
1466
|
+
...result,
|
|
1467
|
+
isPending: status === "pending",
|
|
1468
|
+
isSuccess: status === "success",
|
|
1469
|
+
isError: status === "error"
|
|
1470
|
+
};
|
|
1471
|
+
const typedResult = computedResult;
|
|
1472
|
+
const signal2 = client.getSignal(options.queryKey);
|
|
1053
1473
|
return {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
isFetching: statusState.isFetching,
|
|
1058
|
-
isStale,
|
|
1059
|
-
error: statusState.error,
|
|
1060
|
-
refetch
|
|
1474
|
+
...typedResult,
|
|
1475
|
+
signal: signal2
|
|
1476
|
+
// Keep signal as T (source)
|
|
1061
1477
|
};
|
|
1062
1478
|
}
|
|
1063
|
-
function statusReducer(state, action) {
|
|
1064
|
-
switch (action.type) {
|
|
1065
|
-
case "FETCH_START":
|
|
1066
|
-
return {
|
|
1067
|
-
...state,
|
|
1068
|
-
isFetching: true,
|
|
1069
|
-
error: null
|
|
1070
|
-
};
|
|
1071
|
-
case "FETCH_SUCCESS":
|
|
1072
|
-
return {
|
|
1073
|
-
...state,
|
|
1074
|
-
isFetching: false,
|
|
1075
|
-
error: null
|
|
1076
|
-
};
|
|
1077
|
-
case "FETCH_ERROR":
|
|
1078
|
-
return {
|
|
1079
|
-
...state,
|
|
1080
|
-
isFetching: false,
|
|
1081
|
-
error: action.error
|
|
1082
|
-
};
|
|
1083
|
-
default:
|
|
1084
|
-
return state;
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
1479
|
|
|
1088
1480
|
// src/addon/query/useMutation.ts
|
|
1089
|
-
import {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1481
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useSyncExternalStore as useSyncExternalStore4, useState as useState3 } from "react";
|
|
1482
|
+
|
|
1483
|
+
// src/addon/query/mutationObserver.ts
|
|
1484
|
+
var generateId = () => {
|
|
1485
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
1486
|
+
return crypto.randomUUID();
|
|
1487
|
+
}
|
|
1488
|
+
return "mutation-" + Date.now() + "-" + Math.random().toString(36).slice(2);
|
|
1489
|
+
};
|
|
1490
|
+
var MutationObserver = class {
|
|
1491
|
+
client;
|
|
1492
|
+
options;
|
|
1493
|
+
currentMutationId = null;
|
|
1494
|
+
// We maintain our own signal for this observer's view of the mutation
|
|
1495
|
+
// This ensures we don't miss updates if we switch IDs.
|
|
1496
|
+
signal;
|
|
1497
|
+
constructor(client, options) {
|
|
1498
|
+
this.client = client;
|
|
1499
|
+
this.options = options;
|
|
1500
|
+
this.signal = createSignal({
|
|
1501
|
+
status: "idle",
|
|
1502
|
+
data: void 0,
|
|
1503
|
+
error: null,
|
|
1504
|
+
variables: void 0,
|
|
1505
|
+
context: void 0,
|
|
1506
|
+
submittedAt: 0
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
setOptions(options) {
|
|
1510
|
+
this.options = options;
|
|
1511
|
+
}
|
|
1512
|
+
mutate = (variables) => {
|
|
1513
|
+
const id = generateId();
|
|
1514
|
+
this.currentMutationId = id;
|
|
1515
|
+
this.client.mutationCache.register(id, this.options.mutationKey);
|
|
1516
|
+
const pendingState = {
|
|
1517
|
+
status: "pending",
|
|
1518
|
+
variables,
|
|
1519
|
+
submittedAt: Date.now(),
|
|
1520
|
+
data: void 0,
|
|
1521
|
+
error: null,
|
|
1522
|
+
context: void 0
|
|
1523
|
+
};
|
|
1524
|
+
this.signal.set({
|
|
1525
|
+
...this.signal.get(),
|
|
1526
|
+
...pendingState
|
|
1527
|
+
});
|
|
1528
|
+
this.client.mutationCache.notify(id, pendingState);
|
|
1529
|
+
const unsubscribe = this.client.mutationCache.getSignal(id).subscribe((state) => {
|
|
1530
|
+
const current = this.signal.get();
|
|
1531
|
+
if (current.status !== state.status || current.data !== state.data || current.error !== state.error) {
|
|
1532
|
+
this.signal.set(state);
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1535
|
+
return this.executeMutation(id, variables).finally(() => {
|
|
1536
|
+
});
|
|
1537
|
+
};
|
|
1538
|
+
executeMutation = async (id, variables) => {
|
|
1539
|
+
const { mutationFn, onMutate, onSuccess, onError, onSettled, invalidatesTags, optimistic, mutationKey } = this.options;
|
|
1103
1540
|
let context;
|
|
1541
|
+
let optimisticSnapshot;
|
|
1542
|
+
const notify = (update) => {
|
|
1543
|
+
this.client.mutationCache.notify(id, update);
|
|
1544
|
+
};
|
|
1104
1545
|
try {
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1546
|
+
if (optimistic) {
|
|
1547
|
+
const { queryKey, update } = optimistic;
|
|
1548
|
+
const signal2 = this.client.getSignal(queryKey);
|
|
1549
|
+
const currentData = signal2.get()?.data;
|
|
1550
|
+
optimisticSnapshot = currentData;
|
|
1551
|
+
const optimisticData = update(variables, currentData);
|
|
1552
|
+
this.client.set(queryKey, optimisticData);
|
|
1553
|
+
}
|
|
1109
1554
|
if (onMutate) {
|
|
1110
1555
|
context = await onMutate(variables);
|
|
1556
|
+
notify({ context });
|
|
1111
1557
|
}
|
|
1112
1558
|
const result = await mutationFn(variables);
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
onSuccess(result, variables, context);
|
|
1559
|
+
notify({ status: "success", data: result });
|
|
1560
|
+
if (onSuccess) await onSuccess(result, variables, context);
|
|
1561
|
+
if (this.client.invalidateTags && invalidatesTags) {
|
|
1562
|
+
this.client.invalidateTags(invalidatesTags);
|
|
1118
1563
|
}
|
|
1119
|
-
if (
|
|
1120
|
-
|
|
1564
|
+
if (optimistic) {
|
|
1565
|
+
this.client.invalidate(optimistic.queryKey);
|
|
1121
1566
|
}
|
|
1567
|
+
if (onSettled) onSettled(result, null, variables, context);
|
|
1122
1568
|
return result;
|
|
1123
|
-
} catch (
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
if (onError) {
|
|
1128
|
-
onError(err, variables, context);
|
|
1129
|
-
}
|
|
1130
|
-
if (onSettled) {
|
|
1131
|
-
onSettled(void 0, err, variables, context);
|
|
1569
|
+
} catch (error) {
|
|
1570
|
+
if (optimistic && optimisticSnapshot !== void 0) {
|
|
1571
|
+
const queryCache = this.client;
|
|
1572
|
+
queryCache.set(optimistic.queryKey, optimisticSnapshot);
|
|
1132
1573
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
try {
|
|
1138
|
-
await mutateAsync(variables);
|
|
1139
|
-
} catch {
|
|
1574
|
+
notify({ status: "error", error });
|
|
1575
|
+
if (onError) onError(error, variables, context);
|
|
1576
|
+
if (onSettled) onSettled(void 0, error, variables, context);
|
|
1577
|
+
throw error;
|
|
1140
1578
|
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1579
|
+
};
|
|
1580
|
+
reset = () => {
|
|
1581
|
+
this.signal.set({
|
|
1582
|
+
status: "idle",
|
|
1583
|
+
data: void 0,
|
|
1584
|
+
error: null,
|
|
1585
|
+
variables: void 0,
|
|
1586
|
+
submittedAt: 0
|
|
1587
|
+
});
|
|
1588
|
+
this.currentMutationId = null;
|
|
1589
|
+
};
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1592
|
+
// src/addon/query/useMutation.ts
|
|
1593
|
+
function useMutation(options) {
|
|
1594
|
+
const client = useQueryClient();
|
|
1595
|
+
const [observer] = useState3(() => new MutationObserver(client, options));
|
|
1596
|
+
useEffect4(() => {
|
|
1597
|
+
observer.setOptions(options);
|
|
1598
|
+
}, [observer, options]);
|
|
1599
|
+
const state = useSyncExternalStore4(
|
|
1600
|
+
useCallback4((cb) => observer.signal.subscribe(cb), [observer]),
|
|
1601
|
+
() => observer.signal.get()
|
|
1602
|
+
);
|
|
1603
|
+
const mutateAsync = useCallback4((variables) => {
|
|
1604
|
+
return observer.mutate(variables);
|
|
1605
|
+
}, [observer]);
|
|
1606
|
+
const mutate = useCallback4((variables) => {
|
|
1607
|
+
observer.mutate(variables).catch(() => {
|
|
1608
|
+
});
|
|
1609
|
+
}, [observer]);
|
|
1149
1610
|
return {
|
|
1150
1611
|
mutate,
|
|
1151
1612
|
mutateAsync,
|
|
1152
|
-
data,
|
|
1153
|
-
error,
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1613
|
+
data: state.data,
|
|
1614
|
+
error: state.error,
|
|
1615
|
+
status: state.status,
|
|
1616
|
+
isLoading: state.status === "pending",
|
|
1617
|
+
isError: state.status === "error",
|
|
1618
|
+
isSuccess: state.status === "success",
|
|
1619
|
+
isIdle: state.status === "idle",
|
|
1620
|
+
reset: observer.reset
|
|
1158
1621
|
};
|
|
1159
1622
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
getQueryData(queryKey) {
|
|
1170
|
-
return queryCache.get(queryKey);
|
|
1171
|
-
},
|
|
1172
|
-
/**
|
|
1173
|
-
* Set query data (for optimistic updates)
|
|
1174
|
-
*/
|
|
1175
|
-
setQueryData(queryKey, updater) {
|
|
1176
|
-
const current = queryCache.get(queryKey);
|
|
1177
|
-
const newData = typeof updater === "function" ? updater(current) : updater;
|
|
1178
|
-
queryCache.set(queryKey, newData);
|
|
1179
|
-
return current;
|
|
1180
|
-
},
|
|
1181
|
-
/**
|
|
1182
|
-
* Invalidate queries (trigger refetch)
|
|
1183
|
-
*/
|
|
1184
|
-
invalidateQueries(queryKey) {
|
|
1185
|
-
queryCache.invalidate(queryKey);
|
|
1186
|
-
}
|
|
1623
|
+
|
|
1624
|
+
// src/addon/query/infiniteQuery.ts
|
|
1625
|
+
import { useEffect as useEffect5, useCallback as useCallback5, useRef as useRef4, useSyncExternalStore as useSyncExternalStore5, useMemo } from "react";
|
|
1626
|
+
|
|
1627
|
+
// src/addon/query/plugins/logger.ts
|
|
1628
|
+
var consoleLogger = {
|
|
1629
|
+
log: console.log,
|
|
1630
|
+
warn: console.warn,
|
|
1631
|
+
error: console.error
|
|
1187
1632
|
};
|
|
1633
|
+
var currentLogger = consoleLogger;
|
|
1634
|
+
var getLogger = () => currentLogger;
|
|
1188
1635
|
|
|
1189
1636
|
// src/addon/query/infiniteQuery.ts
|
|
1190
|
-
import { useEffect as useEffect4, useCallback as useCallback5, useRef as useRef4, useReducer as useReducer2, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1191
|
-
function statusReducer2(state, action) {
|
|
1192
|
-
switch (action.type) {
|
|
1193
|
-
case "FETCH_START":
|
|
1194
|
-
return {
|
|
1195
|
-
...state,
|
|
1196
|
-
isFetching: true,
|
|
1197
|
-
isFetchingNextPage: action.direction === "next",
|
|
1198
|
-
isFetchingPreviousPage: action.direction === "previous",
|
|
1199
|
-
error: null
|
|
1200
|
-
};
|
|
1201
|
-
case "FETCH_SUCCESS":
|
|
1202
|
-
return {
|
|
1203
|
-
...state,
|
|
1204
|
-
isFetching: false,
|
|
1205
|
-
isFetchingNextPage: false,
|
|
1206
|
-
isFetchingPreviousPage: false,
|
|
1207
|
-
hasNextPage: action.hasNextPage !== void 0 ? action.hasNextPage : state.hasNextPage,
|
|
1208
|
-
hasPreviousPage: action.hasPreviousPage !== void 0 ? action.hasPreviousPage : state.hasPreviousPage
|
|
1209
|
-
};
|
|
1210
|
-
case "FETCH_ERROR":
|
|
1211
|
-
return {
|
|
1212
|
-
...state,
|
|
1213
|
-
isFetching: false,
|
|
1214
|
-
isFetchingNextPage: false,
|
|
1215
|
-
isFetchingPreviousPage: false,
|
|
1216
|
-
error: action.error
|
|
1217
|
-
};
|
|
1218
|
-
case "SET_PAGINATION":
|
|
1219
|
-
return {
|
|
1220
|
-
...state,
|
|
1221
|
-
hasNextPage: action.hasNextPage !== void 0 ? action.hasNextPage : state.hasNextPage,
|
|
1222
|
-
hasPreviousPage: action.hasPreviousPage !== void 0 ? action.hasPreviousPage : state.hasPreviousPage
|
|
1223
|
-
};
|
|
1224
|
-
default:
|
|
1225
|
-
return state;
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
1637
|
function useInfiniteQuery({
|
|
1229
1638
|
queryKey,
|
|
1230
1639
|
queryFn,
|
|
@@ -1233,619 +1642,319 @@ function useInfiniteQuery({
|
|
|
1233
1642
|
initialPageParam,
|
|
1234
1643
|
staleTime = 0,
|
|
1235
1644
|
cacheTime = 5 * 60 * 1e3,
|
|
1236
|
-
enabled = true
|
|
1645
|
+
enabled = true,
|
|
1646
|
+
retry
|
|
1237
1647
|
}) {
|
|
1238
1648
|
const client = useQueryClient();
|
|
1239
1649
|
const queryKeyHash = stableHash(queryKey);
|
|
1240
|
-
const infiniteQueryKey = [...queryKey, "__infinite__"];
|
|
1650
|
+
const infiniteQueryKey = useMemo(() => [...queryKey, "__infinite__"], [queryKeyHash]);
|
|
1241
1651
|
const subscribe2 = useCallback5((onStoreChange) => {
|
|
1242
|
-
const
|
|
1243
|
-
return
|
|
1244
|
-
}, [client,
|
|
1652
|
+
const signal2 = client.getSignal(infiniteQueryKey);
|
|
1653
|
+
return signal2.subscribe(() => onStoreChange());
|
|
1654
|
+
}, [client, infiniteQueryKey]);
|
|
1245
1655
|
const getSnapshot = useCallback5(() => {
|
|
1246
|
-
const
|
|
1247
|
-
return
|
|
1656
|
+
const signal2 = client.getSignal(infiniteQueryKey);
|
|
1657
|
+
return signal2.get();
|
|
1248
1658
|
}, [client, queryKeyHash]);
|
|
1249
|
-
const cacheEntry =
|
|
1659
|
+
const cacheEntry = useSyncExternalStore5(subscribe2, getSnapshot);
|
|
1250
1660
|
const data = cacheEntry?.data;
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1661
|
+
const isFetching = cacheEntry?.isFetching || false;
|
|
1662
|
+
const fetchDirection = cacheEntry?.fetchDirection || "idle";
|
|
1663
|
+
const status = cacheEntry?.status || "pending";
|
|
1664
|
+
const error = cacheEntry?.error || null;
|
|
1665
|
+
const timestamp = cacheEntry?.timestamp || 0;
|
|
1666
|
+
const isInvalidated = cacheEntry?.isInvalidated || false;
|
|
1667
|
+
let hasNextPage = false;
|
|
1668
|
+
let hasPreviousPage = false;
|
|
1669
|
+
if (data && data.pages.length > 0) {
|
|
1670
|
+
if (getNextPageParam) {
|
|
1671
|
+
const lastPage = data.pages[data.pages.length - 1];
|
|
1672
|
+
hasNextPage = getNextPageParam(lastPage, data.pages) !== void 0;
|
|
1673
|
+
}
|
|
1674
|
+
if (getPreviousPageParam) {
|
|
1675
|
+
const firstPage = data.pages[0];
|
|
1676
|
+
hasPreviousPage = getPreviousPageParam(firstPage, data.pages) !== void 0;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
const isFetchingNextPage = isFetching && fetchDirection === "next";
|
|
1680
|
+
const isFetchingPreviousPage = isFetching && fetchDirection === "previous";
|
|
1681
|
+
const isLoading = data === void 0 && isFetching;
|
|
1682
|
+
const isError = status === "error";
|
|
1260
1683
|
const queryFnRef = useRef4(queryFn);
|
|
1261
1684
|
const getNextPageParamRef = useRef4(getNextPageParam);
|
|
1262
1685
|
const getPreviousPageParamRef = useRef4(getPreviousPageParam);
|
|
1263
|
-
const initialFetchDoneRef = useRef4(false);
|
|
1264
|
-
const clientRef = useRef4(client);
|
|
1265
|
-
const infiniteQueryKeyRef = useRef4(infiniteQueryKey);
|
|
1266
1686
|
const initialPageParamRef = useRef4(initialPageParam);
|
|
1267
1687
|
const staleTimeRef = useRef4(staleTime);
|
|
1268
1688
|
const cacheTimeRef = useRef4(cacheTime);
|
|
1269
|
-
|
|
1689
|
+
useEffect5(() => {
|
|
1270
1690
|
queryFnRef.current = queryFn;
|
|
1271
1691
|
getNextPageParamRef.current = getNextPageParam;
|
|
1272
1692
|
getPreviousPageParamRef.current = getPreviousPageParam;
|
|
1273
|
-
clientRef.current = client;
|
|
1274
|
-
infiniteQueryKeyRef.current = infiniteQueryKey;
|
|
1275
1693
|
initialPageParamRef.current = initialPageParam;
|
|
1276
1694
|
staleTimeRef.current = staleTime;
|
|
1277
1695
|
cacheTimeRef.current = cacheTime;
|
|
1278
1696
|
});
|
|
1279
|
-
|
|
1280
|
-
useEffect4(() => {
|
|
1281
|
-
if (prevDataRef.current && !data) {
|
|
1282
|
-
initialFetchDoneRef.current = false;
|
|
1283
|
-
}
|
|
1284
|
-
prevDataRef.current = data;
|
|
1285
|
-
}, [data]);
|
|
1286
|
-
useEffect4(() => {
|
|
1697
|
+
useEffect5(() => {
|
|
1287
1698
|
if (!enabled) return;
|
|
1288
|
-
if (data) return;
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
const firstParam = initialParam !== void 0 ? initialParam : 0;
|
|
1292
|
-
if (!initialFetchDoneRef.current) {
|
|
1293
|
-
initialFetchDoneRef.current = true;
|
|
1294
|
-
}
|
|
1295
|
-
dispatch({ type: "FETCH_START", direction: "initial" });
|
|
1296
|
-
const pageKey = [...infiniteQueryKey, "initial", String(firstParam)];
|
|
1297
|
-
let firstPage;
|
|
1699
|
+
if (data && !isInvalidated && Date.now() - timestamp <= staleTime) return;
|
|
1700
|
+
if (isFetching) return;
|
|
1701
|
+
const doInitialFetch = async () => {
|
|
1298
1702
|
try {
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1703
|
+
if (data && data.pageParams.length > 0) {
|
|
1704
|
+
const updatedPages = [];
|
|
1705
|
+
const updatedParams = [];
|
|
1706
|
+
let param = data.pageParams[0];
|
|
1707
|
+
updatedParams.push(param);
|
|
1708
|
+
const limit = data.pages.length;
|
|
1709
|
+
const fetchedData = await client.fetch(infiniteQueryKey, async () => {
|
|
1710
|
+
for (let i = 0; i < limit; i++) {
|
|
1711
|
+
const page = await queryFnRef.current({ pageParam: param });
|
|
1712
|
+
updatedPages.push(page);
|
|
1713
|
+
if (i < limit - 1) {
|
|
1714
|
+
const next = getNextPageParamRef.current?.(page, updatedPages);
|
|
1715
|
+
if (next === void 0) break;
|
|
1716
|
+
param = next;
|
|
1717
|
+
updatedParams.push(param);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
return {
|
|
1721
|
+
pages: updatedPages,
|
|
1722
|
+
pageParams: updatedParams
|
|
1723
|
+
};
|
|
1724
|
+
}, { fetchDirection: "initial", retry });
|
|
1725
|
+
client.set(infiniteQueryKey, fetchedData, {
|
|
1726
|
+
staleTime: staleTimeRef.current,
|
|
1727
|
+
cacheTime: cacheTimeRef.current
|
|
1728
|
+
});
|
|
1729
|
+
return;
|
|
1316
1730
|
}
|
|
1317
|
-
|
|
1731
|
+
const initialParam = initialPageParamRef.current;
|
|
1732
|
+
const firstParam = initialParam !== void 0 ? initialParam : 0;
|
|
1733
|
+
const initialData = await client.fetch(infiniteQueryKey, async () => {
|
|
1734
|
+
const firstPage = await queryFnRef.current({ pageParam: firstParam });
|
|
1735
|
+
return {
|
|
1736
|
+
pages: [firstPage],
|
|
1737
|
+
pageParams: [firstParam]
|
|
1738
|
+
};
|
|
1739
|
+
}, { fetchDirection: "initial", retry });
|
|
1740
|
+
client.set(infiniteQueryKey, initialData, {
|
|
1318
1741
|
staleTime: staleTimeRef.current,
|
|
1319
1742
|
cacheTime: cacheTimeRef.current
|
|
1320
1743
|
});
|
|
1321
|
-
|
|
1744
|
+
} catch (err) {
|
|
1745
|
+
getLogger().error("Initial fetch failed", err);
|
|
1322
1746
|
}
|
|
1323
1747
|
};
|
|
1324
|
-
|
|
1325
|
-
}, [enabled, data]);
|
|
1326
|
-
const fetchPageHelper = useCallback5(async (pageParam) => {
|
|
1327
|
-
try {
|
|
1328
|
-
const pageKey = [...infiniteQueryKey, String(pageParam)];
|
|
1329
|
-
return await clientRef.current.fetch(
|
|
1330
|
-
pageKey,
|
|
1331
|
-
() => queryFnRef.current({ pageParam })
|
|
1332
|
-
);
|
|
1333
|
-
} catch (error) {
|
|
1334
|
-
dispatch({ type: "FETCH_ERROR", error });
|
|
1335
|
-
return void 0;
|
|
1336
|
-
}
|
|
1337
|
-
}, [client, infiniteQueryKey]);
|
|
1748
|
+
doInitialFetch();
|
|
1749
|
+
}, [enabled, data === void 0, isInvalidated, staleTime, timestamp]);
|
|
1338
1750
|
const fetchNextPage = useCallback5(async () => {
|
|
1339
|
-
if (!
|
|
1751
|
+
if (!hasNextPage || isFetching || !data) return;
|
|
1340
1752
|
const lastPage = data.pages[data.pages.length - 1];
|
|
1341
|
-
|
|
1342
|
-
const nextPageParam = getNextPageParamRef.current(lastPage, data.pages);
|
|
1753
|
+
const nextPageParam = getNextPageParamRef.current?.(lastPage, data.pages);
|
|
1343
1754
|
if (nextPageParam === void 0) return;
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1755
|
+
try {
|
|
1756
|
+
const updatedData = await client.fetch(infiniteQueryKey, async ({ signal: signal2 }) => {
|
|
1757
|
+
const newPage = await queryFnRef.current({ pageParam: nextPageParam });
|
|
1758
|
+
const currentEntry = client.getSignal(infiniteQueryKey).get();
|
|
1759
|
+
const currentData = currentEntry?.data;
|
|
1760
|
+
if (!currentData) throw new Error("Infinite query data missing during fetchNextPage");
|
|
1761
|
+
const nextCursor = getNextPageParamRef.current?.(newPage, [...currentData.pages, newPage]);
|
|
1762
|
+
const updatedParams = [...currentData.pageParams, nextPageParam];
|
|
1763
|
+
if (nextCursor !== void 0) {
|
|
1764
|
+
updatedParams.push(nextCursor);
|
|
1765
|
+
}
|
|
1766
|
+
return {
|
|
1767
|
+
pages: [...currentData.pages, newPage],
|
|
1768
|
+
pageParams: updatedParams
|
|
1769
|
+
};
|
|
1770
|
+
}, {
|
|
1771
|
+
fetchDirection: "next",
|
|
1772
|
+
retry
|
|
1773
|
+
});
|
|
1774
|
+
client.set(infiniteQueryKey, updatedData, {
|
|
1357
1775
|
staleTime: staleTimeRef.current,
|
|
1358
1776
|
cacheTime: cacheTimeRef.current
|
|
1359
1777
|
});
|
|
1360
|
-
|
|
1778
|
+
} catch (err) {
|
|
1779
|
+
getLogger().error("Fetch next page failed", err);
|
|
1361
1780
|
}
|
|
1362
|
-
}, [
|
|
1781
|
+
}, [hasNextPage, isFetching, data, client, JSON.stringify(infiniteQueryKey)]);
|
|
1363
1782
|
const fetchPreviousPage = useCallback5(async () => {
|
|
1364
|
-
if (!
|
|
1783
|
+
if (!hasPreviousPage || isFetching || !data) return;
|
|
1365
1784
|
const firstPage = data.pages[0];
|
|
1366
|
-
|
|
1367
|
-
const previousPageParam = getPreviousPageParamRef.current(firstPage, data.pages);
|
|
1785
|
+
const previousPageParam = getPreviousPageParamRef.current?.(firstPage, data.pages);
|
|
1368
1786
|
if (previousPageParam === void 0) return;
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
clientRef.current.set(infiniteQueryKeyRef.current, updatedData, {
|
|
1787
|
+
try {
|
|
1788
|
+
const updatedData = await client.fetch(infiniteQueryKey, async () => {
|
|
1789
|
+
const newPage = await queryFnRef.current({ pageParam: previousPageParam });
|
|
1790
|
+
const currentEntry = client.getSignal(infiniteQueryKey).get();
|
|
1791
|
+
const currentData = currentEntry?.data;
|
|
1792
|
+
if (!currentData) throw new Error("Infinite query data missing during fetchPreviousPage");
|
|
1793
|
+
return {
|
|
1794
|
+
pages: [newPage, ...currentData.pages],
|
|
1795
|
+
pageParams: [previousPageParam, ...currentData.pageParams]
|
|
1796
|
+
};
|
|
1797
|
+
}, { fetchDirection: "previous", retry });
|
|
1798
|
+
client.set(infiniteQueryKey, updatedData, {
|
|
1382
1799
|
staleTime: staleTimeRef.current,
|
|
1383
1800
|
cacheTime: cacheTimeRef.current
|
|
1384
1801
|
});
|
|
1385
|
-
|
|
1802
|
+
} catch (err) {
|
|
1803
|
+
getLogger().error("Fetch previous page failed", err);
|
|
1386
1804
|
}
|
|
1387
|
-
}, [
|
|
1805
|
+
}, [hasPreviousPage, isFetching, data, client, JSON.stringify(infiniteQueryKey)]);
|
|
1388
1806
|
const refetch = useCallback5(async () => {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
}, []);
|
|
1807
|
+
client.invalidate(infiniteQueryKey);
|
|
1808
|
+
}, [client, JSON.stringify(infiniteQueryKey)]);
|
|
1392
1809
|
return {
|
|
1393
1810
|
data,
|
|
1394
1811
|
fetchNextPage,
|
|
1395
1812
|
fetchPreviousPage,
|
|
1396
|
-
hasNextPage
|
|
1397
|
-
hasPreviousPage
|
|
1398
|
-
isFetching
|
|
1399
|
-
isFetchingNextPage
|
|
1400
|
-
isFetchingPreviousPage
|
|
1401
|
-
isLoading
|
|
1402
|
-
isError
|
|
1403
|
-
error
|
|
1813
|
+
hasNextPage,
|
|
1814
|
+
hasPreviousPage,
|
|
1815
|
+
isFetching,
|
|
1816
|
+
isFetchingNextPage,
|
|
1817
|
+
isFetchingPreviousPage,
|
|
1818
|
+
isLoading,
|
|
1819
|
+
isError,
|
|
1820
|
+
error,
|
|
1404
1821
|
refetch
|
|
1405
1822
|
};
|
|
1406
1823
|
}
|
|
1407
1824
|
|
|
1408
|
-
// src/addon/query/
|
|
1409
|
-
import {
|
|
1825
|
+
// src/addon/query/HydrationBoundary.tsx
|
|
1826
|
+
import { useRef as useRef5 } from "react";
|
|
1827
|
+
|
|
1828
|
+
// src/addon/query/hydration.ts
|
|
1829
|
+
function dehydrate(client) {
|
|
1830
|
+
const queries = [];
|
|
1831
|
+
const snapshot = client.getSnapshot();
|
|
1832
|
+
snapshot.forEach((signal2, hash) => {
|
|
1833
|
+
const state = signal2.get();
|
|
1834
|
+
if (state) {
|
|
1835
|
+
queries.push({
|
|
1836
|
+
queryKey: state.key,
|
|
1837
|
+
queryHash: hash,
|
|
1838
|
+
state
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
return { queries };
|
|
1843
|
+
}
|
|
1844
|
+
function hydrate(client, state) {
|
|
1845
|
+
if (!state || !state.queries) return;
|
|
1846
|
+
state.queries.forEach(({ queryKey, state: queryState }) => {
|
|
1847
|
+
const key = queryKey;
|
|
1848
|
+
client.restore(queryKey, queryState);
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1410
1851
|
|
|
1411
|
-
// src/addon/query/
|
|
1412
|
-
import {
|
|
1413
|
-
function
|
|
1852
|
+
// src/addon/query/HydrationBoundary.tsx
|
|
1853
|
+
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
1854
|
+
function HydrationBoundary({ state, children }) {
|
|
1414
1855
|
const client = useQueryClient();
|
|
1415
|
-
const
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
}, [client]);
|
|
1422
|
-
return cache;
|
|
1856
|
+
const hydratedRef = useRef5(false);
|
|
1857
|
+
if (state && !hydratedRef.current) {
|
|
1858
|
+
hydrate(client, state);
|
|
1859
|
+
hydratedRef.current = true;
|
|
1860
|
+
}
|
|
1861
|
+
return /* @__PURE__ */ jsx2(Fragment, { children });
|
|
1423
1862
|
}
|
|
1424
1863
|
|
|
1425
|
-
// src/addon/query/
|
|
1426
|
-
|
|
1427
|
-
function QuantumDevTools() {
|
|
1428
|
-
const [isOpen, setIsOpen] = useState5(false);
|
|
1429
|
-
const [isMinimized, setIsMinimized] = useState5(false);
|
|
1430
|
-
const [height, setHeight] = useState5(450);
|
|
1431
|
-
const [filter, setFilter] = useState5("");
|
|
1432
|
-
const cache = useQueryCache();
|
|
1864
|
+
// src/addon/query/useSuspenseQuery.ts
|
|
1865
|
+
function useSuspenseQuery(options) {
|
|
1433
1866
|
const client = useQueryClient();
|
|
1434
|
-
const
|
|
1435
|
-
const
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
bottom: "20px",
|
|
1471
|
-
right: "20px",
|
|
1472
|
-
background: "#111",
|
|
1473
|
-
color: "#b0fb5d",
|
|
1474
|
-
// Quantum Green
|
|
1475
|
-
border: "1px solid #333",
|
|
1476
|
-
borderRadius: "50%",
|
|
1477
|
-
width: "48px",
|
|
1478
|
-
height: "48px",
|
|
1479
|
-
cursor: "pointer",
|
|
1480
|
-
zIndex: 9999,
|
|
1481
|
-
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
1482
|
-
fontSize: "20px",
|
|
1483
|
-
display: "flex",
|
|
1484
|
-
alignItems: "center",
|
|
1485
|
-
justifyContent: "center",
|
|
1486
|
-
transition: "transform 0.2s",
|
|
1487
|
-
fontFamily: "monospace"
|
|
1488
|
-
},
|
|
1489
|
-
onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.1)",
|
|
1490
|
-
onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
|
|
1491
|
-
title: "Open Quantum DevTools",
|
|
1492
|
-
children: "\u26A1\uFE0F"
|
|
1493
|
-
}
|
|
1494
|
-
);
|
|
1495
|
-
}
|
|
1496
|
-
if (isMinimized) {
|
|
1497
|
-
return /* @__PURE__ */ jsxs("div", { style: {
|
|
1498
|
-
position: "fixed",
|
|
1499
|
-
bottom: "20px",
|
|
1500
|
-
right: "20px",
|
|
1501
|
-
background: "#111",
|
|
1502
|
-
border: "1px solid #333",
|
|
1503
|
-
borderRadius: "8px",
|
|
1504
|
-
padding: "8px 12px",
|
|
1505
|
-
zIndex: 9999,
|
|
1506
|
-
display: "flex",
|
|
1507
|
-
alignItems: "center",
|
|
1508
|
-
gap: "10px",
|
|
1509
|
-
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
1510
|
-
fontFamily: "monospace",
|
|
1511
|
-
color: "#e0e0e0",
|
|
1512
|
-
cursor: "pointer"
|
|
1513
|
-
}, onClick: () => setIsMinimized(false), children: [
|
|
1514
|
-
/* @__PURE__ */ jsx2("span", { style: { color: "#b0fb5d" }, children: "\u26A1\uFE0F" }),
|
|
1515
|
-
/* @__PURE__ */ jsx2("span", { style: { fontSize: "12px" }, children: "DevTools" }),
|
|
1516
|
-
/* @__PURE__ */ jsxs("span", { style: {
|
|
1517
|
-
background: "#333",
|
|
1518
|
-
padding: "2px 6px",
|
|
1519
|
-
borderRadius: "4px",
|
|
1520
|
-
fontSize: "10px"
|
|
1521
|
-
}, children: [
|
|
1522
|
-
entries.length,
|
|
1523
|
-
" queries"
|
|
1524
|
-
] })
|
|
1525
|
-
] });
|
|
1526
|
-
}
|
|
1527
|
-
return /* @__PURE__ */ jsxs(
|
|
1528
|
-
"div",
|
|
1529
|
-
{
|
|
1530
|
-
ref: containerRef,
|
|
1531
|
-
style: {
|
|
1532
|
-
position: "fixed",
|
|
1533
|
-
bottom: 0,
|
|
1534
|
-
right: 0,
|
|
1535
|
-
width: "100%",
|
|
1536
|
-
height: `${height}px`,
|
|
1537
|
-
background: "#0a0a0a",
|
|
1538
|
-
color: "#e0e0e0",
|
|
1539
|
-
borderTopLeftRadius: "12px",
|
|
1540
|
-
borderTopRightRadius: "12px",
|
|
1541
|
-
boxShadow: "0 -10px 40px rgba(0,0,0,0.5)",
|
|
1542
|
-
zIndex: 9999,
|
|
1543
|
-
display: "flex",
|
|
1544
|
-
flexDirection: "column",
|
|
1545
|
-
fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
|
|
1546
|
-
fontSize: "13px",
|
|
1547
|
-
borderTop: "1px solid #333"
|
|
1548
|
-
},
|
|
1549
|
-
children: [
|
|
1550
|
-
/* @__PURE__ */ jsx2(
|
|
1551
|
-
"div",
|
|
1552
|
-
{
|
|
1553
|
-
onMouseDown: () => {
|
|
1554
|
-
isResizingRef.current = true;
|
|
1555
|
-
document.body.style.cursor = "ns-resize";
|
|
1556
|
-
},
|
|
1557
|
-
style: {
|
|
1558
|
-
height: "6px",
|
|
1559
|
-
width: "100%",
|
|
1560
|
-
cursor: "ns-resize",
|
|
1561
|
-
position: "absolute",
|
|
1562
|
-
top: "-3px",
|
|
1563
|
-
left: 0,
|
|
1564
|
-
zIndex: 10
|
|
1565
|
-
// debugging color: background: 'red', opacity: 0.2
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
),
|
|
1569
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
1570
|
-
padding: "12px 16px",
|
|
1571
|
-
borderBottom: "1px solid #222",
|
|
1572
|
-
display: "flex",
|
|
1573
|
-
justifyContent: "space-between",
|
|
1574
|
-
alignItems: "center",
|
|
1575
|
-
background: "#111",
|
|
1576
|
-
borderTopLeftRadius: "12px",
|
|
1577
|
-
borderTopRightRadius: "12px",
|
|
1578
|
-
userSelect: "none"
|
|
1579
|
-
}, children: [
|
|
1580
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
1581
|
-
/* @__PURE__ */ jsx2("span", { style: { color: "#b0fb5d", fontSize: "16px" }, children: "\u26A1\uFE0F" }),
|
|
1582
|
-
/* @__PURE__ */ jsx2("span", { style: { fontWeight: 600, letterSpacing: "-0.5px" }, children: "Quantum DevTools" }),
|
|
1583
|
-
/* @__PURE__ */ jsx2("span", { style: {
|
|
1584
|
-
background: "#222",
|
|
1585
|
-
padding: "2px 6px",
|
|
1586
|
-
borderRadius: "4px",
|
|
1587
|
-
fontSize: "10px",
|
|
1588
|
-
color: "#666"
|
|
1589
|
-
}, children: "v1.2.3" })
|
|
1590
|
-
] }),
|
|
1591
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
1592
|
-
/* @__PURE__ */ jsx2(
|
|
1593
|
-
"button",
|
|
1594
|
-
{
|
|
1595
|
-
onClick: () => setIsMinimized(true),
|
|
1596
|
-
title: "Minimize",
|
|
1597
|
-
style: {
|
|
1598
|
-
background: "transparent",
|
|
1599
|
-
border: "none",
|
|
1600
|
-
color: "#666",
|
|
1601
|
-
cursor: "pointer",
|
|
1602
|
-
fontSize: "16px",
|
|
1603
|
-
padding: "4px",
|
|
1604
|
-
lineHeight: 1
|
|
1605
|
-
},
|
|
1606
|
-
children: "_"
|
|
1607
|
-
}
|
|
1608
|
-
),
|
|
1609
|
-
/* @__PURE__ */ jsx2(
|
|
1610
|
-
"button",
|
|
1611
|
-
{
|
|
1612
|
-
onClick: () => setIsOpen(false),
|
|
1613
|
-
title: "Close",
|
|
1614
|
-
style: {
|
|
1615
|
-
background: "transparent",
|
|
1616
|
-
border: "none",
|
|
1617
|
-
color: "#666",
|
|
1618
|
-
cursor: "pointer",
|
|
1619
|
-
fontSize: "18px",
|
|
1620
|
-
padding: "4px",
|
|
1621
|
-
lineHeight: 1
|
|
1622
|
-
},
|
|
1623
|
-
children: "\xD7"
|
|
1624
|
-
}
|
|
1625
|
-
)
|
|
1626
|
-
] })
|
|
1627
|
-
] }),
|
|
1628
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
1629
|
-
padding: "8px 16px",
|
|
1630
|
-
borderBottom: "1px solid #222",
|
|
1631
|
-
background: "#0f0f0f",
|
|
1632
|
-
display: "flex",
|
|
1633
|
-
gap: "12px"
|
|
1634
|
-
}, children: [
|
|
1635
|
-
/* @__PURE__ */ jsx2(
|
|
1636
|
-
"input",
|
|
1637
|
-
{
|
|
1638
|
-
type: "text",
|
|
1639
|
-
placeholder: "Filter queries...",
|
|
1640
|
-
value: filter,
|
|
1641
|
-
onChange: (e) => setFilter(e.target.value),
|
|
1642
|
-
style: {
|
|
1643
|
-
background: "#1a1a1a",
|
|
1644
|
-
border: "1px solid #333",
|
|
1645
|
-
color: "#fff",
|
|
1646
|
-
padding: "6px 10px",
|
|
1647
|
-
borderRadius: "4px",
|
|
1648
|
-
flex: 1,
|
|
1649
|
-
fontSize: "12px",
|
|
1650
|
-
outline: "none"
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
),
|
|
1654
|
-
/* @__PURE__ */ jsx2(
|
|
1655
|
-
"button",
|
|
1656
|
-
{
|
|
1657
|
-
onClick: () => client.invalidateAll(),
|
|
1658
|
-
title: "Invalidate All Queries",
|
|
1659
|
-
style: {
|
|
1660
|
-
background: "#222",
|
|
1661
|
-
border: "1px solid #333",
|
|
1662
|
-
color: "#d69e2e",
|
|
1663
|
-
borderRadius: "4px",
|
|
1664
|
-
padding: "0 12px",
|
|
1665
|
-
cursor: "pointer",
|
|
1666
|
-
fontSize: "12px",
|
|
1667
|
-
fontWeight: 500
|
|
1668
|
-
},
|
|
1669
|
-
children: "\u21BB Invalidate All"
|
|
1670
|
-
}
|
|
1671
|
-
)
|
|
1672
|
-
] }),
|
|
1673
|
-
/* @__PURE__ */ jsx2("div", { style: {
|
|
1674
|
-
flex: 1,
|
|
1675
|
-
overflowY: "auto",
|
|
1676
|
-
padding: "8px",
|
|
1677
|
-
display: "flex",
|
|
1678
|
-
flexDirection: "column",
|
|
1679
|
-
gap: "8px",
|
|
1680
|
-
background: "#050505"
|
|
1681
|
-
}, children: entries.length === 0 ? /* @__PURE__ */ jsxs("div", { style: {
|
|
1682
|
-
padding: "40px",
|
|
1683
|
-
textAlign: "center",
|
|
1684
|
-
color: "#444",
|
|
1685
|
-
fontStyle: "italic"
|
|
1686
|
-
}, children: [
|
|
1687
|
-
"No active queries in cache.",
|
|
1688
|
-
/* @__PURE__ */ jsx2("br", {}),
|
|
1689
|
-
/* @__PURE__ */ jsx2("span", { style: { fontSize: "11px", opacity: 0.7 }, children: "(Note: Only `useQuery` calls appear here. Raw `api.get` calls are not cached globally.)" })
|
|
1690
|
-
] }) : filteredEntries.map(([keyHash, entry]) => /* @__PURE__ */ jsx2(
|
|
1691
|
-
QueryItem,
|
|
1692
|
-
{
|
|
1693
|
-
entry,
|
|
1694
|
-
client,
|
|
1695
|
-
isStale: client.isStale(entry.key)
|
|
1696
|
-
},
|
|
1697
|
-
keyHash
|
|
1698
|
-
)) })
|
|
1699
|
-
]
|
|
1867
|
+
const signal2 = client.getSignal(options.queryKey);
|
|
1868
|
+
const entry = signal2.get();
|
|
1869
|
+
const shouldSuspend = !entry || entry.status === "pending" && entry.data === void 0;
|
|
1870
|
+
if (shouldSuspend) {
|
|
1871
|
+
const fetchPromise = client.fetch(
|
|
1872
|
+
options.queryKey,
|
|
1873
|
+
// @ts-ignore
|
|
1874
|
+
(ctx) => options.queryFn(ctx),
|
|
1875
|
+
{ signal: void 0 }
|
|
1876
|
+
).then((data) => {
|
|
1877
|
+
client.set(options.queryKey, data);
|
|
1878
|
+
return data;
|
|
1879
|
+
});
|
|
1880
|
+
throw fetchPromise;
|
|
1881
|
+
}
|
|
1882
|
+
if (entry?.status === "error") {
|
|
1883
|
+
throw entry.error;
|
|
1884
|
+
}
|
|
1885
|
+
const query = useQuery(options);
|
|
1886
|
+
return {
|
|
1887
|
+
...query,
|
|
1888
|
+
data: query.data
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
// src/core/bridge.ts
|
|
1893
|
+
function fromSignal(signal2) {
|
|
1894
|
+
const initial = signal2.get();
|
|
1895
|
+
const isObject = typeof initial === "object" && initial !== null;
|
|
1896
|
+
const target = isObject ? initial : { value: initial };
|
|
1897
|
+
const proxy = createState(target);
|
|
1898
|
+
signal2.subscribe((newValue) => {
|
|
1899
|
+
if (typeof newValue === "object" && newValue !== null) {
|
|
1900
|
+
Object.assign(proxy, newValue);
|
|
1901
|
+
} else {
|
|
1902
|
+
proxy.value = newValue;
|
|
1700
1903
|
}
|
|
1701
|
-
);
|
|
1904
|
+
});
|
|
1905
|
+
return proxy;
|
|
1702
1906
|
}
|
|
1703
|
-
function
|
|
1704
|
-
const
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
minWidth: "10px"
|
|
1730
|
-
}, children: isStale ? "\u2022" : "\u2022" }),
|
|
1731
|
-
/* @__PURE__ */ jsxs("span", { style: {
|
|
1732
|
-
color: "#e0e0e0",
|
|
1733
|
-
fontWeight: 500,
|
|
1734
|
-
whiteSpace: "nowrap",
|
|
1735
|
-
overflow: "hidden",
|
|
1736
|
-
textOverflow: "ellipsis"
|
|
1737
|
-
}, children: [
|
|
1738
|
-
"['",
|
|
1739
|
-
entry.key.join("', '"),
|
|
1740
|
-
"']"
|
|
1741
|
-
] })
|
|
1742
|
-
] }),
|
|
1743
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
1744
|
-
/* @__PURE__ */ jsx2("span", { style: {
|
|
1745
|
-
fontSize: "10px",
|
|
1746
|
-
padding: "2px 6px",
|
|
1747
|
-
borderRadius: "3px",
|
|
1748
|
-
background: isStale ? "rgba(214, 158, 46, 0.15)" : "rgba(176, 251, 93, 0.15)",
|
|
1749
|
-
color: isStale ? "#d69e2e" : "#b0fb5d",
|
|
1750
|
-
border: `1px solid ${isStale ? "rgba(214, 158, 46, 0.3)" : "rgba(176, 251, 93, 0.3)"}`
|
|
1751
|
-
}, children: isStale ? "STALE" : "FRESH" }),
|
|
1752
|
-
/* @__PURE__ */ jsx2("span", { style: { color: "#666", fontSize: "10px" }, children: expanded ? "\u25BC" : "\u25B6" })
|
|
1753
|
-
] })
|
|
1754
|
-
]
|
|
1755
|
-
}
|
|
1756
|
-
),
|
|
1757
|
-
expanded && /* @__PURE__ */ jsxs("div", { style: {
|
|
1758
|
-
padding: "10px",
|
|
1759
|
-
borderTop: "1px solid #222",
|
|
1760
|
-
background: "#0a0a0a"
|
|
1761
|
-
}, children: [
|
|
1762
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
1763
|
-
display: "flex",
|
|
1764
|
-
gap: "8px",
|
|
1765
|
-
marginBottom: "10px",
|
|
1766
|
-
borderBottom: "1px solid #222",
|
|
1767
|
-
paddingBottom: "8px"
|
|
1768
|
-
}, children: [
|
|
1769
|
-
/* @__PURE__ */ jsx2(
|
|
1770
|
-
"button",
|
|
1771
|
-
{
|
|
1772
|
-
onClick: (e) => {
|
|
1773
|
-
e.stopPropagation();
|
|
1774
|
-
client.invalidate(entry.key);
|
|
1775
|
-
},
|
|
1776
|
-
style: {
|
|
1777
|
-
background: "#222",
|
|
1778
|
-
border: "1px solid #333",
|
|
1779
|
-
color: "#d69e2e",
|
|
1780
|
-
padding: "4px 10px",
|
|
1781
|
-
borderRadius: "4px",
|
|
1782
|
-
cursor: "pointer",
|
|
1783
|
-
fontSize: "11px"
|
|
1784
|
-
},
|
|
1785
|
-
children: "Invalidate"
|
|
1786
|
-
}
|
|
1787
|
-
),
|
|
1788
|
-
/* @__PURE__ */ jsx2(
|
|
1789
|
-
"button",
|
|
1790
|
-
{
|
|
1791
|
-
onClick: (e) => {
|
|
1792
|
-
e.stopPropagation();
|
|
1793
|
-
client.remove(entry.key);
|
|
1794
|
-
},
|
|
1795
|
-
style: {
|
|
1796
|
-
background: "#222",
|
|
1797
|
-
border: "1px solid #333",
|
|
1798
|
-
color: "#ff4d4f",
|
|
1799
|
-
padding: "4px 10px",
|
|
1800
|
-
borderRadius: "4px",
|
|
1801
|
-
cursor: "pointer",
|
|
1802
|
-
fontSize: "11px"
|
|
1803
|
-
},
|
|
1804
|
-
children: "Remove"
|
|
1805
|
-
}
|
|
1806
|
-
)
|
|
1807
|
-
] }),
|
|
1808
|
-
/* @__PURE__ */ jsx2("div", { style: { position: "relative" }, children: /* @__PURE__ */ jsx2("pre", { style: {
|
|
1809
|
-
margin: 0,
|
|
1810
|
-
fontSize: "11px",
|
|
1811
|
-
color: "#a0a0a0",
|
|
1812
|
-
overflowX: "auto",
|
|
1813
|
-
fontFamily: "monospace"
|
|
1814
|
-
}, children: JSON.stringify(entry.data, null, 2) }) }),
|
|
1815
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
1816
|
-
marginTop: "8px",
|
|
1817
|
-
fontSize: "10px",
|
|
1818
|
-
color: "#444",
|
|
1819
|
-
textAlign: "right"
|
|
1820
|
-
}, children: [
|
|
1821
|
-
"Updated: ",
|
|
1822
|
-
new Date(entry.updatedAt).toLocaleTimeString()
|
|
1823
|
-
] })
|
|
1824
|
-
] })
|
|
1825
|
-
] });
|
|
1907
|
+
function toSignal(selector) {
|
|
1908
|
+
const s = createSignal(void 0);
|
|
1909
|
+
let isComputing = false;
|
|
1910
|
+
const onDependencyChange = () => {
|
|
1911
|
+
if (isComputing) return;
|
|
1912
|
+
run();
|
|
1913
|
+
};
|
|
1914
|
+
const run = () => {
|
|
1915
|
+
isComputing = true;
|
|
1916
|
+
setActiveListener(onDependencyChange);
|
|
1917
|
+
try {
|
|
1918
|
+
const value = selector();
|
|
1919
|
+
s.set(value);
|
|
1920
|
+
} finally {
|
|
1921
|
+
setActiveListener(null);
|
|
1922
|
+
isComputing = false;
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
run();
|
|
1926
|
+
return {
|
|
1927
|
+
get: s.get,
|
|
1928
|
+
set: () => {
|
|
1929
|
+
throw new Error("Cannot set a read-only bridge signal");
|
|
1930
|
+
},
|
|
1931
|
+
subscribe: s.subscribe
|
|
1932
|
+
};
|
|
1826
1933
|
}
|
|
1827
1934
|
export {
|
|
1828
|
-
|
|
1935
|
+
HydrationBoundary,
|
|
1829
1936
|
QueryCache,
|
|
1830
1937
|
QueryClientProvider,
|
|
1831
1938
|
computed,
|
|
1832
1939
|
createHttpClient,
|
|
1833
1940
|
createState,
|
|
1834
1941
|
defineModel,
|
|
1942
|
+
dehydrate,
|
|
1835
1943
|
enableDevTools,
|
|
1944
|
+
fromSignal,
|
|
1836
1945
|
getPromiseState,
|
|
1837
1946
|
handlePromise,
|
|
1947
|
+
hydrate,
|
|
1838
1948
|
isPromise,
|
|
1839
|
-
optimisticHelpers,
|
|
1840
|
-
queryCache,
|
|
1841
1949
|
scheduleUpdate,
|
|
1842
1950
|
subscribe,
|
|
1951
|
+
toSignal,
|
|
1843
1952
|
unwrapPromise,
|
|
1844
1953
|
useInfiniteQuery,
|
|
1845
1954
|
useMutation,
|
|
1846
1955
|
usePaginatedQuery,
|
|
1847
1956
|
useQuery,
|
|
1848
|
-
useQueryCache,
|
|
1849
1957
|
useQueryClient,
|
|
1850
|
-
useStore
|
|
1958
|
+
useStore,
|
|
1959
|
+
useSuspenseQuery
|
|
1851
1960
|
};
|