@octanejs/tanstack-query 0.1.2

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.
@@ -0,0 +1,153 @@
1
+ // `useBaseQuery` — the shared core of `useQuery` (and friends), reimplemented on
2
+ // octane's hooks. Mirrors @tanstack/react-query's useBaseQuery: it creates a
3
+ // query Observer, subscribes to it via useSyncExternalStore, and pushes option
4
+ // changes through useEffect. The single compiler-injected slot is split into
5
+ // distinct sub-slots for each internal base hook, the same way the zustand
6
+ // `traditional` binding does.
7
+ import { useState, useCallback, useSyncExternalStore, useEffect, use } from 'octane';
8
+ import { environmentManager, noop, notifyManager } from '@tanstack/query-core';
9
+ import { resolveClient } from './context';
10
+ import { useIsRestoring } from './isRestoring';
11
+ import { useQueryErrorResetBoundary } from './errorResetBoundary';
12
+ import {
13
+ ensurePreventErrorBoundaryRetry,
14
+ ensureSuspenseTimers,
15
+ fetchOptimistic,
16
+ getHasError,
17
+ shouldSuspend,
18
+ subSlot,
19
+ willFetch,
20
+ } from './internal';
21
+
22
+ export function useBaseQuery(
23
+ options: any,
24
+ Observer: any,
25
+ queryClient: any,
26
+ slot: symbol | undefined,
27
+ ): any {
28
+ if (process.env.NODE_ENV !== 'production') {
29
+ if (typeof options !== 'object' || Array.isArray(options)) {
30
+ throw new Error(
31
+ 'Bad argument type. Starting with v5, only the "Object" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',
32
+ );
33
+ }
34
+ }
35
+
36
+ const oq = (tag: string) => subSlot(slot, 'oq:' + tag);
37
+ const client = resolveClient(queryClient);
38
+ const isRestoring = useIsRestoring();
39
+ const errorResetBoundary = useQueryErrorResetBoundary();
40
+ const defaultedOptions = client.defaultQueryOptions(options);
41
+
42
+ (client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(defaultedOptions);
43
+
44
+ const query = client.getQueryCache().get(defaultedOptions.queryHash);
45
+
46
+ if (process.env.NODE_ENV !== 'production') {
47
+ if (!defaultedOptions.queryFn) {
48
+ console.error(
49
+ `[${defaultedOptions.queryHash}]: No queryFn was passed as an option, and no default queryFn was found. The queryFn parameter is only optional when using a default queryFn. More info here: https://tanstack.com/query/latest/docs/framework/react/guides/default-query-function`,
50
+ );
51
+ }
52
+ }
53
+
54
+ // `subscribed: false` makes a passive query (read the cache, never subscribe).
55
+ // While restoring a persisted client, queries also stay passive.
56
+ const subscribed = options.subscribed !== false;
57
+ defaultedOptions._optimisticResults = isRestoring
58
+ ? 'isRestoring'
59
+ : subscribed
60
+ ? 'optimistic'
61
+ : undefined;
62
+
63
+ ensureSuspenseTimers(defaultedOptions);
64
+ ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary, query);
65
+ // Clear the reset boundary on mount (so a fresh mount can throw again).
66
+ useEffect(
67
+ () => {
68
+ errorResetBoundary.clearReset();
69
+ },
70
+ [errorResetBoundary],
71
+ oq('clr'),
72
+ );
73
+
74
+ // Probed BEFORE creating the Observer — the constructor can create the entry.
75
+ const isNewCacheEntry = !client.getQueryCache().get(defaultedOptions.queryHash);
76
+
77
+ const [observer] = useState(() => new Observer(client, defaultedOptions), oq('obs'));
78
+
79
+ const result = observer.getOptimisticResult(defaultedOptions);
80
+
81
+ const shouldSubscribe = !isRestoring && subscribed;
82
+ useSyncExternalStore(
83
+ useCallback(
84
+ (onStoreChange: () => void) => {
85
+ const unsubscribe = shouldSubscribe
86
+ ? observer.subscribe(notifyManager.batchCalls(onStoreChange))
87
+ : noop;
88
+ observer.updateResult();
89
+ return unsubscribe;
90
+ },
91
+ [observer, shouldSubscribe],
92
+ oq('cb'),
93
+ ),
94
+ () => observer.getCurrentResult(),
95
+ () => observer.getCurrentResult(),
96
+ oq('uses'),
97
+ );
98
+
99
+ useEffect(
100
+ () => {
101
+ observer.setOptions(defaultedOptions);
102
+ },
103
+ [defaultedOptions, observer],
104
+ oq('eff'),
105
+ );
106
+
107
+ // Suspense: suspend on the in-flight promise via `use(thenable)` (octane's
108
+ // suspend primitive — NOT a raw `throw promise`). fetchOptimistic clears the
109
+ // reset boundary on error (upstream suspense.ts), so a reset→retry that fails
110
+ // again re-throws to the boundary on replay instead of falling through with
111
+ // undefined data. The promise resolves even on error; the replay surfaces the
112
+ // error through the error-boundary throw below.
113
+ if (shouldSuspend(defaultedOptions, result)) {
114
+ use(fetchOptimistic(defaultedOptions, observer, errorResetBoundary));
115
+ }
116
+
117
+ // Error boundary: throw so the nearest @try/@catch (or <ErrorBoundary>) handles
118
+ // it, when the query errored and the options opt into throwing.
119
+ if (
120
+ getHasError({
121
+ result,
122
+ errorResetBoundary,
123
+ throwOnError: defaultedOptions.throwOnError,
124
+ query,
125
+ suspense: defaultedOptions.suspense,
126
+ })
127
+ ) {
128
+ throw result.error;
129
+ }
130
+
131
+ (client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(defaultedOptions, result);
132
+
133
+ // experimental_prefetchInRender: kick the fetch during render so
134
+ // `result.promise` settles even if the component unmounts, and finalize the
135
+ // observer's thenable (via updateResult) when the data lands.
136
+ if (
137
+ defaultedOptions.experimental_prefetchInRender &&
138
+ !environmentManager.isServer() &&
139
+ willFetch(result, isRestoring)
140
+ ) {
141
+ const promise = isNewCacheEntry
142
+ ? // Fetch immediately on render so `.promise` resolves even on unmount.
143
+ fetchOptimistic(defaultedOptions, observer, errorResetBoundary)
144
+ : // Subscribe to the cache promise to finalize the current thenable.
145
+ query?.promise;
146
+
147
+ promise?.catch(noop).finally(() => {
148
+ observer.updateResult();
149
+ });
150
+ }
151
+
152
+ return !defaultedOptions.notifyOnChangeProps ? observer.trackResult(result) : result;
153
+ }
@@ -0,0 +1,52 @@
1
+ import { InfiniteQueryObserver } from '@tanstack/query-core';
2
+ import type { DefaultError, InfiniteData, QueryClient, QueryKey } from '@tanstack/query-core';
3
+ import { useBaseQuery } from './useBaseQuery';
4
+ import { splitSlot } from './internal';
5
+ import type {
6
+ DefinedUseInfiniteQueryResult,
7
+ UseInfiniteQueryOptions,
8
+ UseInfiniteQueryResult,
9
+ } from './types';
10
+ import type {
11
+ DefinedInitialDataInfiniteOptions,
12
+ UndefinedInitialDataInfiniteOptions,
13
+ } from './infiniteQueryOptions';
14
+
15
+ // Overloads match @tanstack/react-query's useInfiniteQuery.ts.
16
+ export function useInfiniteQuery<
17
+ TQueryFnData,
18
+ TError = DefaultError,
19
+ TData = InfiniteData<TQueryFnData>,
20
+ TQueryKey extends QueryKey = QueryKey,
21
+ TPageParam = unknown,
22
+ >(
23
+ options: DefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
24
+ queryClient?: QueryClient,
25
+ ): DefinedUseInfiniteQueryResult<TData, TError>;
26
+
27
+ export function useInfiniteQuery<
28
+ TQueryFnData,
29
+ TError = DefaultError,
30
+ TData = InfiniteData<TQueryFnData>,
31
+ TQueryKey extends QueryKey = QueryKey,
32
+ TPageParam = unknown,
33
+ >(
34
+ options: UndefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
35
+ queryClient?: QueryClient,
36
+ ): UseInfiniteQueryResult<TData, TError>;
37
+
38
+ export function useInfiniteQuery<
39
+ TQueryFnData,
40
+ TError = DefaultError,
41
+ TData = InfiniteData<TQueryFnData>,
42
+ TQueryKey extends QueryKey = QueryKey,
43
+ TPageParam = unknown,
44
+ >(
45
+ options: UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
46
+ queryClient?: QueryClient,
47
+ ): UseInfiniteQueryResult<TData, TError>;
48
+
49
+ export function useInfiniteQuery(options: any, ...rest: any[]): any {
50
+ const [user, slot] = splitSlot(rest);
51
+ return useBaseQuery(options, InfiniteQueryObserver, user[0], slot);
52
+ }
@@ -0,0 +1,25 @@
1
+ import { notifyManager } from '@tanstack/query-core';
2
+ import type { QueryClient, QueryFilters } from '@tanstack/query-core';
3
+ import { useSyncExternalStore, useCallback } from 'octane';
4
+ import { resolveClient } from './context';
5
+ import { splitSlot, subSlot } from './internal';
6
+
7
+ // Signature matches @tanstack/react-query's useIsFetching.ts.
8
+ export function useIsFetching(filters?: QueryFilters, queryClient?: QueryClient): number;
9
+
10
+ export function useIsFetching(...args: any[]): number {
11
+ const [user, slot] = splitSlot(args);
12
+ const filters = user[0];
13
+ const client = resolveClient(user[1]);
14
+ const queryCache = client.getQueryCache();
15
+ return useSyncExternalStore(
16
+ useCallback(
17
+ (onStoreChange: () => void) => queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),
18
+ [queryCache],
19
+ subSlot(slot, 'if:cb'),
20
+ ),
21
+ () => client.isFetching(filters),
22
+ () => client.isFetching(filters),
23
+ subSlot(slot, 'if:uses'),
24
+ );
25
+ }
@@ -0,0 +1,65 @@
1
+ // `useMutation` — reimplemented on octane's hooks, mirroring
2
+ // @tanstack/react-query: a MutationObserver subscribed via useSyncExternalStore,
3
+ // with a stable `mutate` callback. The single compiler-injected slot is split
4
+ // into distinct sub-slots for each internal base hook.
5
+ import { useState, useCallback, useSyncExternalStore, useEffect } from 'octane';
6
+ import { MutationObserver, noop, notifyManager, shouldThrowError } from '@tanstack/query-core';
7
+ import type { DefaultError, QueryClient } from '@tanstack/query-core';
8
+ import { resolveClient } from './context';
9
+ import { splitSlot, subSlot as subSlotBase } from './internal';
10
+ import type { UseMutationOptions, UseMutationResult } from './types';
11
+
12
+ // Namespaced per-hook (':om:') on top of the shared helper — the minted symbols
13
+ // are byte-identical to the previous private copy, so slot identity is stable.
14
+ const subSlot = (slot: symbol | undefined, tag: string) => subSlotBase(slot, 'om:' + tag);
15
+
16
+ // Signature matches @tanstack/react-query's useMutation.ts.
17
+ export function useMutation<
18
+ TData = unknown,
19
+ TError = DefaultError,
20
+ TVariables = void,
21
+ TOnMutateResult = unknown,
22
+ >(
23
+ options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>,
24
+ queryClient?: QueryClient,
25
+ ): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;
26
+
27
+ export function useMutation(options: any, ...rest: any[]): any {
28
+ const [user, slot] = splitSlot(rest);
29
+ const client = resolveClient(user[0]);
30
+
31
+ const [observer] = useState(() => new MutationObserver(client, options), subSlot(slot, 'obs'));
32
+
33
+ useEffect(
34
+ () => {
35
+ observer.setOptions(options);
36
+ },
37
+ [observer, options],
38
+ subSlot(slot, 'eff'),
39
+ );
40
+
41
+ const result = useSyncExternalStore(
42
+ useCallback(
43
+ (onStoreChange: () => void) => observer.subscribe(notifyManager.batchCalls(onStoreChange)),
44
+ [observer],
45
+ subSlot(slot, 'cb'),
46
+ ),
47
+ () => observer.getCurrentResult(),
48
+ () => observer.getCurrentResult(),
49
+ subSlot(slot, 'uses'),
50
+ );
51
+
52
+ const mutate = useCallback(
53
+ (variables: any, mutateOptions: any) => {
54
+ observer.mutate(variables, mutateOptions).catch(noop);
55
+ },
56
+ [observer],
57
+ subSlot(slot, 'mut'),
58
+ );
59
+
60
+ if (result.error && shouldThrowError(observer.options.throwOnError, [result.error])) {
61
+ throw result.error;
62
+ }
63
+
64
+ return { ...result, mutate, mutateAsync: result.mutate };
65
+ }
@@ -0,0 +1,78 @@
1
+ import { notifyManager, replaceEqualDeep } from '@tanstack/query-core';
2
+ import type { Mutation, MutationFilters, MutationState, QueryClient } from '@tanstack/query-core';
3
+ import { useSyncExternalStore, useCallback, useRef, useEffect } from 'octane';
4
+ import { resolveClient } from './context';
5
+ import { splitSlot, subSlot } from './internal';
6
+
7
+ // Per upstream useMutationState.ts (kept module-private there too).
8
+ type MutationStateOptions<TResult = MutationState> = {
9
+ filters?: MutationFilters;
10
+ select?: (mutation: Mutation) => TResult;
11
+ };
12
+
13
+ function getResult(mutationCache: any, options: any): any[] {
14
+ return mutationCache
15
+ .findAll(options.filters)
16
+ .map((mutation: any) => (options.select ? options.select(mutation) : mutation.state));
17
+ }
18
+
19
+ // Signatures match @tanstack/react-query's useMutationState.ts.
20
+ export function useMutationState<TResult = MutationState>(
21
+ options?: MutationStateOptions<TResult>,
22
+ queryClient?: QueryClient,
23
+ ): Array<TResult>;
24
+
25
+ export function useMutationState(...args: any[]): any[] {
26
+ const [user, slot] = splitSlot(args);
27
+ const options = user[0] ?? {};
28
+ const mutationCache = resolveClient(user[1]).getMutationCache();
29
+
30
+ const optionsRef = useRef(options, subSlot(slot, 'ms:opt'));
31
+ const result = useRef<any[] | null>(null, subSlot(slot, 'ms:res'));
32
+ if (result.current === null) {
33
+ result.current = getResult(mutationCache, options);
34
+ }
35
+ useEffect(
36
+ () => {
37
+ optionsRef.current = options;
38
+ },
39
+ undefined,
40
+ subSlot(slot, 'ms:eff'),
41
+ );
42
+
43
+ return useSyncExternalStore(
44
+ useCallback(
45
+ (onStoreChange: () => void) =>
46
+ mutationCache.subscribe(() => {
47
+ const next = replaceEqualDeep(
48
+ result.current,
49
+ getResult(mutationCache, optionsRef.current),
50
+ );
51
+ if (result.current !== next) {
52
+ result.current = next;
53
+ notifyManager.schedule(onStoreChange);
54
+ }
55
+ }),
56
+ [mutationCache],
57
+ subSlot(slot, 'ms:cb'),
58
+ ),
59
+ () => result.current as any[],
60
+ () => result.current as any[],
61
+ subSlot(slot, 'ms:uses'),
62
+ );
63
+ }
64
+
65
+ // Signature matches @tanstack/react-query's useMutationState.ts.
66
+ export function useIsMutating(filters?: MutationFilters, queryClient?: QueryClient): number;
67
+
68
+ export function useIsMutating(...args: any[]): number {
69
+ const [user, slot] = splitSlot(args);
70
+ const filters = user[0];
71
+ const client = resolveClient(user[1]);
72
+ // Forward this hook's slot to useMutationState (it owns the base hooks).
73
+ return (useMutationState as (...a: any[]) => any[])(
74
+ { filters: { ...filters, status: 'pending' } },
75
+ client,
76
+ slot,
77
+ ).length;
78
+ }
@@ -0,0 +1,48 @@
1
+ import type {
2
+ DefaultError,
3
+ FetchInfiniteQueryOptions,
4
+ QueryClient,
5
+ QueryKey,
6
+ } from '@tanstack/query-core';
7
+ import { resolveClient } from './context';
8
+ import { splitSlot } from './internal';
9
+ import type { UsePrefetchQueryOptions } from './types';
10
+
11
+ // Signatures match @tanstack/react-query's usePrefetchQuery.tsx /
12
+ // usePrefetchInfiniteQuery.tsx.
13
+ export function usePrefetchQuery<
14
+ TQueryFnData = unknown,
15
+ TError = DefaultError,
16
+ TData = TQueryFnData,
17
+ TQueryKey extends QueryKey = QueryKey,
18
+ >(
19
+ options: UsePrefetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
20
+ queryClient?: QueryClient,
21
+ ): void;
22
+
23
+ export function usePrefetchQuery(options: any, ...rest: any[]): void {
24
+ const [user] = splitSlot(rest);
25
+ const client = resolveClient(user[0]);
26
+ if (!client.getQueryState(options.queryKey)) {
27
+ client.prefetchQuery(options);
28
+ }
29
+ }
30
+
31
+ export function usePrefetchInfiniteQuery<
32
+ TQueryFnData = unknown,
33
+ TError = DefaultError,
34
+ TData = TQueryFnData,
35
+ TQueryKey extends QueryKey = QueryKey,
36
+ TPageParam = unknown,
37
+ >(
38
+ options: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
39
+ queryClient?: QueryClient,
40
+ ): void;
41
+
42
+ export function usePrefetchInfiniteQuery(options: any, ...rest: any[]): void {
43
+ const [user] = splitSlot(rest);
44
+ const client = resolveClient(user[0]);
45
+ if (!client.getQueryState(options.queryKey)) {
46
+ client.prefetchInfiniteQuery(options);
47
+ }
48
+ }
@@ -0,0 +1,134 @@
1
+ import { QueriesObserver, QueryObserver, noop, notifyManager } from '@tanstack/query-core';
2
+ import type { QueryClient } from '@tanstack/query-core';
3
+ import { useState, useMemo, useSyncExternalStore, useCallback, useEffect, use } from 'octane';
4
+ import { resolveClient } from './context';
5
+ import { useIsRestoring } from './isRestoring';
6
+ import { useQueryErrorResetBoundary } from './errorResetBoundary';
7
+ import {
8
+ ensurePreventErrorBoundaryRetry,
9
+ ensureSuspenseTimers,
10
+ fetchOptimistic,
11
+ getHasError,
12
+ shouldSuspend,
13
+ splitSlot,
14
+ subSlot,
15
+ } from './internal';
16
+ import type { QueriesOptions, QueriesResults } from './queries-types';
17
+
18
+ // Signature matches @tanstack/react-query's useQueries.ts — per-entry tuple
19
+ // inference via QueriesOptions/QueriesResults, with `combine` re-typing the
20
+ // aggregate result. The untyped implementation signature also accepts the
21
+ // compiler-injected trailing slot symbol.
22
+ export function useQueries<T extends Array<any>, TCombinedResult = QueriesResults<T>>(
23
+ options: {
24
+ queries: readonly [...QueriesOptions<T>];
25
+ combine?: (result: QueriesResults<T>) => TCombinedResult;
26
+ subscribed?: boolean;
27
+ },
28
+ queryClient?: QueryClient,
29
+ ): TCombinedResult;
30
+
31
+ export function useQueries(options: any, ...rest: any[]): any {
32
+ const [user, slot] = splitSlot(rest);
33
+ const client = resolveClient(user[0]);
34
+ const isRestoring = useIsRestoring();
35
+ const errorResetBoundary = useQueryErrorResetBoundary();
36
+ const { queries, ...restOptions } = options;
37
+ const qs = (tag: string) => subSlot(slot, 'qs:' + tag);
38
+
39
+ const defaultedQueries = useMemo(
40
+ () =>
41
+ queries.map((opts: any) => {
42
+ const defaulted = client.defaultQueryOptions(opts);
43
+ defaulted._optimisticResults = isRestoring ? 'isRestoring' : 'optimistic';
44
+ return defaulted;
45
+ }),
46
+ [queries, client, isRestoring],
47
+ qs('memo'),
48
+ );
49
+ defaultedQueries.forEach((queryOptions: any) => {
50
+ ensureSuspenseTimers(queryOptions);
51
+ ensurePreventErrorBoundaryRetry(
52
+ queryOptions,
53
+ errorResetBoundary,
54
+ client.getQueryCache().get(queryOptions.queryHash),
55
+ );
56
+ });
57
+ useEffect(
58
+ () => {
59
+ errorResetBoundary.clearReset();
60
+ },
61
+ [errorResetBoundary],
62
+ qs('clr'),
63
+ );
64
+
65
+ const [observer] = useState(
66
+ () => new QueriesObserver(client, defaultedQueries, restOptions),
67
+ qs('obs'),
68
+ );
69
+
70
+ const [optimisticResult, getCombinedResult, trackResult] = observer.getOptimisticResult(
71
+ defaultedQueries,
72
+ restOptions.combine,
73
+ );
74
+
75
+ const shouldSubscribe = !isRestoring && restOptions.subscribed !== false;
76
+ useSyncExternalStore(
77
+ useCallback(
78
+ (onStoreChange: () => void) =>
79
+ shouldSubscribe ? observer.subscribe(notifyManager.batchCalls(onStoreChange)) : noop,
80
+ [observer, shouldSubscribe],
81
+ qs('cb'),
82
+ ),
83
+ () => observer.getCurrentResult(),
84
+ () => observer.getCurrentResult(),
85
+ qs('uses'),
86
+ );
87
+
88
+ useEffect(
89
+ () => {
90
+ observer.setQueries(defaultedQueries, restOptions);
91
+ },
92
+ [defaultedQueries, restOptions, observer],
93
+ qs('eff'),
94
+ );
95
+
96
+ // Suspense: if any query should suspend, suspend on Promise.all of their
97
+ // optimistic fetches. octane suspends via use(thenable), not `throw promise`.
98
+ const shouldAtLeastOneSuspend = optimisticResult.some((result: any, index: number) =>
99
+ shouldSuspend(defaultedQueries[index], result),
100
+ );
101
+ if (shouldAtLeastOneSuspend) {
102
+ const suspensePromises = optimisticResult.flatMap((result: any, index: number) => {
103
+ const opts = defaultedQueries[index];
104
+ if (opts && shouldSuspend(opts, result)) {
105
+ // fetchOptimistic clears the reset boundary on error (upstream
106
+ // suspense.ts) so a reset→retry→fail-again re-throws to the boundary.
107
+ return fetchOptimistic(opts, new QueryObserver(client, opts), errorResetBoundary);
108
+ }
109
+ return [];
110
+ });
111
+ if (suspensePromises.length > 0) {
112
+ use(Promise.all(suspensePromises));
113
+ }
114
+ }
115
+
116
+ const firstError = optimisticResult.find((result: any, index: number) => {
117
+ const query = defaultedQueries[index];
118
+ return (
119
+ query &&
120
+ getHasError({
121
+ result,
122
+ errorResetBoundary,
123
+ throwOnError: query.throwOnError,
124
+ query: client.getQueryCache().get(query.queryHash),
125
+ suspense: query.suspense,
126
+ })
127
+ );
128
+ });
129
+ if (firstError?.error) {
130
+ throw firstError.error;
131
+ }
132
+
133
+ return getCombinedResult(trackResult());
134
+ }
@@ -0,0 +1,47 @@
1
+ import { QueryObserver } from '@tanstack/query-core';
2
+ import type { DefaultError, QueryClient, QueryKey } from '@tanstack/query-core';
3
+ import { useBaseQuery } from './useBaseQuery';
4
+ import type { DefinedUseQueryResult, UseQueryOptions, UseQueryResult } from './types';
5
+ import type { DefinedInitialDataOptions, UndefinedInitialDataOptions } from './queryOptions';
6
+
7
+ // Overloads match @tanstack/react-query's useQuery.ts: `initialData` narrows the
8
+ // result to DefinedUseQueryResult. The untyped implementation signature also
9
+ // accepts the compiler-injected trailing slot symbol (never visible to users).
10
+ export function useQuery<
11
+ TQueryFnData = unknown,
12
+ TError = DefaultError,
13
+ TData = TQueryFnData,
14
+ TQueryKey extends QueryKey = QueryKey,
15
+ >(
16
+ options: DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
17
+ queryClient?: QueryClient,
18
+ ): DefinedUseQueryResult<NoInfer<TData>, TError>;
19
+
20
+ export function useQuery<
21
+ TQueryFnData = unknown,
22
+ TError = DefaultError,
23
+ TData = TQueryFnData,
24
+ TQueryKey extends QueryKey = QueryKey,
25
+ >(
26
+ options: UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
27
+ queryClient?: QueryClient,
28
+ ): UseQueryResult<NoInfer<TData>, TError>;
29
+
30
+ export function useQuery<
31
+ TQueryFnData = unknown,
32
+ TError = DefaultError,
33
+ TData = TQueryFnData,
34
+ TQueryKey extends QueryKey = QueryKey,
35
+ >(
36
+ options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
37
+ queryClient?: QueryClient,
38
+ ): UseQueryResult<NoInfer<TData>, TError>;
39
+
40
+ export function useQuery(options: any, ...rest: any[]): any {
41
+ // `[queryClient?, slot?]` — the slot (symbol) is the compiler-injected trailing
42
+ // arg; an explicit client is the first non-symbol arg.
43
+ const tail = rest[rest.length - 1];
44
+ const slot = typeof tail === 'symbol' ? (tail as symbol) : undefined;
45
+ const queryClient = typeof rest[0] !== 'symbol' ? rest[0] : undefined;
46
+ return useBaseQuery(options, QueryObserver, queryClient, slot);
47
+ }
@@ -0,0 +1,38 @@
1
+ import { skipToken } from '@tanstack/query-core';
2
+ import type { QueryClient } from '@tanstack/query-core';
3
+ import { defaultThrowOnError } from './internal';
4
+ import { useQueries } from './useQueries';
5
+ import type { SuspenseQueriesOptions, SuspenseQueriesResults } from './suspense-queries-types';
6
+
7
+ // Signature matches @tanstack/react-query's useSuspenseQueries.ts.
8
+ export function useSuspenseQueries<
9
+ T extends Array<any>,
10
+ TCombinedResult = SuspenseQueriesResults<T>,
11
+ >(
12
+ options: {
13
+ queries: readonly [...SuspenseQueriesOptions<T>];
14
+ combine?: (result: SuspenseQueriesResults<T>) => TCombinedResult;
15
+ },
16
+ queryClient?: QueryClient,
17
+ ): TCombinedResult;
18
+
19
+ export function useSuspenseQueries(options: any, ...rest: any[]): any {
20
+ return useQueries(
21
+ {
22
+ ...options,
23
+ queries: options.queries.map((query: any) => {
24
+ if (process.env.NODE_ENV !== 'production' && query.queryFn === skipToken) {
25
+ console.error('skipToken is not allowed for useSuspenseQueries');
26
+ }
27
+ return {
28
+ ...query,
29
+ suspense: true,
30
+ throwOnError: defaultThrowOnError,
31
+ enabled: true,
32
+ placeholderData: undefined,
33
+ };
34
+ }),
35
+ },
36
+ ...rest,
37
+ );
38
+ }