reactjrx 1.108.0 → 1.108.4

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,135 @@ 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(rxjs.fromEvent(signal2, "abort")),
672
+ rxjs.share()
673
+ );
674
+ const cacheEntry = {
675
+ query$: sharedQuery$,
676
+ signal: signal2,
677
+ sub: void 0,
678
+ isCompleted: false,
679
+ lastData: void 0
680
+ };
681
+ this.queryMap.set(queryHash, cacheEntry);
682
+ const sub = sharedQuery$.subscribe({
683
+ next: (data) => {
684
+ const entry = this.queryMap.get(queryHash);
685
+ if (entry) {
686
+ entry.lastData = { value: data };
687
+ }
688
+ },
689
+ complete: () => {
690
+ this.deleteQuery(queryHash);
691
+ }
692
+ });
693
+ cacheEntry.sub = sub;
694
+ return cacheEntry;
695
+ }
696
+ deleteQuery(queryHash) {
697
+ const entry = this.queryMap.get(queryHash);
698
+ if (!entry) return;
699
+ if (entry.sub) {
700
+ entry.sub.unsubscribe();
701
+ entry.sub = void 0;
702
+ }
703
+ entry.isCompleted = true;
704
+ this.queryMap.delete(queryHash);
705
+ }
706
+ destroy() {
707
+ this.queryMap.forEach((_, key) => {
708
+ this.deleteQuery(key);
709
+ });
710
+ }
711
+ }
712
+ const Context$1 = React.createContext(void 0);
713
+ const QueryClientProvider$ = React.memo(
714
+ ({
715
+ children,
716
+ client: _client2
717
+ }) => {
718
+ const [client] = React.useState(() => _client2 ?? new QueryClient$());
719
+ React.useEffect(() => {
720
+ return () => {
721
+ client.destroy();
722
+ };
723
+ }, [client]);
724
+ return /* @__PURE__ */ jsxRuntime.jsx(Context$1.Provider, { value: client, children });
725
+ }
726
+ );
727
+ const useQueryClient$ = () => {
728
+ const client = React.useContext(Context$1);
729
+ if (!client) {
730
+ throw new Error(
731
+ "useReactJrxQueryClient must be used within a ReactJrxQueryProvider"
732
+ );
733
+ }
734
+ return client;
735
+ };
655
736
  function useQuery$(options, queryClient) {
656
- const sub = React.useRef();
657
737
  const _queryClient = reactQuery.useQueryClient(queryClient);
738
+ const queryClient$ = useQueryClient$();
658
739
  const queryFnAsync = (context) => {
659
- let isResolved = false;
660
740
  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(
741
+ const getSource = () => rxjs.defer(
675
742
  () => typeof options.queryFn === "function" ? options.queryFn(context) : options.queryFn
676
743
  );
677
- sub.current = source.pipe(
678
- rxjs.finalize(() => {
679
- unsub();
680
- isResolved = true;
681
- })
744
+ const queryHash = reactQuery.hashKey(context.queryKey);
745
+ const queryCacheEntry = queryClient$.getQuery(queryHash) ?? queryClient$.setQuery(
746
+ context.queryKey,
747
+ getSource(),
748
+ context.signal
749
+ );
750
+ const query$ = queryCacheEntry.query$;
751
+ query$.pipe(
752
+ rxjs.take(1),
753
+ /**
754
+ * If several values are emitted during this delay, we will only
755
+ * keep the last value. This is unfortunate but it's the best we can do
756
+ * for now.
757
+ */
758
+ rxjs.delay(1)
682
759
  ).subscribe({
683
- next: (data) => {
684
- lastData = data;
685
- _queryClient == null ? void 0 : _queryClient.setQueryData(context.queryKey, data);
686
- },
687
760
  error: (error) => {
688
- isResolved = true;
689
- reject(error);
761
+ return reject(error);
690
762
  },
691
763
  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);
764
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.lastData) === void 0) {
765
+ console.log(
766
+ "cancelled due to stream completing without data",
767
+ queryCacheEntry == null ? void 0 : queryCacheEntry.lastData
768
+ );
769
+ _queryClient.cancelQueries({
770
+ queryKey: context.queryKey,
771
+ exact: true
772
+ });
773
+ return resolve(void 0);
774
+ }
775
+ resolve(queryCacheEntry.lastData.value);
776
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.isCompleted) === false) {
777
+ setTimeout(() => {
778
+ _queryClient == null ? void 0 : _queryClient.refetchQueries({
779
+ queryKey: context.queryKey,
780
+ exact: true
781
+ });
782
+ });
783
+ }
697
784
  }
698
785
  });
699
786
  });
@@ -3519,10 +3606,13 @@ _queryCache = new WeakMap();
3519
3606
  _mutationDefaults = new WeakMap();
3520
3607
  _queryDefaults = new WeakMap();
3521
3608
  _defaultOptions2 = new WeakMap();
3609
+ exports.Context = Context$1;
3522
3610
  exports.MutationCache = MutationCache;
3523
3611
  exports.QueryCache = QueryCache;
3524
3612
  exports.QueryClient = QueryClient;
3613
+ exports.QueryClient$ = QueryClient$;
3525
3614
  exports.QueryClientProvider = QueryClientProvider;
3615
+ exports.QueryClientProvider$ = QueryClientProvider$;
3526
3616
  exports.SIGNAL_RESET = SIGNAL_RESET;
3527
3617
  exports.arrayEqual = arrayEqual;
3528
3618
  exports.createLocalStorageAdapter = createLocalStorageAdapter;
@@ -3549,6 +3639,7 @@ exports.usePersistSignals = usePersistSignals;
3549
3639
  exports.useQuery = useQuery;
3550
3640
  exports.useQuery$ = useQuery$;
3551
3641
  exports.useQueryClient = useQueryClient;
3642
+ exports.useQueryClient$ = useQueryClient$;
3552
3643
  exports.useSignal = useSignal;
3553
3644
  exports.useSignalValue = useSignalValue;
3554
3645
  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,135 @@ 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(fromEvent(signal2, "abort")),
654
+ share()
655
+ );
656
+ const cacheEntry = {
657
+ query$: sharedQuery$,
658
+ signal: signal2,
659
+ sub: void 0,
660
+ isCompleted: false,
661
+ lastData: void 0
662
+ };
663
+ this.queryMap.set(queryHash, cacheEntry);
664
+ const sub = sharedQuery$.subscribe({
665
+ next: (data) => {
666
+ const entry = this.queryMap.get(queryHash);
667
+ if (entry) {
668
+ entry.lastData = { value: data };
669
+ }
670
+ },
671
+ complete: () => {
672
+ this.deleteQuery(queryHash);
673
+ }
674
+ });
675
+ cacheEntry.sub = sub;
676
+ return cacheEntry;
677
+ }
678
+ deleteQuery(queryHash) {
679
+ const entry = this.queryMap.get(queryHash);
680
+ if (!entry) return;
681
+ if (entry.sub) {
682
+ entry.sub.unsubscribe();
683
+ entry.sub = void 0;
684
+ }
685
+ entry.isCompleted = true;
686
+ this.queryMap.delete(queryHash);
687
+ }
688
+ destroy() {
689
+ this.queryMap.forEach((_, key) => {
690
+ this.deleteQuery(key);
691
+ });
692
+ }
693
+ }
694
+ const Context$1 = createContext(void 0);
695
+ const QueryClientProvider$ = memo(
696
+ ({
697
+ children,
698
+ client: _client2
699
+ }) => {
700
+ const [client] = useState(() => _client2 ?? new QueryClient$());
701
+ useEffect(() => {
702
+ return () => {
703
+ client.destroy();
704
+ };
705
+ }, [client]);
706
+ return /* @__PURE__ */ jsx(Context$1.Provider, { value: client, children });
707
+ }
708
+ );
709
+ const useQueryClient$ = () => {
710
+ const client = useContext(Context$1);
711
+ if (!client) {
712
+ throw new Error(
713
+ "useReactJrxQueryClient must be used within a ReactJrxQueryProvider"
714
+ );
715
+ }
716
+ return client;
717
+ };
637
718
  function useQuery$(options, queryClient) {
638
- const sub = useRef();
639
719
  const _queryClient = useQueryClient$1(queryClient);
720
+ const queryClient$ = useQueryClient$();
640
721
  const queryFnAsync = (context) => {
641
- let isResolved = false;
642
722
  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(
723
+ const getSource = () => defer(
657
724
  () => typeof options.queryFn === "function" ? options.queryFn(context) : options.queryFn
658
725
  );
659
- sub.current = source.pipe(
660
- finalize(() => {
661
- unsub();
662
- isResolved = true;
663
- })
726
+ const queryHash = hashKey$1(context.queryKey);
727
+ const queryCacheEntry = queryClient$.getQuery(queryHash) ?? queryClient$.setQuery(
728
+ context.queryKey,
729
+ getSource(),
730
+ context.signal
731
+ );
732
+ const query$ = queryCacheEntry.query$;
733
+ query$.pipe(
734
+ take(1),
735
+ /**
736
+ * If several values are emitted during this delay, we will only
737
+ * keep the last value. This is unfortunate but it's the best we can do
738
+ * for now.
739
+ */
740
+ delay(1)
664
741
  ).subscribe({
665
- next: (data) => {
666
- lastData = data;
667
- _queryClient == null ? void 0 : _queryClient.setQueryData(context.queryKey, data);
668
- },
669
742
  error: (error) => {
670
- isResolved = true;
671
- reject(error);
743
+ return reject(error);
672
744
  },
673
745
  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);
746
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.lastData) === void 0) {
747
+ console.log(
748
+ "cancelled due to stream completing without data",
749
+ queryCacheEntry == null ? void 0 : queryCacheEntry.lastData
750
+ );
751
+ _queryClient.cancelQueries({
752
+ queryKey: context.queryKey,
753
+ exact: true
754
+ });
755
+ return resolve(void 0);
756
+ }
757
+ resolve(queryCacheEntry.lastData.value);
758
+ if ((queryCacheEntry == null ? void 0 : queryCacheEntry.isCompleted) === false) {
759
+ setTimeout(() => {
760
+ _queryClient == null ? void 0 : _queryClient.refetchQueries({
761
+ queryKey: context.queryKey,
762
+ exact: true
763
+ });
764
+ });
765
+ }
679
766
  }
680
767
  });
681
768
  });
@@ -3502,10 +3589,13 @@ _mutationDefaults = new WeakMap();
3502
3589
  _queryDefaults = new WeakMap();
3503
3590
  _defaultOptions2 = new WeakMap();
3504
3591
  export {
3592
+ Context$1 as Context,
3505
3593
  MutationCache,
3506
3594
  QueryCache,
3507
3595
  QueryClient,
3596
+ QueryClient$,
3508
3597
  QueryClientProvider,
3598
+ QueryClientProvider$,
3509
3599
  SIGNAL_RESET,
3510
3600
  arrayEqual,
3511
3601
  createLocalStorageAdapter,
@@ -3532,6 +3622,7 @@ export {
3532
3622
  useQuery,
3533
3623
  useQuery$,
3534
3624
  useQueryClient,
3625
+ useQueryClient$,
3535
3626
  useSignal,
3536
3627
  useSignalValue,
3537
3628
  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.4",
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 {};