reactjrx 1.108.0 → 1.108.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -652,48 +652,141 @@ function isDefined(arg) {
652
652
  }
653
653
  const arrayEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
654
654
  const isServer = typeof window === "undefined" || "Deno" in window;
655
+ class QueryClient$ {
656
+ constructor() {
657
+ __publicField(this, "queryMap", /* @__PURE__ */ new Map());
658
+ }
659
+ getQuery(queryHash) {
660
+ return this.queryMap.get(queryHash);
661
+ }
662
+ setQuery(queryKey, query$, signal2) {
663
+ const queryHash = reactQuery.hashKey(queryKey);
664
+ const sharedQuery$ = query$.pipe(
665
+ /**
666
+ * abort signal is triggered on:
667
+ * - manual cancellation from user
668
+ * - unmounting the component
669
+ * @see https://tanstack.com/query/latest/docs/framework/react/guides/query-cancellation
670
+ */
671
+ rxjs.takeUntil(
672
+ rxjs.fromEvent(signal2, "abort").pipe(
673
+ rxjs.tap(() => {
674
+ debugger;
675
+ })
676
+ )
677
+ ),
678
+ rxjs.share()
679
+ );
680
+ const cacheEntry = {
681
+ query$: sharedQuery$,
682
+ signal: signal2,
683
+ sub: void 0,
684
+ isCompleted: false,
685
+ lastData: void 0
686
+ };
687
+ this.queryMap.set(queryHash, cacheEntry);
688
+ const sub = sharedQuery$.subscribe({
689
+ next: (data) => {
690
+ const entry = this.queryMap.get(queryHash);
691
+ if (entry) {
692
+ entry.lastData = { value: data };
693
+ }
694
+ },
695
+ complete: () => {
696
+ this.deleteQuery(queryHash);
697
+ }
698
+ });
699
+ cacheEntry.sub = sub;
700
+ return cacheEntry;
701
+ }
702
+ deleteQuery(queryHash) {
703
+ const entry = this.queryMap.get(queryHash);
704
+ if (!entry) return;
705
+ if (entry.sub) {
706
+ entry.sub.unsubscribe();
707
+ entry.sub = void 0;
708
+ }
709
+ entry.isCompleted = true;
710
+ this.queryMap.delete(queryHash);
711
+ }
712
+ destroy() {
713
+ this.queryMap.forEach((_, key) => {
714
+ this.deleteQuery(key);
715
+ });
716
+ }
717
+ }
718
+ const Context$1 = React.createContext(void 0);
719
+ const QueryClientProvider$ = React.memo(
720
+ ({
721
+ children,
722
+ client: _client2
723
+ }) => {
724
+ const [client] = React.useState(() => _client2 ?? new QueryClient$());
725
+ React.useEffect(() => {
726
+ return () => {
727
+ client.destroy();
728
+ };
729
+ }, [client]);
730
+ return /* @__PURE__ */ jsxRuntime.jsx(Context$1.Provider, { value: client, children });
731
+ }
732
+ );
733
+ const useQueryClient$ = () => {
734
+ const client = React.useContext(Context$1);
735
+ if (!client) {
736
+ throw new Error(
737
+ "useReactJrxQueryClient must be used within a ReactJrxQueryProvider"
738
+ );
739
+ }
740
+ return client;
741
+ };
655
742
  function useQuery$(options, queryClient) {
656
- const sub = React.useRef();
657
743
  const _queryClient = reactQuery.useQueryClient(queryClient);
744
+ const queryClient$ = useQueryClient$();
658
745
  const queryFnAsync = (context) => {
659
- let isResolved = false;
660
746
  return new Promise((resolve, reject) => {
661
- let lastData = void 0;
662
- if (sub.current) {
663
- sub.current.unsubscribe();
664
- sub.current = void 0;
665
- }
666
- const unsub = _queryClient.getQueryCache().subscribe((d) => {
667
- var _a;
668
- if (d.type === "observerRemoved" && d.query.observers.length === 0) {
669
- unsub();
670
- _queryClient.cancelQueries({ queryKey: context.queryKey });
671
- (_a = sub.current) == null ? void 0 : _a.unsubscribe();
672
- }
673
- });
674
- const source = rxjs.defer(
747
+ const getSource = () => rxjs.defer(
675
748
  () => typeof options.queryFn === "function" ? options.queryFn(context) : options.queryFn
676
749
  );
677
- sub.current = source.pipe(
678
- rxjs.finalize(() => {
679
- unsub();
680
- isResolved = true;
681
- })
750
+ const queryHash = reactQuery.hashKey(context.queryKey);
751
+ const queryCacheEntry = queryClient$.getQuery(queryHash) ?? queryClient$.setQuery(
752
+ context.queryKey,
753
+ getSource(),
754
+ context.signal
755
+ );
756
+ const query$ = queryCacheEntry.query$;
757
+ query$.pipe(
758
+ rxjs.take(1),
759
+ /**
760
+ * If several values are emitted during this delay, we will only
761
+ * keep the last value. This is unfortunate but it's the best we can do
762
+ * for now.
763
+ */
764
+ rxjs.delay(1)
682
765
  ).subscribe({
683
- next: (data) => {
684
- lastData = data;
685
- _queryClient == null ? void 0 : _queryClient.setQueryData(context.queryKey, data);
686
- },
687
766
  error: (error) => {
688
- isResolved = true;
689
- reject(error);
767
+ return reject(error);
690
768
  },
691
769
  complete: () => {
692
- if (lastData === void 0)
693
- return reject(new Error("Stream completed without any data"));
694
- if (isResolved) return;
695
- isResolved = true;
696
- resolve(lastData);
770
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.lastData) === void 0) {
771
+ console.log(
772
+ "cancelled due to stream completing without data",
773
+ queryCacheEntry == null ? void 0 : queryCacheEntry.lastData
774
+ );
775
+ _queryClient.cancelQueries({
776
+ queryKey: context.queryKey,
777
+ exact: true
778
+ });
779
+ return resolve(void 0);
780
+ }
781
+ resolve(queryCacheEntry.lastData.value);
782
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.isCompleted) === false) {
783
+ setTimeout(() => {
784
+ _queryClient == null ? void 0 : _queryClient.refetchQueries({
785
+ queryKey: context.queryKey,
786
+ exact: true
787
+ });
788
+ });
789
+ }
697
790
  }
698
791
  });
699
792
  });
@@ -3519,10 +3612,13 @@ _queryCache = new WeakMap();
3519
3612
  _mutationDefaults = new WeakMap();
3520
3613
  _queryDefaults = new WeakMap();
3521
3614
  _defaultOptions2 = new WeakMap();
3615
+ exports.Context = Context$1;
3522
3616
  exports.MutationCache = MutationCache;
3523
3617
  exports.QueryCache = QueryCache;
3524
3618
  exports.QueryClient = QueryClient;
3619
+ exports.QueryClient$ = QueryClient$;
3525
3620
  exports.QueryClientProvider = QueryClientProvider;
3621
+ exports.QueryClientProvider$ = QueryClientProvider$;
3526
3622
  exports.SIGNAL_RESET = SIGNAL_RESET;
3527
3623
  exports.arrayEqual = arrayEqual;
3528
3624
  exports.createLocalStorageAdapter = createLocalStorageAdapter;
@@ -3549,6 +3645,7 @@ exports.usePersistSignals = usePersistSignals;
3549
3645
  exports.useQuery = useQuery;
3550
3646
  exports.useQuery$ = useQuery$;
3551
3647
  exports.useQueryClient = useQueryClient;
3648
+ exports.useQueryClient$ = useQueryClient$;
3552
3649
  exports.useSignal = useSignal;
3553
3650
  exports.useSignalValue = useSignalValue;
3554
3651
  exports.useSubject = useSubject;
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export * from './lib/utils';
17
17
  export * from './lib/queries/useQuery$';
18
18
  export * from './lib/queries/useMutation$';
19
19
  export * from './lib/queries/useSwitchMutation$';
20
+ export * from './lib/queries/QueryClientProvider$';
20
21
  export * from './lib/deprecated/react/mutations/useMutation';
21
22
  export * from './lib/deprecated/react/queries/useQuery';
22
23
  export * from './lib/deprecated/react/useQueryClient';
package/dist/index.js CHANGED
@@ -11,10 +11,10 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
11
11
  var _trigger$, _mutationRunner, _currentMutationSubject, _visibility$, _focusedSubject, _client, _currentQuery, _fetchSubject, _currentQueryInitialState, _lastResult, _lastQueryWithDefinedData, _observers, _observerCount, _cancelSubject, _executeSubject, _store, _defaultOptions, _initialState, _notifySubject, _store2, _mutationCache, _queryCache, _mutationDefaults, _queryDefaults, _defaultOptions2;
12
12
  import * as React from "react";
13
13
  import { useRef, useMemo, useCallback, useSyncExternalStore, useEffect, useState, createContext, memo, useContext } from "react";
14
- import { isObservable, from, of, defer, startWith, identity, distinctUntilChanged, tap, catchError, EMPTY, Subject, BehaviorSubject, skip, first, map, switchMap, zip, share, merge, throttleTime, asyncScheduler, concatMap, scan, throwError, timer, finalize, take, takeUntil, defaultIfEmpty, Observable, takeWhile, filter, last, mergeMap as mergeMap$1, shareReplay, ignoreElements, fromEvent, noop as noop$1, pairwise, NEVER, delay, interval, withLatestFrom, retry, iif, isEmpty, concat, toArray, combineLatest, endWith, lastValueFrom } from "rxjs";
14
+ import { isObservable, from, of, defer, startWith, identity, distinctUntilChanged, tap, catchError, EMPTY, Subject, BehaviorSubject, skip, first, map, switchMap, zip, share, merge, throttleTime, asyncScheduler, concatMap, scan, throwError, timer, takeUntil, fromEvent, take, delay, defaultIfEmpty, Observable, takeWhile, filter, last, mergeMap as mergeMap$1, shareReplay, ignoreElements, noop as noop$1, pairwise, NEVER, interval, withLatestFrom, retry, iif, isEmpty, concat, toArray, combineLatest, endWith, lastValueFrom } from "rxjs";
15
15
  import { catchError as catchError$1, mergeMap, retryWhen, concatMap as concatMap$1, first as first$1, tap as tap$1 } from "rxjs/operators";
16
- import { useQueryClient as useQueryClient$1, useQuery as useQuery$1, useMutation as useMutation$1 } from "@tanstack/react-query";
17
- import { jsxs, jsx } from "react/jsx-runtime";
16
+ import { hashKey as hashKey$1, useQueryClient as useQueryClient$1, useQuery as useQuery$1, useMutation as useMutation$1 } from "@tanstack/react-query";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
18
  const useLiveRef = (value) => {
19
19
  const ref = useRef(value);
20
20
  useMemo(() => {
@@ -634,48 +634,141 @@ function isDefined(arg) {
634
634
  }
635
635
  const arrayEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
636
636
  const isServer = typeof window === "undefined" || "Deno" in window;
637
+ class QueryClient$ {
638
+ constructor() {
639
+ __publicField(this, "queryMap", /* @__PURE__ */ new Map());
640
+ }
641
+ getQuery(queryHash) {
642
+ return this.queryMap.get(queryHash);
643
+ }
644
+ setQuery(queryKey, query$, signal2) {
645
+ const queryHash = hashKey$1(queryKey);
646
+ const sharedQuery$ = query$.pipe(
647
+ /**
648
+ * abort signal is triggered on:
649
+ * - manual cancellation from user
650
+ * - unmounting the component
651
+ * @see https://tanstack.com/query/latest/docs/framework/react/guides/query-cancellation
652
+ */
653
+ takeUntil(
654
+ fromEvent(signal2, "abort").pipe(
655
+ tap(() => {
656
+ debugger;
657
+ })
658
+ )
659
+ ),
660
+ share()
661
+ );
662
+ const cacheEntry = {
663
+ query$: sharedQuery$,
664
+ signal: signal2,
665
+ sub: void 0,
666
+ isCompleted: false,
667
+ lastData: void 0
668
+ };
669
+ this.queryMap.set(queryHash, cacheEntry);
670
+ const sub = sharedQuery$.subscribe({
671
+ next: (data) => {
672
+ const entry = this.queryMap.get(queryHash);
673
+ if (entry) {
674
+ entry.lastData = { value: data };
675
+ }
676
+ },
677
+ complete: () => {
678
+ this.deleteQuery(queryHash);
679
+ }
680
+ });
681
+ cacheEntry.sub = sub;
682
+ return cacheEntry;
683
+ }
684
+ deleteQuery(queryHash) {
685
+ const entry = this.queryMap.get(queryHash);
686
+ if (!entry) return;
687
+ if (entry.sub) {
688
+ entry.sub.unsubscribe();
689
+ entry.sub = void 0;
690
+ }
691
+ entry.isCompleted = true;
692
+ this.queryMap.delete(queryHash);
693
+ }
694
+ destroy() {
695
+ this.queryMap.forEach((_, key) => {
696
+ this.deleteQuery(key);
697
+ });
698
+ }
699
+ }
700
+ const Context$1 = createContext(void 0);
701
+ const QueryClientProvider$ = memo(
702
+ ({
703
+ children,
704
+ client: _client2
705
+ }) => {
706
+ const [client] = useState(() => _client2 ?? new QueryClient$());
707
+ useEffect(() => {
708
+ return () => {
709
+ client.destroy();
710
+ };
711
+ }, [client]);
712
+ return /* @__PURE__ */ jsx(Context$1.Provider, { value: client, children });
713
+ }
714
+ );
715
+ const useQueryClient$ = () => {
716
+ const client = useContext(Context$1);
717
+ if (!client) {
718
+ throw new Error(
719
+ "useReactJrxQueryClient must be used within a ReactJrxQueryProvider"
720
+ );
721
+ }
722
+ return client;
723
+ };
637
724
  function useQuery$(options, queryClient) {
638
- const sub = useRef();
639
725
  const _queryClient = useQueryClient$1(queryClient);
726
+ const queryClient$ = useQueryClient$();
640
727
  const queryFnAsync = (context) => {
641
- let isResolved = false;
642
728
  return new Promise((resolve, reject) => {
643
- let lastData = void 0;
644
- if (sub.current) {
645
- sub.current.unsubscribe();
646
- sub.current = void 0;
647
- }
648
- const unsub = _queryClient.getQueryCache().subscribe((d) => {
649
- var _a;
650
- if (d.type === "observerRemoved" && d.query.observers.length === 0) {
651
- unsub();
652
- _queryClient.cancelQueries({ queryKey: context.queryKey });
653
- (_a = sub.current) == null ? void 0 : _a.unsubscribe();
654
- }
655
- });
656
- const source = defer(
729
+ const getSource = () => defer(
657
730
  () => typeof options.queryFn === "function" ? options.queryFn(context) : options.queryFn
658
731
  );
659
- sub.current = source.pipe(
660
- finalize(() => {
661
- unsub();
662
- isResolved = true;
663
- })
732
+ const queryHash = hashKey$1(context.queryKey);
733
+ const queryCacheEntry = queryClient$.getQuery(queryHash) ?? queryClient$.setQuery(
734
+ context.queryKey,
735
+ getSource(),
736
+ context.signal
737
+ );
738
+ const query$ = queryCacheEntry.query$;
739
+ query$.pipe(
740
+ take(1),
741
+ /**
742
+ * If several values are emitted during this delay, we will only
743
+ * keep the last value. This is unfortunate but it's the best we can do
744
+ * for now.
745
+ */
746
+ delay(1)
664
747
  ).subscribe({
665
- next: (data) => {
666
- lastData = data;
667
- _queryClient == null ? void 0 : _queryClient.setQueryData(context.queryKey, data);
668
- },
669
748
  error: (error) => {
670
- isResolved = true;
671
- reject(error);
749
+ return reject(error);
672
750
  },
673
751
  complete: () => {
674
- if (lastData === void 0)
675
- return reject(new Error("Stream completed without any data"));
676
- if (isResolved) return;
677
- isResolved = true;
678
- resolve(lastData);
752
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.lastData) === void 0) {
753
+ console.log(
754
+ "cancelled due to stream completing without data",
755
+ queryCacheEntry == null ? void 0 : queryCacheEntry.lastData
756
+ );
757
+ _queryClient.cancelQueries({
758
+ queryKey: context.queryKey,
759
+ exact: true
760
+ });
761
+ return resolve(void 0);
762
+ }
763
+ resolve(queryCacheEntry.lastData.value);
764
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.isCompleted) === false) {
765
+ setTimeout(() => {
766
+ _queryClient == null ? void 0 : _queryClient.refetchQueries({
767
+ queryKey: context.queryKey,
768
+ exact: true
769
+ });
770
+ });
771
+ }
679
772
  }
680
773
  });
681
774
  });
@@ -3502,10 +3595,13 @@ _mutationDefaults = new WeakMap();
3502
3595
  _queryDefaults = new WeakMap();
3503
3596
  _defaultOptions2 = new WeakMap();
3504
3597
  export {
3598
+ Context$1 as Context,
3505
3599
  MutationCache,
3506
3600
  QueryCache,
3507
3601
  QueryClient,
3602
+ QueryClient$,
3508
3603
  QueryClientProvider,
3604
+ QueryClientProvider$,
3509
3605
  SIGNAL_RESET,
3510
3606
  arrayEqual,
3511
3607
  createLocalStorageAdapter,
@@ -3532,6 +3628,7 @@ export {
3532
3628
  useQuery,
3533
3629
  useQuery$,
3534
3630
  useQueryClient,
3631
+ useQueryClient$,
3535
3632
  useSignal,
3536
3633
  useSignalValue,
3537
3634
  useSubject,
@@ -0,0 +1,25 @@
1
+ import { QueryKey } from '@tanstack/react-query';
2
+ import { Observable, Subscription } from 'rxjs';
3
+ type CacheEntry = {
4
+ query$: Observable<unknown>;
5
+ signal: AbortSignal;
6
+ sub: Subscription | undefined;
7
+ isCompleted: boolean;
8
+ lastData: {
9
+ value: unknown;
10
+ } | undefined;
11
+ };
12
+ export declare class QueryClient$ {
13
+ readonly queryMap: Map<string, CacheEntry>;
14
+ getQuery(queryHash: string): CacheEntry | undefined;
15
+ setQuery(queryKey: QueryKey, query$: Observable<unknown>, signal: AbortSignal): CacheEntry;
16
+ deleteQuery(queryHash: string): void;
17
+ destroy(): void;
18
+ }
19
+ export declare const Context: import('react').Context<QueryClient$ | undefined>;
20
+ export declare const QueryClientProvider$: import('react').MemoExoticComponent<({ children, client: _client }: {
21
+ children: React.ReactNode;
22
+ client?: QueryClient$;
23
+ }) => import("react/jsx-runtime").JSX.Element>;
24
+ export declare const useQueryClient$: () => QueryClient$;
25
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "reactjrx",
3
3
  "private": false,
4
- "version": "1.108.0",
4
+ "version": "1.108.3",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -54,7 +54,6 @@
54
54
  "eslint-plugin-react-hooks": "^4.6.0",
55
55
  "jsdom": "^25.0.0",
56
56
  "prettier": "^3.1.0",
57
- "react-error-boundary": "^4.0.12",
58
57
  "rollup-plugin-node-externals": "^7.0.1",
59
58
  "rxjs": "^7.8.0",
60
59
  "semantic-release": "^24.1.1",
@@ -1 +0,0 @@
1
- export {};