reactjrx 1.34.0 → 1.40.0
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 +1047 -248
- package/dist/index.d.ts +6 -4
- package/dist/index.js +1049 -250
- package/dist/lib/binding/useObserve.d.ts +2 -2
- package/dist/lib/logger.d.ts +48 -0
- package/dist/lib/queries/client/cache/cacheClient.d.ts +12 -0
- package/dist/lib/queries/client/cache/invalidateCache.d.ts +5 -0
- package/dist/lib/queries/client/cache/logger.d.ts +24 -0
- package/dist/lib/queries/client/cache/registerResultInCache.d.ts +8 -0
- package/dist/lib/queries/client/createClient.d.ts +73 -0
- package/dist/lib/queries/client/deduplication/deduplicate.d.ts +3 -0
- package/dist/lib/queries/client/fetch/mapWithComplete.d.ts +4 -0
- package/dist/lib/queries/client/fetch/notifyQueryResult.d.ts +3 -0
- package/dist/lib/queries/client/fetch/queryFetch.d.ts +12 -0
- package/dist/lib/queries/client/invalidation/invalidationClient.d.ts +12 -0
- package/dist/lib/queries/client/invalidation/logger.d.ts +24 -0
- package/dist/lib/queries/client/invalidation/markAsStale.d.ts +8 -0
- package/dist/lib/queries/client/keys/compareKeys.d.ts +4 -0
- package/dist/lib/queries/client/keys/serializeKey.d.ts +3 -0
- package/dist/lib/queries/client/keys/types.d.ts +10 -0
- package/dist/lib/queries/client/operators.d.ts +4 -0
- package/dist/lib/queries/client/refetch/client.d.ts +18 -0
- package/dist/lib/queries/client/store/createQueryStore.d.ts +55 -0
- package/dist/lib/queries/client/store/debugger.d.ts +3 -0
- package/dist/lib/queries/client/store/garbageCache.d.ts +5 -0
- package/dist/lib/queries/client/store/initializeQueryInStore.d.ts +8 -0
- package/dist/lib/queries/client/store/mapStoreQueryToRunnerOptions.d.ts +4 -0
- package/dist/lib/queries/client/store/queryListener.d.ts +3 -0
- package/dist/lib/queries/client/store/updateStoreWithQuery.d.ts +14 -0
- package/dist/lib/queries/client/triggers.d.ts +17 -0
- package/dist/lib/queries/client/types.d.ts +48 -0
- package/dist/lib/queries/react/Provider.d.ts +12 -0
- package/dist/lib/queries/react/helpers.d.ts +27 -0
- package/dist/lib/queries/react/triggers/activityTrigger.d.ts +9 -0
- package/dist/lib/queries/react/triggers/networkTrigger.d.ts +7 -0
- package/dist/lib/queries/react/types.d.ts +13 -0
- package/dist/lib/queries/react/useQuery.d.ts +6 -0
- package/dist/lib/state/useSignal.d.ts +1 -1
- package/dist/lib/state/useSignalValue.d.ts +1 -1
- package/dist/lib/utils/difference.d.ts +1 -0
- package/package.json +1 -1
- package/dist/lib/queries/Provider.d.ts +0 -23
- package/dist/lib/queries/cache/useCreateCacheStore.d.ts +0 -9
- package/dist/lib/queries/deduplication/deduplicate.d.ts +0 -3
- package/dist/lib/queries/deduplication/useQueryStore.d.ts +0 -3
- package/dist/lib/queries/invalidation/autoRefetch.d.ts +0 -4
- package/dist/lib/queries/keys/serializeKey.d.ts +0 -1
- package/dist/lib/queries/keys/withKeyComparison.d.ts +0 -16
- package/dist/lib/queries/operators.d.ts +0 -2
- package/dist/lib/queries/querx.d.ts +0 -3
- package/dist/lib/queries/types.d.ts +0 -10
- package/dist/lib/queries/useQuery.d.ts +0 -12
- /package/dist/lib/queries/{useAsyncQuery.d.ts → react/useAsyncQuery.d.ts} +0 -0
- /package/dist/lib/queries/{useSubscribeEffect.d.ts → react/useSubscribeEffect.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useRef, useMemo, useCallback, useSyncExternalStore, useEffect, createContext, memo, useContext
|
|
2
|
-
import { distinctUntilChanged, tap, finalize, catchError, EMPTY, Subject, identity, BehaviorSubject, of, zip, from, map, merge, throttleTime, switchMap, defer, iif, timer, throwError, take, startWith, combineLatest, first, takeUntil, filter, concatMap as concatMap$1, mergeMap,
|
|
1
|
+
import { useRef, useMemo, useCallback, useSyncExternalStore, useEffect, createContext, memo, useContext } from "react";
|
|
2
|
+
import { distinctUntilChanged, tap, finalize, catchError, EMPTY, Subject, identity, BehaviorSubject, of, zip, from, map, merge, throttleTime, switchMap, defer, iif, timer, throwError, scan, take, startWith, combineLatest, first, takeUntil, filter, concatMap as concatMap$1, mergeMap, fromEvent, skip, withLatestFrom, retry, shareReplay, endWith, delay, share, pairwise, NEVER, takeWhile } from "rxjs";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { retryWhen, concatMap, tap as tap$1 } from "rxjs/operators";
|
|
5
5
|
const useLiveRef = (value) => {
|
|
@@ -145,8 +145,8 @@ function trigger(mapper = identity) {
|
|
|
145
145
|
}
|
|
146
146
|
const SIGNAL_RESET = Symbol("SIGNAL_RESET");
|
|
147
147
|
function signal(options) {
|
|
148
|
-
const { default:
|
|
149
|
-
const subject = new BehaviorSubject(
|
|
148
|
+
const { default: defaultValue2 } = options ?? {};
|
|
149
|
+
const subject = new BehaviorSubject(defaultValue2);
|
|
150
150
|
const setValue = (arg) => {
|
|
151
151
|
if (arg === subject.getValue())
|
|
152
152
|
return;
|
|
@@ -158,7 +158,7 @@ function signal(options) {
|
|
|
158
158
|
return;
|
|
159
159
|
}
|
|
160
160
|
if (arg === SIGNAL_RESET) {
|
|
161
|
-
subject.next(
|
|
161
|
+
subject.next(defaultValue2 ?? void 0);
|
|
162
162
|
return;
|
|
163
163
|
}
|
|
164
164
|
subject.next(arg);
|
|
@@ -409,15 +409,6 @@ function retryBackoff(config) {
|
|
|
409
409
|
);
|
|
410
410
|
});
|
|
411
411
|
}
|
|
412
|
-
const retryFromOptions = (options) => retryBackoff({
|
|
413
|
-
initialInterval: 100,
|
|
414
|
-
...typeof options.retry === "function" ? {
|
|
415
|
-
shouldRetry: options.retry
|
|
416
|
-
} : {
|
|
417
|
-
maxRetries: options.retry === false ? 0 : options.retry ?? 3
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
const querx = (options) => (source) => source.pipe(retryFromOptions(options));
|
|
421
412
|
const useBehaviorSubject = (state) => {
|
|
422
413
|
const subject = useConstant(() => new BehaviorSubject(state));
|
|
423
414
|
const completed = useRef(false);
|
|
@@ -457,6 +448,31 @@ function shallowEqual(objA, objB) {
|
|
|
457
448
|
}
|
|
458
449
|
return true;
|
|
459
450
|
}
|
|
451
|
+
const retryOnError = (options) => retryBackoff({
|
|
452
|
+
initialInterval: 100,
|
|
453
|
+
...typeof options.retry === "function" ? {
|
|
454
|
+
shouldRetry: options.retry
|
|
455
|
+
} : {
|
|
456
|
+
maxRetries: options.retry === false ? 0 : options.retry ?? 3
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
const mergeResults = (stream$) => stream$.pipe(
|
|
460
|
+
scan(
|
|
461
|
+
(acc, current) => {
|
|
462
|
+
return {
|
|
463
|
+
...acc,
|
|
464
|
+
...current
|
|
465
|
+
};
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
data: void 0,
|
|
469
|
+
error: void 0,
|
|
470
|
+
fetchStatus: "idle",
|
|
471
|
+
status: "loading"
|
|
472
|
+
}
|
|
473
|
+
),
|
|
474
|
+
distinctUntilChanged(shallowEqual)
|
|
475
|
+
);
|
|
460
476
|
function useAsyncQuery(query, mapOperatorOrOptions, options = {}) {
|
|
461
477
|
const queryRef = useLiveRef(query);
|
|
462
478
|
const triggerSubject = useSubject();
|
|
@@ -503,7 +519,7 @@ function useAsyncQuery(query, mapOperatorOrOptions, options = {}) {
|
|
|
503
519
|
}),
|
|
504
520
|
combineLatest([
|
|
505
521
|
defer(() => from(queryRef.current(args))).pipe(
|
|
506
|
-
|
|
522
|
+
retryOnError(optionsRef.current),
|
|
507
523
|
first(),
|
|
508
524
|
map((data) => ({ data, isError: false })),
|
|
509
525
|
catchError((error) => {
|
|
@@ -544,12 +560,12 @@ function useAsyncQuery(query, mapOperatorOrOptions, options = {}) {
|
|
|
544
560
|
})
|
|
545
561
|
)
|
|
546
562
|
).pipe(
|
|
563
|
+
filter((state) => !!state && !!Object.keys(state).length),
|
|
547
564
|
/**
|
|
548
565
|
* @important
|
|
549
566
|
* state update optimization
|
|
550
567
|
*/
|
|
551
|
-
distinctUntilChanged(shallowEqual)
|
|
552
|
-
filter((state) => !!state && !!Object.keys(state).length)
|
|
568
|
+
distinctUntilChanged(shallowEqual)
|
|
553
569
|
).subscribe((state) => {
|
|
554
570
|
data$.current.next({
|
|
555
571
|
...data$.current.getValue(),
|
|
@@ -577,255 +593,168 @@ function useAsyncQuery(query, mapOperatorOrOptions, options = {}) {
|
|
|
577
593
|
}, []);
|
|
578
594
|
return { ...result, isLoading: result.status === "loading", mutate, reset };
|
|
579
595
|
}
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
const cacheStore = useBehaviorSubject({});
|
|
583
|
-
useSubscribe(
|
|
584
|
-
() => cacheStore.current.pipe(
|
|
585
|
-
skip(1),
|
|
586
|
-
tap(() => {
|
|
587
|
-
const store = cacheStore.current.getValue();
|
|
588
|
-
console.log(
|
|
589
|
-
"[cache] update",
|
|
590
|
-
Object.keys(store).reduce((acc, key) => {
|
|
591
|
-
const entry = store[key];
|
|
592
|
-
if (entry != null) {
|
|
593
|
-
acc[key] = entry;
|
|
594
|
-
}
|
|
595
|
-
acc[key]._debug = {
|
|
596
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
597
|
-
// @ts-expect-error
|
|
598
|
-
eol: new Date(store[key].date + store[key].ttl)
|
|
599
|
-
};
|
|
600
|
-
return acc;
|
|
601
|
-
}, {})
|
|
602
|
-
);
|
|
603
|
-
})
|
|
604
|
-
),
|
|
605
|
-
[cacheStore]
|
|
606
|
-
);
|
|
607
|
-
useSubscribe(
|
|
608
|
-
() => interval(1e3).pipe(
|
|
609
|
-
withLatestFrom(cacheStore.current),
|
|
610
|
-
tap(() => {
|
|
611
|
-
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
612
|
-
const store = cacheStore.current.getValue();
|
|
613
|
-
const keys = Object.keys(store);
|
|
614
|
-
const validKeys = keys.filter((key) => {
|
|
615
|
-
const value = store[key];
|
|
616
|
-
if (value != null && value.date + value.ttl > now) {
|
|
617
|
-
return true;
|
|
618
|
-
}
|
|
619
|
-
return false;
|
|
620
|
-
});
|
|
621
|
-
if (validKeys.length === keys.length) {
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
const newStore = validKeys.reduce((acc, key) => {
|
|
625
|
-
const entry = store[key];
|
|
626
|
-
if (entry != null) {
|
|
627
|
-
acc[key] = entry;
|
|
628
|
-
}
|
|
629
|
-
return acc;
|
|
630
|
-
}, {});
|
|
631
|
-
cacheStore.current.next(newStore);
|
|
632
|
-
})
|
|
633
|
-
),
|
|
634
|
-
[cacheStore]
|
|
635
|
-
);
|
|
636
|
-
return cacheStore;
|
|
637
|
-
};
|
|
638
|
-
const useQueryStore = () => {
|
|
639
|
-
const [store] = useState(/* @__PURE__ */ new Map());
|
|
640
|
-
return store;
|
|
641
|
-
};
|
|
642
|
-
const Context = createContext(void 0);
|
|
643
|
-
const Provider = memo(({ children }) => {
|
|
644
|
-
const cacheStore = useCreateCacheStore();
|
|
645
|
-
const queryStore = useQueryStore();
|
|
646
|
-
const value = useMemo(() => ({ cacheStore, queryStore }), []);
|
|
647
|
-
return /* @__PURE__ */ jsx(Context.Provider, { value, children });
|
|
596
|
+
const Context = createContext({
|
|
597
|
+
client: null
|
|
648
598
|
});
|
|
649
|
-
const
|
|
599
|
+
const Provider = memo(
|
|
600
|
+
({
|
|
601
|
+
children,
|
|
602
|
+
client
|
|
603
|
+
}) => {
|
|
604
|
+
const value = useMemo(() => ({ client }), [client]);
|
|
605
|
+
useEffect(
|
|
606
|
+
() => () => {
|
|
607
|
+
client.destroy();
|
|
608
|
+
},
|
|
609
|
+
[client]
|
|
610
|
+
);
|
|
611
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value, children });
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
const useReactJrxProvider = () => {
|
|
650
615
|
const context = useContext(Context);
|
|
616
|
+
if (context === null) {
|
|
617
|
+
throw new Error("You forgot to register the provider");
|
|
618
|
+
}
|
|
651
619
|
return { ...context };
|
|
652
620
|
};
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
621
|
+
const arrayEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
|
|
622
|
+
function isDefined(arg) {
|
|
623
|
+
return arg !== null && arg !== void 0;
|
|
624
|
+
}
|
|
625
|
+
const createActivityTrigger = (params$) => {
|
|
626
|
+
return params$.pipe(
|
|
627
|
+
switchMap(({ options: { refetchOnWindowFocus = true } }) => {
|
|
628
|
+
const shouldRunTrigger = typeof refetchOnWindowFocus === "function" ? refetchOnWindowFocus({}) : refetchOnWindowFocus;
|
|
629
|
+
return shouldRunTrigger !== false ? merge(
|
|
630
|
+
fromEvent(document, "visibilitychange").pipe(
|
|
631
|
+
filter(() => !document.hidden),
|
|
632
|
+
map(() => ({ ignoreStale: shouldRunTrigger === "always" }))
|
|
633
|
+
),
|
|
634
|
+
fromEvent(window, "focus").pipe(
|
|
635
|
+
map(() => ({ ignoreStale: shouldRunTrigger === "always" }))
|
|
636
|
+
)
|
|
637
|
+
) : EMPTY;
|
|
669
638
|
})
|
|
670
639
|
);
|
|
671
|
-
if (sourceFromStore == null) {
|
|
672
|
-
queryStore == null ? void 0 : queryStore.set(key, finalSource);
|
|
673
|
-
}
|
|
674
|
-
return finalSource;
|
|
675
640
|
};
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
641
|
+
const createNetworkTrigger = (params$) => {
|
|
642
|
+
return params$.pipe(
|
|
643
|
+
switchMap(({ options: { refetchOnReconnect = true } }) => {
|
|
644
|
+
const shouldRunTrigger = typeof refetchOnReconnect === "function" ? refetchOnReconnect({}) : refetchOnReconnect;
|
|
645
|
+
return shouldRunTrigger !== false ? fromEvent(window, "online").pipe(
|
|
646
|
+
map(() => ({ ignoreStale: shouldRunTrigger === "always" }))
|
|
647
|
+
) : EMPTY;
|
|
682
648
|
})
|
|
683
649
|
);
|
|
684
650
|
};
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
map(([previous, current]) => {
|
|
692
|
-
if (current) {
|
|
693
|
-
if (!previous) {
|
|
694
|
-
return {
|
|
695
|
-
...current,
|
|
696
|
-
previousKey: void 0,
|
|
697
|
-
isUsingDifferentKey: true
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
const serializedKey = serializeKey(current.key);
|
|
701
|
-
const serializedPreviousKey = serializeKey(previous.key);
|
|
702
|
-
return {
|
|
703
|
-
...current,
|
|
704
|
-
previousKey: (previous == null ? void 0 : previous.key) ?? current.key,
|
|
705
|
-
isUsingDifferentKey: serializedPreviousKey !== serializedKey
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
return void 0;
|
|
709
|
-
}),
|
|
710
|
-
filter(isDefined)
|
|
711
|
-
);
|
|
712
|
-
function useQuery(keyOrQuery, queryOrOptionOrNothing, optionsOrNothing) {
|
|
713
|
-
const query = Array.isArray(keyOrQuery) ? queryOrOptionOrNothing : keyOrQuery;
|
|
714
|
-
const options = optionsOrNothing ?? (queryOrOptionOrNothing !== query ? queryOrOptionOrNothing : void 0) ?? {};
|
|
715
|
-
const key = Array.isArray(keyOrQuery) ? keyOrQuery : void 0;
|
|
716
|
-
const params$ = useBehaviorSubject({ key, options, query });
|
|
717
|
-
const refetch$ = useSubject();
|
|
718
|
-
const data$ = useBehaviorSubject({
|
|
719
|
-
data: void 0,
|
|
720
|
-
error: void 0,
|
|
721
|
-
isLoading: true
|
|
722
|
-
});
|
|
723
|
-
const { queryStore } = useProvider();
|
|
651
|
+
const useQueryParams = ({
|
|
652
|
+
queryKey,
|
|
653
|
+
queryFn,
|
|
654
|
+
...options
|
|
655
|
+
}) => {
|
|
656
|
+
const params$ = useBehaviorSubject({ queryKey, options, queryFn });
|
|
724
657
|
useEffect(() => {
|
|
725
658
|
params$.current.next({
|
|
726
|
-
|
|
659
|
+
queryKey,
|
|
727
660
|
options,
|
|
728
|
-
|
|
661
|
+
queryFn
|
|
729
662
|
});
|
|
730
|
-
}, [
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
map(({ enabled = true }) => enabled),
|
|
749
|
-
distinctUntilChanged(),
|
|
750
|
-
share()
|
|
751
|
-
);
|
|
752
|
-
const queryTrigger$ = combineLatest([
|
|
753
|
-
newKeyReceived$,
|
|
754
|
-
enabledOptionChanged$,
|
|
755
|
-
queryAsObservableObjectChanged$.pipe(startWith(void 0)),
|
|
756
|
-
refetch$.current.pipe(startWith(void 0))
|
|
757
|
-
]);
|
|
758
|
-
const disabled$ = enabledOptionChanged$.pipe(
|
|
759
|
-
filter((enabled) => !enabled),
|
|
760
|
-
tap(() => {
|
|
761
|
-
data$.current.next({
|
|
762
|
-
...data$.current.getValue(),
|
|
763
|
-
isLoading: false
|
|
764
|
-
});
|
|
765
|
-
})
|
|
766
|
-
);
|
|
767
|
-
return queryTrigger$.pipe(
|
|
768
|
-
withLatestFrom(options$, newQuery$),
|
|
769
|
-
map(([[key2, enabled], options2, query2]) => ({
|
|
770
|
-
key: key2,
|
|
771
|
-
enabled,
|
|
772
|
-
options: options2,
|
|
773
|
-
query: query2
|
|
774
|
-
})),
|
|
775
|
-
withKeyComparison,
|
|
776
|
-
filter(({ enabled }) => enabled),
|
|
777
|
-
switchMap(({ key: key2, options: options2, isUsingDifferentKey, query: query2 }) => {
|
|
778
|
-
const serializedKey = serializeKey(key2);
|
|
779
|
-
return of(null).pipe(
|
|
780
|
-
tap(() => {
|
|
781
|
-
data$.current.next({
|
|
782
|
-
...data$.current.getValue(),
|
|
783
|
-
data: isUsingDifferentKey ? void 0 : data$.current.getValue().data,
|
|
784
|
-
error: void 0,
|
|
785
|
-
isLoading: true
|
|
786
|
-
});
|
|
787
|
-
}),
|
|
788
|
-
switchMap(() => {
|
|
789
|
-
const query$ = defer(() => {
|
|
790
|
-
const queryOrResponse = typeof query2 === "function" ? query2() : query2;
|
|
791
|
-
return from(queryOrResponse);
|
|
792
|
-
});
|
|
793
|
-
return query$.pipe(
|
|
794
|
-
querx(options2),
|
|
795
|
-
deduplicate(serializedKey, queryStore),
|
|
796
|
-
// key.length > 0 ? withCache(key) : identity,
|
|
797
|
-
map((response) => [response]),
|
|
798
|
-
catchError((error) => {
|
|
799
|
-
return of([void 0, error]);
|
|
800
|
-
}),
|
|
801
|
-
tap(([response, error]) => {
|
|
802
|
-
if (response) {
|
|
803
|
-
if (options2.onSuccess != null)
|
|
804
|
-
options2.onSuccess(response);
|
|
805
|
-
}
|
|
806
|
-
data$.current.next({
|
|
807
|
-
...data$.current.getValue(),
|
|
808
|
-
isLoading: false,
|
|
809
|
-
error,
|
|
810
|
-
data: response
|
|
811
|
-
});
|
|
812
|
-
})
|
|
813
|
-
);
|
|
814
|
-
}),
|
|
815
|
-
autoRefetch(options2),
|
|
816
|
-
takeUntil(disabled$)
|
|
817
|
-
);
|
|
818
|
-
})
|
|
819
|
-
);
|
|
820
|
-
}, []);
|
|
663
|
+
}, [queryKey, options, queryFn]);
|
|
664
|
+
return params$;
|
|
665
|
+
};
|
|
666
|
+
const defaultValue = {
|
|
667
|
+
data: void 0,
|
|
668
|
+
isLoading: true,
|
|
669
|
+
error: void 0,
|
|
670
|
+
status: "loading",
|
|
671
|
+
fetchStatus: "idle"
|
|
672
|
+
};
|
|
673
|
+
function useQuery({
|
|
674
|
+
queryKey,
|
|
675
|
+
queryFn,
|
|
676
|
+
...options
|
|
677
|
+
}) {
|
|
678
|
+
const internalRefresh$ = useSubject();
|
|
679
|
+
const { client } = useReactJrxProvider();
|
|
680
|
+
const params$ = useQueryParams({ queryFn, queryKey, ...options });
|
|
821
681
|
const result = useObserve(
|
|
822
|
-
() =>
|
|
823
|
-
|
|
824
|
-
|
|
682
|
+
() => {
|
|
683
|
+
const key$ = params$.current.pipe(map(({ queryKey: queryKey2 }) => queryKey2 ?? []));
|
|
684
|
+
const initialTrigger$ = of(null);
|
|
685
|
+
const newKeyTrigger$ = key$.pipe(
|
|
686
|
+
distinctUntilChanged(arrayEqual),
|
|
687
|
+
skip(1)
|
|
688
|
+
);
|
|
689
|
+
const isQueryObject = (query) => !!query && typeof query !== "function";
|
|
690
|
+
const newObservableObjectQuery$ = params$.current.pipe(
|
|
691
|
+
map(({ queryFn: queryFn2 }) => queryFn2),
|
|
692
|
+
filter(isQueryObject),
|
|
693
|
+
distinctUntilChanged(shallowEqual),
|
|
694
|
+
isQueryObject(params$.current.getValue().queryFn) ? skip(1) : identity
|
|
695
|
+
);
|
|
696
|
+
const fn$ = params$.current.pipe(
|
|
697
|
+
map(({ queryFn: queryFn2 }) => queryFn2),
|
|
698
|
+
filter(isDefined)
|
|
699
|
+
);
|
|
700
|
+
const options$ = params$.current.pipe(map(({ options: options2 }) => options2));
|
|
701
|
+
const activityRefetch$ = createActivityTrigger(params$.current);
|
|
702
|
+
const networkRefetch$ = createNetworkTrigger(params$.current);
|
|
703
|
+
const newQueryTrigger$ = merge(
|
|
704
|
+
initialTrigger$,
|
|
705
|
+
newKeyTrigger$,
|
|
706
|
+
newObservableObjectQuery$
|
|
707
|
+
);
|
|
708
|
+
const refetch$ = merge(
|
|
709
|
+
internalRefresh$.current.pipe(map(() => ({ ignoreStale: true }))),
|
|
710
|
+
merge(activityRefetch$, networkRefetch$).pipe(throttleTime(500))
|
|
711
|
+
);
|
|
712
|
+
return newQueryTrigger$.pipe(
|
|
713
|
+
withLatestFrom(key$),
|
|
714
|
+
switchMap(([, key]) => {
|
|
715
|
+
const { result$ } = client.query$({
|
|
716
|
+
key,
|
|
717
|
+
fn$,
|
|
718
|
+
options$,
|
|
719
|
+
refetch$
|
|
720
|
+
});
|
|
721
|
+
return result$.pipe(
|
|
722
|
+
scan(
|
|
723
|
+
(previousValue, { data: currentData, ...currentValue }) => ({
|
|
724
|
+
data: void 0,
|
|
725
|
+
...previousValue,
|
|
726
|
+
...currentValue,
|
|
727
|
+
isLoading: currentValue.status === "loading",
|
|
728
|
+
...currentData && {
|
|
729
|
+
data: currentData.result
|
|
730
|
+
}
|
|
731
|
+
}),
|
|
732
|
+
{}
|
|
733
|
+
)
|
|
734
|
+
);
|
|
735
|
+
})
|
|
736
|
+
/**
|
|
737
|
+
* @important
|
|
738
|
+
* We skip the first result as it is comparable to default passed value.
|
|
739
|
+
* This is assuming all query are async and does not return a result right away.
|
|
740
|
+
* This is a design choice.
|
|
741
|
+
*/
|
|
742
|
+
// params$.current.getValue().options.enabled !== false
|
|
743
|
+
// ? skip(1)
|
|
744
|
+
// : identity
|
|
745
|
+
);
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
defaultValue: {
|
|
749
|
+
...defaultValue,
|
|
750
|
+
isLoading: params$.current.getValue().options.enabled !== false
|
|
751
|
+
}
|
|
752
|
+
},
|
|
753
|
+
[client]
|
|
825
754
|
);
|
|
826
|
-
const refetch = useCallback((
|
|
827
|
-
|
|
828
|
-
}, []);
|
|
755
|
+
const refetch = useCallback(() => {
|
|
756
|
+
internalRefresh$.current.next();
|
|
757
|
+
}, [client]);
|
|
829
758
|
return { ...result, refetch };
|
|
830
759
|
}
|
|
831
760
|
function useSubscribeEffect(source, unsafeOptions, deps = []) {
|
|
@@ -848,10 +777,878 @@ function useSubscribeEffect(source, unsafeOptions, deps = []) {
|
|
|
848
777
|
);
|
|
849
778
|
useSubscribe(enhancerMakeObservable, deps);
|
|
850
779
|
}
|
|
780
|
+
const serializeObject = (object) => {
|
|
781
|
+
if (Array.isArray(object)) {
|
|
782
|
+
return object.reduce((acc, value, index) => {
|
|
783
|
+
if (index === object.length - 1)
|
|
784
|
+
return `${acc}${serializeObject(value)}]`;
|
|
785
|
+
return `${acc}${serializeObject(value)},`;
|
|
786
|
+
}, "[");
|
|
787
|
+
}
|
|
788
|
+
if (object === void 0)
|
|
789
|
+
return "";
|
|
790
|
+
return JSON.stringify(object, Object.keys(object).sort());
|
|
791
|
+
};
|
|
792
|
+
const serializeKey = (key) => {
|
|
793
|
+
if (key.length === 0)
|
|
794
|
+
return "[]";
|
|
795
|
+
return serializeObject(key);
|
|
796
|
+
};
|
|
797
|
+
const resetStyle = { backgroundColor: "transparent", color: "inherit" };
|
|
798
|
+
function createLogger(env) {
|
|
799
|
+
const _logger = {
|
|
800
|
+
namespaces: [
|
|
801
|
+
{ name: "@reactjrx", style: { backgroundColor: "#d02f4e", color: "white" } }
|
|
802
|
+
],
|
|
803
|
+
namespace(name, style) {
|
|
804
|
+
const logger2 = createLogger(env);
|
|
805
|
+
logger2.namespaces.push({
|
|
806
|
+
name,
|
|
807
|
+
style: style ?? resetStyle
|
|
808
|
+
});
|
|
809
|
+
return logger2;
|
|
810
|
+
},
|
|
811
|
+
printNamespaces() {
|
|
812
|
+
return {
|
|
813
|
+
namespaces: _logger.namespaces.map(({ name }) => `%c ${name} %c`).join(" "),
|
|
814
|
+
styles: _logger.namespaces.reduce((acc, { style }) => {
|
|
815
|
+
acc.push(
|
|
816
|
+
`background-color: ${style.backgroundColor}; color: ${style.color};`
|
|
817
|
+
);
|
|
818
|
+
acc.push("background-color: transparent; color: inherit;");
|
|
819
|
+
return acc;
|
|
820
|
+
}, [])
|
|
821
|
+
};
|
|
822
|
+
},
|
|
823
|
+
print(method, ...message) {
|
|
824
|
+
if (env === "development") {
|
|
825
|
+
const { namespaces, styles } = _logger.printNamespaces();
|
|
826
|
+
console[method](namespaces, ...styles, ...message);
|
|
827
|
+
}
|
|
828
|
+
return _logger;
|
|
829
|
+
},
|
|
830
|
+
printWithoutNamespace(method, ...message) {
|
|
831
|
+
if (env === "development") {
|
|
832
|
+
console[method](...message);
|
|
833
|
+
}
|
|
834
|
+
return _logger;
|
|
835
|
+
},
|
|
836
|
+
log(...message) {
|
|
837
|
+
return _logger.print("log", ...message);
|
|
838
|
+
},
|
|
839
|
+
warn(...message) {
|
|
840
|
+
return _logger.print("warn", ...message);
|
|
841
|
+
},
|
|
842
|
+
error(...message) {
|
|
843
|
+
return _logger.print("error", ...message);
|
|
844
|
+
},
|
|
845
|
+
group(...message) {
|
|
846
|
+
return _logger.print("group", ...message);
|
|
847
|
+
},
|
|
848
|
+
groupEnd() {
|
|
849
|
+
if (env === "development") {
|
|
850
|
+
console.groupEnd();
|
|
851
|
+
}
|
|
852
|
+
return _logger;
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
return _logger;
|
|
856
|
+
}
|
|
857
|
+
const Logger = createLogger("development");
|
|
858
|
+
const logger$3 = Logger.namespace("store");
|
|
859
|
+
const createDebugger = (store$) => {
|
|
860
|
+
return store$.pipe(
|
|
861
|
+
map(
|
|
862
|
+
(value) => [...value.keys()].reduce((acc, key) => {
|
|
863
|
+
var _a;
|
|
864
|
+
acc[key] = (_a = value.get(key)) == null ? void 0 : _a.getValue();
|
|
865
|
+
return acc;
|
|
866
|
+
}, {})
|
|
867
|
+
),
|
|
868
|
+
distinctUntilChanged(shallowEqual)
|
|
869
|
+
).subscribe((value) => {
|
|
870
|
+
logger$3.log("store", "update", value);
|
|
871
|
+
});
|
|
872
|
+
};
|
|
873
|
+
const createQueryStore = () => {
|
|
874
|
+
const store = /* @__PURE__ */ new Map();
|
|
875
|
+
const store$ = new BehaviorSubject(store);
|
|
876
|
+
const queryEventSubject = new Subject();
|
|
877
|
+
const queryTriggerSubject = new Subject();
|
|
878
|
+
const notify = () => {
|
|
879
|
+
store$.next(store);
|
|
880
|
+
};
|
|
881
|
+
const setValue = (key, value) => {
|
|
882
|
+
store.set(key, new BehaviorSubject(value));
|
|
883
|
+
notify();
|
|
884
|
+
};
|
|
885
|
+
const getValue = (serializedKey) => {
|
|
886
|
+
var _a;
|
|
887
|
+
return (_a = store.get(serializedKey)) == null ? void 0 : _a.getValue();
|
|
888
|
+
};
|
|
889
|
+
const getValue$ = (key) => {
|
|
890
|
+
return store$.pipe(
|
|
891
|
+
map(() => store.get(key)),
|
|
892
|
+
filter(isDefined),
|
|
893
|
+
map((entry) => entry.getValue()),
|
|
894
|
+
distinctUntilChanged(shallowEqual)
|
|
895
|
+
);
|
|
896
|
+
};
|
|
897
|
+
const updateValue = (key, value) => {
|
|
898
|
+
const existingObject = store.get(key);
|
|
899
|
+
if (!existingObject)
|
|
900
|
+
return;
|
|
901
|
+
if (typeof value === "function") {
|
|
902
|
+
existingObject.next({
|
|
903
|
+
...existingObject.getValue(),
|
|
904
|
+
...value(existingObject.getValue())
|
|
905
|
+
});
|
|
906
|
+
} else {
|
|
907
|
+
existingObject.next({ ...existingObject.getValue(), ...value });
|
|
908
|
+
}
|
|
909
|
+
store$.next(store);
|
|
910
|
+
};
|
|
911
|
+
const updateMany = (value, predicate = () => true) => {
|
|
912
|
+
store.forEach((oldValue$) => {
|
|
913
|
+
const oldValue = oldValue$.getValue();
|
|
914
|
+
if (predicate(oldValue)) {
|
|
915
|
+
oldValue$.next({ ...oldValue, ...value });
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
store$.next(store);
|
|
919
|
+
};
|
|
920
|
+
const deleteValue = (key) => {
|
|
921
|
+
store.delete(key);
|
|
922
|
+
store$.next(store);
|
|
923
|
+
};
|
|
924
|
+
const addRunner = (key, stream) => {
|
|
925
|
+
updateValue(key, (old) => ({
|
|
926
|
+
...old,
|
|
927
|
+
runners: [...old.runners, stream]
|
|
928
|
+
}));
|
|
929
|
+
return () => {
|
|
930
|
+
var _a;
|
|
931
|
+
const newListeners = ((_a = store.get(key)) == null ? void 0 : _a.getValue().runners.filter((reference) => reference !== stream)) ?? [];
|
|
932
|
+
updateValue(key, (old) => ({
|
|
933
|
+
...old,
|
|
934
|
+
runners: newListeners
|
|
935
|
+
}));
|
|
936
|
+
};
|
|
937
|
+
};
|
|
938
|
+
const debugger$ = createDebugger(store$);
|
|
939
|
+
return {
|
|
940
|
+
set: setValue,
|
|
941
|
+
get: getValue,
|
|
942
|
+
get$: getValue$,
|
|
943
|
+
delete: deleteValue,
|
|
944
|
+
update: updateValue,
|
|
945
|
+
keys: () => store.keys(),
|
|
946
|
+
updateMany,
|
|
947
|
+
addRunner,
|
|
948
|
+
store$,
|
|
949
|
+
queryEvent$: queryEventSubject.asObservable(),
|
|
950
|
+
dispatchQueryEvent: (event) => {
|
|
951
|
+
queryEventSubject.next(event);
|
|
952
|
+
},
|
|
953
|
+
queryTrigger$: queryTriggerSubject.asObservable(),
|
|
954
|
+
dispatchQueryTrigger: (event) => {
|
|
955
|
+
queryTriggerSubject.next(event);
|
|
956
|
+
},
|
|
957
|
+
size: () => store.size,
|
|
958
|
+
destroy: () => {
|
|
959
|
+
debugger$.unsubscribe();
|
|
960
|
+
queryEventSubject.complete();
|
|
961
|
+
queryTriggerSubject.complete();
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
};
|
|
965
|
+
const createQueryTrigger = ({
|
|
966
|
+
refetch$,
|
|
967
|
+
options$,
|
|
968
|
+
queryStore,
|
|
969
|
+
key
|
|
970
|
+
}) => {
|
|
971
|
+
const enabledOption$ = options$.pipe(
|
|
972
|
+
map(({ enabled = true }) => enabled),
|
|
973
|
+
distinctUntilChanged()
|
|
974
|
+
);
|
|
975
|
+
const enabledTrigger$ = enabledOption$.pipe(
|
|
976
|
+
skip(1),
|
|
977
|
+
filter((enabled) => enabled)
|
|
978
|
+
);
|
|
979
|
+
return merge(
|
|
980
|
+
queryStore.queryTrigger$.pipe(
|
|
981
|
+
filter((event) => key === event.key),
|
|
982
|
+
map(({ trigger: trigger2 }) => trigger2)
|
|
983
|
+
),
|
|
984
|
+
refetch$.pipe(
|
|
985
|
+
map((event) => ({
|
|
986
|
+
...event,
|
|
987
|
+
type: "refetch"
|
|
988
|
+
}))
|
|
989
|
+
),
|
|
990
|
+
enabledTrigger$.pipe(
|
|
991
|
+
map(() => ({
|
|
992
|
+
type: "enabled",
|
|
993
|
+
ignoreStale: false
|
|
994
|
+
}))
|
|
995
|
+
)
|
|
996
|
+
);
|
|
997
|
+
};
|
|
998
|
+
const deduplicate = (key, queryStore) => (source) => {
|
|
999
|
+
if (key === serializeKey([]))
|
|
1000
|
+
return source;
|
|
1001
|
+
return defer(() => {
|
|
1002
|
+
var _a;
|
|
1003
|
+
const sourceFromStore = (_a = queryStore.get(key)) == null ? void 0 : _a.deduplication_fn;
|
|
1004
|
+
const deleteFromStore = () => {
|
|
1005
|
+
queryStore.update(key, {
|
|
1006
|
+
deduplication_fn: void 0
|
|
1007
|
+
});
|
|
1008
|
+
};
|
|
1009
|
+
const finalSource = sourceFromStore ?? source.pipe(
|
|
1010
|
+
/**
|
|
1011
|
+
* Ideally we would want to remove the query from the store only on finalize,
|
|
1012
|
+
* which means whenever the query complete or error. Unfortunately finalize is
|
|
1013
|
+
* triggered after a new stream arrive which create a concurrency issue.
|
|
1014
|
+
* tap is triggered correctly synchronously and before a new query arrive.
|
|
1015
|
+
*/
|
|
1016
|
+
tap({
|
|
1017
|
+
error: deleteFromStore,
|
|
1018
|
+
complete: deleteFromStore
|
|
1019
|
+
}),
|
|
1020
|
+
/**
|
|
1021
|
+
* Because tap is not called on unsubscription we still need to handle the case.
|
|
1022
|
+
*/
|
|
1023
|
+
finalize(deleteFromStore),
|
|
1024
|
+
shareReplay({
|
|
1025
|
+
refCount: true,
|
|
1026
|
+
bufferSize: 1
|
|
1027
|
+
})
|
|
1028
|
+
);
|
|
1029
|
+
if (!sourceFromStore) {
|
|
1030
|
+
queryStore.update(key, {
|
|
1031
|
+
deduplication_fn: finalSource
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
return finalSource;
|
|
1035
|
+
});
|
|
1036
|
+
};
|
|
1037
|
+
const notifyQueryResult = (options$) => (stream$) => stream$.pipe(
|
|
1038
|
+
withLatestFrom(options$),
|
|
1039
|
+
map(([result, options]) => {
|
|
1040
|
+
var _a, _b;
|
|
1041
|
+
if (result.error) {
|
|
1042
|
+
(_a = options.onError) == null ? void 0 : _a.call(options, result.error);
|
|
1043
|
+
} else {
|
|
1044
|
+
(_b = options.onSuccess) == null ? void 0 : _b.call(options, result);
|
|
1045
|
+
}
|
|
1046
|
+
return result;
|
|
1047
|
+
})
|
|
1048
|
+
);
|
|
1049
|
+
const registerResultInCache = ({
|
|
1050
|
+
queryStore,
|
|
1051
|
+
serializedKey,
|
|
1052
|
+
options
|
|
1053
|
+
}) => (stream) => stream.pipe(
|
|
1054
|
+
tap((result) => {
|
|
1055
|
+
queryStore.update(serializedKey, {
|
|
1056
|
+
...options.cacheTime !== 0 && {
|
|
1057
|
+
cache_fnResult: { result }
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
})
|
|
1061
|
+
);
|
|
1062
|
+
const mapWithComplete = (mapFn) => (stream) => {
|
|
1063
|
+
return stream.pipe(map(mapFn({ isComplete: false })));
|
|
1064
|
+
};
|
|
1065
|
+
const createQueryFetch = ({
|
|
1066
|
+
options$,
|
|
1067
|
+
options,
|
|
1068
|
+
fn,
|
|
1069
|
+
queryStore,
|
|
1070
|
+
serializedKey,
|
|
1071
|
+
trigger: trigger2,
|
|
1072
|
+
trigger$
|
|
1073
|
+
}) => {
|
|
1074
|
+
const enabledOption$ = options$.pipe(
|
|
1075
|
+
map(({ enabled = true }) => enabled),
|
|
1076
|
+
distinctUntilChanged()
|
|
1077
|
+
);
|
|
1078
|
+
const disabled$ = enabledOption$.pipe(
|
|
1079
|
+
distinctUntilChanged(),
|
|
1080
|
+
filter((enabled) => !enabled)
|
|
1081
|
+
);
|
|
1082
|
+
const deferredQuery = defer(() => {
|
|
1083
|
+
const queryOrResponse = typeof fn === "function" ? fn() : fn;
|
|
1084
|
+
return from(queryOrResponse);
|
|
1085
|
+
});
|
|
1086
|
+
const fnExecution$ = deferredQuery.pipe(
|
|
1087
|
+
retryOnError(options),
|
|
1088
|
+
deduplicate(serializedKey, queryStore),
|
|
1089
|
+
tap(() => {
|
|
1090
|
+
queryStore.dispatchQueryEvent({
|
|
1091
|
+
key: serializedKey,
|
|
1092
|
+
type: "fetchSuccess"
|
|
1093
|
+
});
|
|
1094
|
+
queryStore.update(serializedKey, {
|
|
1095
|
+
lastFetchedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
1096
|
+
});
|
|
1097
|
+
}),
|
|
1098
|
+
registerResultInCache({ serializedKey, options, queryStore }),
|
|
1099
|
+
mapWithComplete(({ isComplete }) => (result) => ({
|
|
1100
|
+
status: "success",
|
|
1101
|
+
...isComplete && {
|
|
1102
|
+
fetchStatus: "idle"
|
|
1103
|
+
},
|
|
1104
|
+
data: { result },
|
|
1105
|
+
error: void 0
|
|
1106
|
+
})),
|
|
1107
|
+
endWith({
|
|
1108
|
+
fetchStatus: "idle"
|
|
1109
|
+
}),
|
|
1110
|
+
catchError((error) => {
|
|
1111
|
+
queryStore.dispatchQueryEvent({
|
|
1112
|
+
key: serializedKey,
|
|
1113
|
+
type: "fetchError"
|
|
1114
|
+
});
|
|
1115
|
+
return of({
|
|
1116
|
+
fetchStatus: "idle",
|
|
1117
|
+
status: "error",
|
|
1118
|
+
data: void 0,
|
|
1119
|
+
error
|
|
1120
|
+
});
|
|
1121
|
+
}),
|
|
1122
|
+
notifyQueryResult(options$)
|
|
1123
|
+
);
|
|
1124
|
+
const newCache$ = queryStore.queryEvent$.pipe(
|
|
1125
|
+
filter(
|
|
1126
|
+
(event) => event.key === serializedKey && event.type === "queryDataSet"
|
|
1127
|
+
),
|
|
1128
|
+
map(() => {
|
|
1129
|
+
var _a, _b;
|
|
1130
|
+
return (_b = (_a = queryStore.get(serializedKey)) == null ? void 0 : _a.cache_fnResult) == null ? void 0 : _b.result;
|
|
1131
|
+
}),
|
|
1132
|
+
filter(isDefined),
|
|
1133
|
+
map((result) => ({
|
|
1134
|
+
status: "success",
|
|
1135
|
+
data: { result }
|
|
1136
|
+
})),
|
|
1137
|
+
/**
|
|
1138
|
+
* @important
|
|
1139
|
+
* To avoid cache update being returned being the first result is returned.
|
|
1140
|
+
* For example if user set query data inside onSuccess callback, we simulate
|
|
1141
|
+
* a small delay to ensure it happens after.
|
|
1142
|
+
*/
|
|
1143
|
+
delay(1)
|
|
1144
|
+
);
|
|
1145
|
+
const execution$ = merge(
|
|
1146
|
+
disabled$.pipe(
|
|
1147
|
+
take(1),
|
|
1148
|
+
map(() => ({
|
|
1149
|
+
fetchStatus: "idle"
|
|
1150
|
+
}))
|
|
1151
|
+
),
|
|
1152
|
+
merge(
|
|
1153
|
+
of({ fetchStatus: "fetching", error: void 0 }),
|
|
1154
|
+
fnExecution$
|
|
1155
|
+
).pipe(takeUntil(disabled$)),
|
|
1156
|
+
newCache$
|
|
1157
|
+
).pipe(takeUntil(trigger$));
|
|
1158
|
+
const query = queryStore.get(serializedKey);
|
|
1159
|
+
const cacheResult = query == null ? void 0 : query.cache_fnResult;
|
|
1160
|
+
const hasCache = !!cacheResult;
|
|
1161
|
+
if (hasCache) {
|
|
1162
|
+
if (!(query == null ? void 0 : query.isStale) && !trigger2.ignoreStale) {
|
|
1163
|
+
return of({
|
|
1164
|
+
fetchStatus: "idle",
|
|
1165
|
+
status: "success",
|
|
1166
|
+
data: { result: cacheResult.result },
|
|
1167
|
+
error: void 0
|
|
1168
|
+
});
|
|
1169
|
+
} else {
|
|
1170
|
+
return merge(
|
|
1171
|
+
of({
|
|
1172
|
+
fetchStatus: "fetching",
|
|
1173
|
+
status: "success",
|
|
1174
|
+
data: { result: cacheResult.result },
|
|
1175
|
+
error: void 0
|
|
1176
|
+
}),
|
|
1177
|
+
execution$
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
return execution$;
|
|
1182
|
+
};
|
|
1183
|
+
const compareKeys = (keyA, keyB, { exact = false } = {}) => {
|
|
1184
|
+
if (exact) {
|
|
1185
|
+
return serializeKey(keyA) === serializeKey(keyB);
|
|
1186
|
+
}
|
|
1187
|
+
return keyA.reduce((acc, value, index) => {
|
|
1188
|
+
if (!acc)
|
|
1189
|
+
return false;
|
|
1190
|
+
return serializeObject(value) === serializeObject(keyB[index]);
|
|
1191
|
+
}, true);
|
|
1192
|
+
};
|
|
1193
|
+
const logger$2 = Logger.namespace("invalidation");
|
|
1194
|
+
const createInvalidationClient = ({
|
|
1195
|
+
queryStore
|
|
1196
|
+
}) => {
|
|
1197
|
+
const invalidateQueries = ({
|
|
1198
|
+
queryKey,
|
|
1199
|
+
exact = false,
|
|
1200
|
+
predicate
|
|
1201
|
+
} = {}) => {
|
|
1202
|
+
let keysToRefetch = [];
|
|
1203
|
+
if (queryKey) {
|
|
1204
|
+
logger$2.log(`invalidation requested for`, queryKey);
|
|
1205
|
+
queryStore.updateMany({ isStale: true }, (entry) => {
|
|
1206
|
+
const isValid = compareKeys(queryKey, entry.queryKey, { exact });
|
|
1207
|
+
if (isValid) {
|
|
1208
|
+
keysToRefetch.push(serializeKey(entry.queryKey));
|
|
1209
|
+
}
|
|
1210
|
+
return isValid;
|
|
1211
|
+
});
|
|
1212
|
+
} else if (predicate) {
|
|
1213
|
+
queryStore.updateMany({ isStale: true }, (entry) => {
|
|
1214
|
+
const isValid = predicate(entry);
|
|
1215
|
+
if (isValid) {
|
|
1216
|
+
keysToRefetch.push(serializeKey(entry.queryKey));
|
|
1217
|
+
}
|
|
1218
|
+
return isValid;
|
|
1219
|
+
});
|
|
1220
|
+
} else {
|
|
1221
|
+
logger$2.log(`Invalidation requested for all queries`);
|
|
1222
|
+
queryStore.updateMany({ isStale: true });
|
|
1223
|
+
keysToRefetch = Array.from(queryStore.keys());
|
|
1224
|
+
}
|
|
1225
|
+
keysToRefetch.forEach((key) => {
|
|
1226
|
+
queryStore.dispatchQueryTrigger({
|
|
1227
|
+
key,
|
|
1228
|
+
trigger: { ignoreStale: true, type: "refetch" }
|
|
1229
|
+
});
|
|
1230
|
+
});
|
|
1231
|
+
};
|
|
1232
|
+
return {
|
|
1233
|
+
invalidateQueries,
|
|
1234
|
+
destroy: () => {
|
|
1235
|
+
}
|
|
1236
|
+
};
|
|
1237
|
+
};
|
|
1238
|
+
const logger$1 = Logger.namespace("refetch");
|
|
1239
|
+
const createRefetchClient = ({
|
|
1240
|
+
queryStore
|
|
1241
|
+
}) => {
|
|
1242
|
+
const pipeQueryResult = ({
|
|
1243
|
+
options$
|
|
1244
|
+
}) => (stream) => {
|
|
1245
|
+
const sharedStream = stream.pipe(share());
|
|
1246
|
+
return merge(
|
|
1247
|
+
sharedStream,
|
|
1248
|
+
sharedStream.pipe(
|
|
1249
|
+
filter(
|
|
1250
|
+
(result) => !!result.data && result.fetchStatus !== "fetching"
|
|
1251
|
+
),
|
|
1252
|
+
distinctUntilChanged((prev, curr) => prev.data === curr.data),
|
|
1253
|
+
withLatestFrom(options$),
|
|
1254
|
+
map(([, { refetchInterval }]) => refetchInterval),
|
|
1255
|
+
filter(isDefined),
|
|
1256
|
+
switchMap((refetchInterval) => {
|
|
1257
|
+
if (typeof refetchInterval === "number") {
|
|
1258
|
+
return timer(refetchInterval).pipe(
|
|
1259
|
+
map(() => ({
|
|
1260
|
+
type: "refetch",
|
|
1261
|
+
ignoreStale: true
|
|
1262
|
+
})),
|
|
1263
|
+
switchMap(() => EMPTY)
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
return EMPTY;
|
|
1267
|
+
})
|
|
1268
|
+
)
|
|
1269
|
+
);
|
|
1270
|
+
};
|
|
1271
|
+
const pipeQueryTrigger = ({
|
|
1272
|
+
key
|
|
1273
|
+
}) => (stream) => {
|
|
1274
|
+
return merge(
|
|
1275
|
+
stream.pipe(
|
|
1276
|
+
tap(({ ignoreStale }) => {
|
|
1277
|
+
const query = queryStore.get(key);
|
|
1278
|
+
if (query && ignoreStale && !query.isStale) {
|
|
1279
|
+
logger$1.log(key, "marked stale by trigger!");
|
|
1280
|
+
queryStore.update(key, {
|
|
1281
|
+
isStale: true
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
})
|
|
1285
|
+
)
|
|
1286
|
+
);
|
|
1287
|
+
};
|
|
1288
|
+
return {
|
|
1289
|
+
pipeQueryResult,
|
|
1290
|
+
pipeQueryTrigger,
|
|
1291
|
+
destroy: () => {
|
|
1292
|
+
}
|
|
1293
|
+
};
|
|
1294
|
+
};
|
|
1295
|
+
const difference = (a, b) => a.filter((element) => !b.includes(element));
|
|
1296
|
+
const createQueryListener = (store, onQuery) => store.store$.pipe(
|
|
1297
|
+
map((store2) => [...store2.keys()]),
|
|
1298
|
+
startWith([]),
|
|
1299
|
+
pairwise(),
|
|
1300
|
+
mergeMap(([previousKeys, currentKeys]) => {
|
|
1301
|
+
const newKeys = difference(currentKeys, previousKeys);
|
|
1302
|
+
return merge(
|
|
1303
|
+
...newKeys.map((key) => {
|
|
1304
|
+
const deleted$ = store.store$.pipe(
|
|
1305
|
+
map(() => store.get(key)),
|
|
1306
|
+
filter((item) => item === void 0)
|
|
1307
|
+
);
|
|
1308
|
+
return merge(NEVER, of(key)).pipe(
|
|
1309
|
+
tap(() => {
|
|
1310
|
+
console.log("QUERY", key, "in");
|
|
1311
|
+
}),
|
|
1312
|
+
onQuery,
|
|
1313
|
+
finalize(() => {
|
|
1314
|
+
console.log("QUERY", key, "complete");
|
|
1315
|
+
}),
|
|
1316
|
+
takeUntil(deleted$)
|
|
1317
|
+
);
|
|
1318
|
+
})
|
|
1319
|
+
);
|
|
1320
|
+
})
|
|
1321
|
+
);
|
|
1322
|
+
const mapStoreQueryToRunnerOptions = (stream) => stream.pipe(
|
|
1323
|
+
switchMap((entry) => combineLatest(entry.runners)),
|
|
1324
|
+
map((runnerValues) => runnerValues.map(({ options }) => options))
|
|
1325
|
+
);
|
|
1326
|
+
const mapOptionsToOption$1 = (stream) => stream.pipe(
|
|
1327
|
+
map(
|
|
1328
|
+
(options) => options.reduce(
|
|
1329
|
+
(acc, value) => {
|
|
1330
|
+
return {
|
|
1331
|
+
...acc,
|
|
1332
|
+
lowestStaleTime: value.staleTime === void 0 ? acc.lowestStaleTime : Math.min(
|
|
1333
|
+
value.staleTime ?? Infinity,
|
|
1334
|
+
acc.lowestStaleTime ?? Infinity
|
|
1335
|
+
)
|
|
1336
|
+
};
|
|
1337
|
+
},
|
|
1338
|
+
{ lowestStaleTime: void 0 }
|
|
1339
|
+
)
|
|
1340
|
+
),
|
|
1341
|
+
distinctUntilChanged(shallowEqual)
|
|
1342
|
+
);
|
|
1343
|
+
const onlyFetchEventDone = (key) => (stream) => stream.pipe(
|
|
1344
|
+
filter(
|
|
1345
|
+
(event) => event.key === key && (event.type === "fetchError" || event.type === "fetchSuccess")
|
|
1346
|
+
)
|
|
1347
|
+
);
|
|
1348
|
+
const markAsStale = ({
|
|
1349
|
+
queryStore
|
|
1350
|
+
}) => (stream) => stream.pipe(
|
|
1351
|
+
switchMap((key) => {
|
|
1352
|
+
const query$ = queryStore.get$(key);
|
|
1353
|
+
return queryStore.queryEvent$.pipe(
|
|
1354
|
+
onlyFetchEventDone(key),
|
|
1355
|
+
switchMap(
|
|
1356
|
+
() => query$.pipe(
|
|
1357
|
+
mapStoreQueryToRunnerOptions,
|
|
1358
|
+
mapOptionsToOption$1,
|
|
1359
|
+
tap(({ lowestStaleTime = 0 }) => {
|
|
1360
|
+
var _a;
|
|
1361
|
+
if (lowestStaleTime === 0) {
|
|
1362
|
+
logger$2.log(key, "marked as stale!", {
|
|
1363
|
+
staleTime: lowestStaleTime
|
|
1364
|
+
});
|
|
1365
|
+
queryStore.update(key, { isStale: true });
|
|
1366
|
+
} else if ((_a = queryStore.get(key)) == null ? void 0 : _a.isStale) {
|
|
1367
|
+
logger$2.log(key, "marked non stale", {
|
|
1368
|
+
staleTime: lowestStaleTime
|
|
1369
|
+
});
|
|
1370
|
+
queryStore.update(key, { isStale: false });
|
|
1371
|
+
}
|
|
1372
|
+
}),
|
|
1373
|
+
filter(
|
|
1374
|
+
({ lowestStaleTime }) => lowestStaleTime !== Infinity && lowestStaleTime !== 0
|
|
1375
|
+
),
|
|
1376
|
+
switchMap(({ lowestStaleTime = 0 }) => timer(lowestStaleTime)),
|
|
1377
|
+
tap(() => {
|
|
1378
|
+
var _a;
|
|
1379
|
+
if (!((_a = queryStore.get(key)) == null ? void 0 : _a.isStale)) {
|
|
1380
|
+
logger$2.log(key, "marked as stale!");
|
|
1381
|
+
queryStore.update(key, { isStale: true });
|
|
1382
|
+
}
|
|
1383
|
+
})
|
|
1384
|
+
)
|
|
1385
|
+
),
|
|
1386
|
+
map(() => key)
|
|
1387
|
+
);
|
|
1388
|
+
})
|
|
1389
|
+
);
|
|
1390
|
+
const mapOptionsToOption = (stream) => stream.pipe(
|
|
1391
|
+
map(
|
|
1392
|
+
(options) => options.reduce(
|
|
1393
|
+
(acc, value) => {
|
|
1394
|
+
return {
|
|
1395
|
+
...acc,
|
|
1396
|
+
lowestCacheTime: value.cacheTime === void 0 ? acc.lowestCacheTime : Math.min(
|
|
1397
|
+
value.cacheTime ?? Infinity,
|
|
1398
|
+
acc.lowestCacheTime ?? Infinity
|
|
1399
|
+
)
|
|
1400
|
+
};
|
|
1401
|
+
},
|
|
1402
|
+
{ lowestCacheTime: void 0 }
|
|
1403
|
+
)
|
|
1404
|
+
),
|
|
1405
|
+
distinctUntilChanged(shallowEqual)
|
|
1406
|
+
);
|
|
1407
|
+
const onCacheUpdate = (stream) => stream.pipe(
|
|
1408
|
+
map((item) => item.cache_fnResult),
|
|
1409
|
+
distinctUntilChanged(shallowEqual)
|
|
1410
|
+
);
|
|
1411
|
+
const invalidateCache = ({
|
|
1412
|
+
queryStore
|
|
1413
|
+
}) => (stream) => stream.pipe(
|
|
1414
|
+
switchMap((key) => {
|
|
1415
|
+
const query$ = queryStore.get$(key);
|
|
1416
|
+
const invalidateCache$ = query$.pipe(
|
|
1417
|
+
onCacheUpdate,
|
|
1418
|
+
switchMap(
|
|
1419
|
+
() => query$.pipe(
|
|
1420
|
+
mapStoreQueryToRunnerOptions,
|
|
1421
|
+
mapOptionsToOption,
|
|
1422
|
+
switchMap(
|
|
1423
|
+
({
|
|
1424
|
+
lowestCacheTime = 5 * 60 * 1e3
|
|
1425
|
+
/* 5mn */
|
|
1426
|
+
}) => timer(lowestCacheTime).pipe(
|
|
1427
|
+
tap(() => {
|
|
1428
|
+
queryStore.update(key, { cache_fnResult: void 0 });
|
|
1429
|
+
})
|
|
1430
|
+
)
|
|
1431
|
+
)
|
|
1432
|
+
)
|
|
1433
|
+
)
|
|
1434
|
+
);
|
|
1435
|
+
return invalidateCache$.pipe(map(() => key));
|
|
1436
|
+
})
|
|
1437
|
+
);
|
|
1438
|
+
const garbageCache = ({
|
|
1439
|
+
queryStore
|
|
1440
|
+
}) => (stream) => stream.pipe(
|
|
1441
|
+
switchMap((key) => {
|
|
1442
|
+
const query$ = queryStore.get$(key);
|
|
1443
|
+
return query$.pipe(
|
|
1444
|
+
filter((entry) => !entry.cache_fnResult),
|
|
1445
|
+
map((entry) => entry.runners.length > 0),
|
|
1446
|
+
pairwise(),
|
|
1447
|
+
filter(([hadRunners, hasRunners]) => hadRunners && !hasRunners),
|
|
1448
|
+
tap(() => {
|
|
1449
|
+
queryStore.delete(key);
|
|
1450
|
+
}),
|
|
1451
|
+
map(() => key)
|
|
1452
|
+
);
|
|
1453
|
+
})
|
|
1454
|
+
);
|
|
1455
|
+
const getInitialQueryEntity = ({ key }) => ({
|
|
1456
|
+
isStale: true,
|
|
1457
|
+
queryKey: key,
|
|
1458
|
+
runners: []
|
|
1459
|
+
});
|
|
1460
|
+
const updateStoreWithQuery = ({
|
|
1461
|
+
queryStore,
|
|
1462
|
+
serializedKey,
|
|
1463
|
+
runner$,
|
|
1464
|
+
key
|
|
1465
|
+
}) => (stream) => stream.pipe(
|
|
1466
|
+
map((value) => {
|
|
1467
|
+
if (key.length === 0)
|
|
1468
|
+
return [value, () => {
|
|
1469
|
+
}];
|
|
1470
|
+
if (!queryStore.get(serializedKey)) {
|
|
1471
|
+
queryStore.set(serializedKey, getInitialQueryEntity({ key }));
|
|
1472
|
+
} else {
|
|
1473
|
+
queryStore.update(serializedKey, {
|
|
1474
|
+
queryKey: key,
|
|
1475
|
+
...value.options.markStale && {
|
|
1476
|
+
isStale: true
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
return [value, queryStore.addRunner(serializedKey, runner$)];
|
|
1481
|
+
})
|
|
1482
|
+
);
|
|
1483
|
+
const logger = Logger.namespace("cache");
|
|
1484
|
+
const createCacheClient = ({
|
|
1485
|
+
queryStore
|
|
1486
|
+
}) => {
|
|
1487
|
+
const setQueryData = ({
|
|
1488
|
+
queryKey,
|
|
1489
|
+
updater
|
|
1490
|
+
}) => {
|
|
1491
|
+
const serializedKey = serializeKey(queryKey);
|
|
1492
|
+
if (queryKey.length === 0)
|
|
1493
|
+
return;
|
|
1494
|
+
logger.log("set cache for query", serializeKey);
|
|
1495
|
+
if (!queryStore.get(serializedKey)) {
|
|
1496
|
+
queryStore.set(serializedKey, getInitialQueryEntity({ key: queryKey }));
|
|
1497
|
+
}
|
|
1498
|
+
queryStore.update(serializedKey, (entity) => {
|
|
1499
|
+
var _a;
|
|
1500
|
+
if (typeof updater === "function") {
|
|
1501
|
+
const callableUpdater = updater;
|
|
1502
|
+
return {
|
|
1503
|
+
...entity,
|
|
1504
|
+
cache_fnResult: {
|
|
1505
|
+
result: callableUpdater(
|
|
1506
|
+
(_a = entity.cache_fnResult) == null ? void 0 : _a.result
|
|
1507
|
+
)
|
|
1508
|
+
}
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
return {
|
|
1512
|
+
...entity,
|
|
1513
|
+
cache_fnResult: {
|
|
1514
|
+
result: updater
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1517
|
+
});
|
|
1518
|
+
queryStore.dispatchQueryEvent({
|
|
1519
|
+
key: serializedKey,
|
|
1520
|
+
type: "queryDataSet"
|
|
1521
|
+
});
|
|
1522
|
+
};
|
|
1523
|
+
return {
|
|
1524
|
+
setQueryData
|
|
1525
|
+
};
|
|
1526
|
+
};
|
|
1527
|
+
const createClient = () => {
|
|
1528
|
+
const queryStore = createQueryStore();
|
|
1529
|
+
const invalidationClient = createInvalidationClient({ queryStore });
|
|
1530
|
+
const cacheClient = createCacheClient({ queryStore });
|
|
1531
|
+
const refetchClient = createRefetchClient({ queryStore });
|
|
1532
|
+
const query$ = ({
|
|
1533
|
+
key,
|
|
1534
|
+
fn$: maybeFn$,
|
|
1535
|
+
fn: maybeFn,
|
|
1536
|
+
refetch$ = new Subject(),
|
|
1537
|
+
options$ = new BehaviorSubject({})
|
|
1538
|
+
}) => {
|
|
1539
|
+
const serializedKey = serializeKey(key);
|
|
1540
|
+
const internalRefetch$ = new Subject();
|
|
1541
|
+
const fn$ = maybeFn$ ?? (maybeFn ? of(maybeFn) : NEVER);
|
|
1542
|
+
console.log("query$()", serializedKey);
|
|
1543
|
+
const runner$ = options$.pipe(map((options) => ({ options })));
|
|
1544
|
+
let deleteRunner = () => {
|
|
1545
|
+
};
|
|
1546
|
+
const initialTrigger$ = of({
|
|
1547
|
+
type: "initial",
|
|
1548
|
+
ignoreStale: false
|
|
1549
|
+
});
|
|
1550
|
+
const trigger$ = createQueryTrigger({
|
|
1551
|
+
options$,
|
|
1552
|
+
refetch$: merge(refetch$, internalRefetch$),
|
|
1553
|
+
key: serializedKey,
|
|
1554
|
+
queryStore
|
|
1555
|
+
}).pipe(refetchClient.pipeQueryTrigger({ options$, key: serializedKey }));
|
|
1556
|
+
const result$ = merge(initialTrigger$, trigger$).pipe(
|
|
1557
|
+
withLatestFrom(fn$, options$),
|
|
1558
|
+
map(([trigger2, fn, options]) => ({ trigger: trigger2, fn, options })),
|
|
1559
|
+
updateStoreWithQuery({
|
|
1560
|
+
key,
|
|
1561
|
+
queryStore,
|
|
1562
|
+
runner$,
|
|
1563
|
+
serializedKey
|
|
1564
|
+
}),
|
|
1565
|
+
map(([value, deleteRunnerFn]) => {
|
|
1566
|
+
deleteRunner = deleteRunnerFn;
|
|
1567
|
+
console.log("reactjrx", serializedKey, "query trigger", {
|
|
1568
|
+
trigger: value.trigger,
|
|
1569
|
+
options: value.options
|
|
1570
|
+
});
|
|
1571
|
+
return value;
|
|
1572
|
+
}),
|
|
1573
|
+
filter(({ options }) => options.enabled !== false),
|
|
1574
|
+
mergeMap(
|
|
1575
|
+
({ fn, options, trigger: trigger2 }) => createQueryFetch({
|
|
1576
|
+
options$,
|
|
1577
|
+
options,
|
|
1578
|
+
fn,
|
|
1579
|
+
queryStore,
|
|
1580
|
+
serializedKey,
|
|
1581
|
+
trigger: trigger2,
|
|
1582
|
+
trigger$
|
|
1583
|
+
})
|
|
1584
|
+
),
|
|
1585
|
+
// hooks
|
|
1586
|
+
switchMap(
|
|
1587
|
+
(result) => merge(
|
|
1588
|
+
of(result).pipe(
|
|
1589
|
+
refetchClient.pipeQueryResult({
|
|
1590
|
+
key: serializedKey,
|
|
1591
|
+
queryStore,
|
|
1592
|
+
options$,
|
|
1593
|
+
refetch$: internalRefetch$
|
|
1594
|
+
})
|
|
1595
|
+
)
|
|
1596
|
+
)
|
|
1597
|
+
),
|
|
1598
|
+
mergeResults,
|
|
1599
|
+
withLatestFrom(options$),
|
|
1600
|
+
takeWhile(([result, options]) => {
|
|
1601
|
+
const shouldStop = result.data !== void 0 && options.terminateOnFirstResult;
|
|
1602
|
+
return !shouldStop;
|
|
1603
|
+
}, true),
|
|
1604
|
+
map(([result]) => result),
|
|
1605
|
+
tap((result) => {
|
|
1606
|
+
console.log("result", result);
|
|
1607
|
+
}),
|
|
1608
|
+
finalize(() => {
|
|
1609
|
+
deleteRunner();
|
|
1610
|
+
})
|
|
1611
|
+
);
|
|
1612
|
+
return {
|
|
1613
|
+
result$
|
|
1614
|
+
};
|
|
1615
|
+
};
|
|
1616
|
+
const queryListenerSub = createQueryListener(
|
|
1617
|
+
queryStore,
|
|
1618
|
+
(stream) => stream.pipe(
|
|
1619
|
+
switchMap((key) => {
|
|
1620
|
+
const key$ = of(key);
|
|
1621
|
+
return merge(
|
|
1622
|
+
invalidateCache({
|
|
1623
|
+
queryStore
|
|
1624
|
+
})(key$),
|
|
1625
|
+
markAsStale({
|
|
1626
|
+
queryStore
|
|
1627
|
+
})(key$),
|
|
1628
|
+
garbageCache({
|
|
1629
|
+
queryStore
|
|
1630
|
+
})(key$)
|
|
1631
|
+
);
|
|
1632
|
+
})
|
|
1633
|
+
)
|
|
1634
|
+
).subscribe();
|
|
1635
|
+
return {
|
|
1636
|
+
query$,
|
|
1637
|
+
queryStore,
|
|
1638
|
+
...invalidationClient,
|
|
1639
|
+
...cacheClient,
|
|
1640
|
+
...refetchClient,
|
|
1641
|
+
destroy: () => {
|
|
1642
|
+
queryStore.destroy();
|
|
1643
|
+
queryListenerSub.unsubscribe();
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
};
|
|
851
1647
|
export {
|
|
852
1648
|
PersistSignals,
|
|
853
1649
|
Provider as ReactjrxQueryProvider,
|
|
854
1650
|
SIGNAL_RESET,
|
|
1651
|
+
createClient,
|
|
855
1652
|
createLocalforageAdapter,
|
|
856
1653
|
createSharedStoreAdapter,
|
|
857
1654
|
exponentialBackoffDelay,
|
|
@@ -865,10 +1662,12 @@ export {
|
|
|
865
1662
|
useObserveCallback,
|
|
866
1663
|
usePersistSignalsContext,
|
|
867
1664
|
useQuery,
|
|
1665
|
+
useReactJrxProvider,
|
|
868
1666
|
useScopeSignals,
|
|
869
1667
|
useSetSignal,
|
|
870
1668
|
useSignal,
|
|
871
1669
|
useSignalValue,
|
|
1670
|
+
useSubject,
|
|
872
1671
|
useSubscribe,
|
|
873
1672
|
useSubscribeEffect,
|
|
874
1673
|
useUnmountObservable,
|