@trpc/react-query 10.0.0-proxy-beta.21
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/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/createHooksInternal-b47ee704.mjs +392 -0
- package/dist/createHooksInternal-e8214d72.js +400 -0
- package/dist/createTRPCReact.d.ts +38 -0
- package/dist/createTRPCReact.d.ts.map +1 -0
- package/dist/getArrayQueryKey-062214e0.mjs +19 -0
- package/dist/getArrayQueryKey-a2092b3c.js +21 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.mjs +47 -0
- package/dist/internals/context.d.ts +99 -0
- package/dist/internals/context.d.ts.map +1 -0
- package/dist/internals/getArrayQueryKey.d.ts +9 -0
- package/dist/internals/getArrayQueryKey.d.ts.map +1 -0
- package/dist/internals/getQueryKey.d.ts +6 -0
- package/dist/internals/getQueryKey.d.ts.map +1 -0
- package/dist/interop.d.ts +10 -0
- package/dist/interop.d.ts.map +1 -0
- package/dist/queryClient-0569f6e0.mjs +7 -0
- package/dist/queryClient-83576230.js +9 -0
- package/dist/shared/hooks/createHooksInternal.d.ts +115 -0
- package/dist/shared/hooks/createHooksInternal.d.ts.map +1 -0
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +18 -0
- package/dist/shared/index.mjs +7 -0
- package/dist/shared/proxy/decorationProxy.d.ts +8 -0
- package/dist/shared/proxy/decorationProxy.d.ts.map +1 -0
- package/dist/shared/proxy/utilsProxy.d.ts +80 -0
- package/dist/shared/proxy/utilsProxy.d.ts.map +1 -0
- package/dist/shared/queryClient.d.ts +16 -0
- package/dist/shared/queryClient.d.ts.map +1 -0
- package/dist/shared/types.d.ts +26 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/ssg/index.d.ts +5 -0
- package/dist/ssg/index.d.ts.map +1 -0
- package/dist/ssg/index.js +126 -0
- package/dist/ssg/index.mjs +121 -0
- package/dist/ssg/ssg.d.ts +23 -0
- package/dist/ssg/ssg.d.ts.map +1 -0
- package/dist/ssg/ssgProxy.d.ts +36 -0
- package/dist/ssg/ssgProxy.d.ts.map +1 -0
- package/package.json +75 -0
- package/shared/index.d.ts +1 -0
- package/shared/index.js +1 -0
- package/src/createTRPCReact.tsx +164 -0
- package/src/index.ts +4 -0
- package/src/internals/context.tsx +235 -0
- package/src/internals/getArrayQueryKey.test.ts +41 -0
- package/src/internals/getArrayQueryKey.ts +18 -0
- package/src/internals/getQueryKey.ts +10 -0
- package/src/interop.ts +25 -0
- package/src/shared/hooks/createHooksInternal.tsx +664 -0
- package/src/shared/index.ts +8 -0
- package/src/shared/proxy/decorationProxy.ts +33 -0
- package/src/shared/proxy/utilsProxy.ts +266 -0
- package/src/shared/queryClient.ts +20 -0
- package/src/shared/types.ts +27 -0
- package/src/ssg/index.ts +4 -0
- package/src/ssg/ssg.ts +138 -0
- package/src/ssg/ssgProxy.ts +105 -0
- package/ssg/index.d.ts +1 -0
- package/ssg/index.js +1 -0
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import {
|
|
3
|
+
DehydratedState,
|
|
4
|
+
UseInfiniteQueryOptions,
|
|
5
|
+
UseInfiniteQueryResult,
|
|
6
|
+
UseMutationOptions,
|
|
7
|
+
UseMutationResult,
|
|
8
|
+
UseQueryOptions,
|
|
9
|
+
UseQueryResult,
|
|
10
|
+
useInfiniteQuery as __useInfiniteQuery,
|
|
11
|
+
useMutation as __useMutation,
|
|
12
|
+
useQuery as __useQuery,
|
|
13
|
+
hashQueryKey,
|
|
14
|
+
useQueryClient,
|
|
15
|
+
} from '@tanstack/react-query';
|
|
16
|
+
import {
|
|
17
|
+
CreateTRPCClientOptions,
|
|
18
|
+
TRPCClient,
|
|
19
|
+
TRPCClientErrorLike,
|
|
20
|
+
TRPCRequestOptions,
|
|
21
|
+
createTRPCClient,
|
|
22
|
+
} from '@trpc/client';
|
|
23
|
+
import type {
|
|
24
|
+
AnyRouter,
|
|
25
|
+
ProcedureRecord,
|
|
26
|
+
inferHandlerInput,
|
|
27
|
+
inferProcedureClientError,
|
|
28
|
+
inferProcedureInput,
|
|
29
|
+
inferProcedureOutput,
|
|
30
|
+
inferSubscriptionOutput,
|
|
31
|
+
} from '@trpc/server';
|
|
32
|
+
import { inferObservableValue } from '@trpc/server/observable';
|
|
33
|
+
import React, {
|
|
34
|
+
ReactNode,
|
|
35
|
+
useCallback,
|
|
36
|
+
useEffect,
|
|
37
|
+
useMemo,
|
|
38
|
+
useRef,
|
|
39
|
+
useState,
|
|
40
|
+
} from 'react';
|
|
41
|
+
import {
|
|
42
|
+
SSRState,
|
|
43
|
+
TRPCContext,
|
|
44
|
+
TRPCContextProps,
|
|
45
|
+
TRPCContextState,
|
|
46
|
+
} from '../../internals/context';
|
|
47
|
+
import { getArrayQueryKey } from '../../internals/getArrayQueryKey';
|
|
48
|
+
import { CreateTRPCReactOptions, UseMutationOverride } from '../types';
|
|
49
|
+
|
|
50
|
+
export type OutputWithCursor<TData, TCursor = any> = {
|
|
51
|
+
cursor: TCursor | null;
|
|
52
|
+
data: TData;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export interface TRPCReactRequestOptions
|
|
56
|
+
// For RQ, we use their internal AbortSignals instead of letting the user pass their own
|
|
57
|
+
extends Omit<TRPCRequestOptions, 'signal'> {
|
|
58
|
+
/**
|
|
59
|
+
* Opt out of SSR for this query by passing `ssr: false`
|
|
60
|
+
*/
|
|
61
|
+
ssr?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Opt out or into aborting request on unmount
|
|
64
|
+
*/
|
|
65
|
+
abortOnUnmount?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface TRPCUseQueryBaseOptions {
|
|
69
|
+
/**
|
|
70
|
+
* tRPC-related options
|
|
71
|
+
*/
|
|
72
|
+
trpc?: TRPCReactRequestOptions;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type { TRPCContext, TRPCContextState } from '../../internals/context';
|
|
76
|
+
|
|
77
|
+
export interface UseTRPCQueryOptions<TPath, TInput, TOutput, TData, TError>
|
|
78
|
+
extends UseQueryOptions<TOutput, TError, TData, [TPath, TInput]>,
|
|
79
|
+
TRPCUseQueryBaseOptions {}
|
|
80
|
+
|
|
81
|
+
export interface UseTRPCInfiniteQueryOptions<TPath, TInput, TOutput, TError>
|
|
82
|
+
extends UseInfiniteQueryOptions<
|
|
83
|
+
TOutput,
|
|
84
|
+
TError,
|
|
85
|
+
TOutput,
|
|
86
|
+
TOutput,
|
|
87
|
+
[TPath, TInput]
|
|
88
|
+
>,
|
|
89
|
+
TRPCUseQueryBaseOptions {}
|
|
90
|
+
|
|
91
|
+
export interface UseTRPCMutationOptions<
|
|
92
|
+
TInput,
|
|
93
|
+
TError,
|
|
94
|
+
TOutput,
|
|
95
|
+
TContext = unknown,
|
|
96
|
+
> extends UseMutationOptions<TOutput, TError, TInput, TContext>,
|
|
97
|
+
TRPCUseQueryBaseOptions {}
|
|
98
|
+
|
|
99
|
+
export interface UseTRPCSubscriptionOptions<TOutput, TError> {
|
|
100
|
+
enabled?: boolean;
|
|
101
|
+
onStarted?: () => void;
|
|
102
|
+
onData: (data: TOutput) => void;
|
|
103
|
+
onError?: (err: TError) => void;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getClientArgs<TPathAndInput extends unknown[], TOptions>(
|
|
107
|
+
pathAndInput: TPathAndInput,
|
|
108
|
+
opts: TOptions,
|
|
109
|
+
) {
|
|
110
|
+
const [path, input] = pathAndInput;
|
|
111
|
+
return [path, input, (opts as any)?.trpc] as const;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type inferInfiniteQueryNames<TObj extends ProcedureRecord> = {
|
|
115
|
+
[TPath in keyof TObj]: inferProcedureInput<TObj[TPath]> extends {
|
|
116
|
+
cursor?: any;
|
|
117
|
+
}
|
|
118
|
+
? TPath
|
|
119
|
+
: never;
|
|
120
|
+
}[keyof TObj];
|
|
121
|
+
|
|
122
|
+
type inferProcedures<TObj extends ProcedureRecord> = {
|
|
123
|
+
[TPath in keyof TObj]: {
|
|
124
|
+
input: inferProcedureInput<TObj[TPath]>;
|
|
125
|
+
output: inferProcedureOutput<TObj[TPath]>;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export interface TRPCProviderProps<TRouter extends AnyRouter, TSSRContext>
|
|
130
|
+
extends TRPCContextProps<TRouter, TSSRContext> {
|
|
131
|
+
children: ReactNode;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export type TRPCProvider<TRouter extends AnyRouter, TSSRContext> = (
|
|
135
|
+
props: TRPCProviderProps<TRouter, TSSRContext>,
|
|
136
|
+
) => JSX.Element;
|
|
137
|
+
|
|
138
|
+
export type UseDehydratedState<TRouter extends AnyRouter> = (
|
|
139
|
+
client: TRPCClient<TRouter>,
|
|
140
|
+
trpcState: DehydratedState | undefined,
|
|
141
|
+
) => DehydratedState | undefined;
|
|
142
|
+
|
|
143
|
+
export type CreateClient<TRouter extends AnyRouter> = (
|
|
144
|
+
opts: CreateTRPCClientOptions<TRouter>,
|
|
145
|
+
) => TRPCClient<TRouter>;
|
|
146
|
+
|
|
147
|
+
interface TRPCHookResult {
|
|
148
|
+
trpc: {
|
|
149
|
+
path: string;
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
export type UseTRPCQueryResult<TData, TError> = UseQueryResult<TData, TError> &
|
|
157
|
+
TRPCHookResult;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
export type UseTRPCInfiniteQueryResult<TData, TError> = UseInfiniteQueryResult<
|
|
163
|
+
TData,
|
|
164
|
+
TError
|
|
165
|
+
> &
|
|
166
|
+
TRPCHookResult;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @internal
|
|
170
|
+
*/
|
|
171
|
+
export type UseTRPCMutationResult<TData, TError, TVariables, TContext> =
|
|
172
|
+
UseMutationResult<TData, TError, TVariables, TContext> & TRPCHookResult;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Makes a stable reference of the `trpc` prop
|
|
176
|
+
*/
|
|
177
|
+
function useHookResult(value: TRPCHookResult['trpc']): TRPCHookResult['trpc'] {
|
|
178
|
+
const ref = useRef(value);
|
|
179
|
+
ref.current.path = value.path;
|
|
180
|
+
return ref.current;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Create strongly typed react hooks
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
186
|
+
export function createHooksInternal<
|
|
187
|
+
TRouter extends AnyRouter,
|
|
188
|
+
TSSRContext = unknown,
|
|
189
|
+
>(config?: CreateTRPCReactOptions<TRouter>) {
|
|
190
|
+
const mutationSuccessOverride: UseMutationOverride['onSuccess'] =
|
|
191
|
+
config?.unstable_overrides?.useMutation?.onSuccess ??
|
|
192
|
+
((options) => options.originalFn());
|
|
193
|
+
|
|
194
|
+
type TQueries = TRouter['_def']['queries'];
|
|
195
|
+
type TSubscriptions = TRouter['_def']['subscriptions'];
|
|
196
|
+
type TMutations = TRouter['_def']['mutations'];
|
|
197
|
+
|
|
198
|
+
type TError = TRPCClientErrorLike<TRouter>;
|
|
199
|
+
type TInfiniteQueryNames = inferInfiniteQueryNames<TQueries>;
|
|
200
|
+
|
|
201
|
+
type TQueryValues = inferProcedures<TQueries>;
|
|
202
|
+
type TMutationValues = inferProcedures<TMutations>;
|
|
203
|
+
|
|
204
|
+
type ProviderContext = TRPCContextState<TRouter, TSSRContext>;
|
|
205
|
+
const Context = TRPCContext as React.Context<ProviderContext>;
|
|
206
|
+
|
|
207
|
+
const createClient: CreateClient<TRouter> = (opts) => {
|
|
208
|
+
return createTRPCClient(opts);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const TRPCProvider: TRPCProvider<TRouter, TSSRContext> = (props) => {
|
|
212
|
+
const { abortOnUnmount = false, client, queryClient, ssrContext } = props;
|
|
213
|
+
const [ssrState, setSSRState] = useState<SSRState>(props.ssrState ?? false);
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
// Only updating state to `mounted` if we are using SSR.
|
|
216
|
+
// This makes it so we don't have an unnecessary re-render when opting out of SSR.
|
|
217
|
+
setSSRState((state) => (state ? 'mounted' : false));
|
|
218
|
+
}, []);
|
|
219
|
+
return (
|
|
220
|
+
<Context.Provider
|
|
221
|
+
value={{
|
|
222
|
+
abortOnUnmount,
|
|
223
|
+
queryClient,
|
|
224
|
+
client,
|
|
225
|
+
ssrContext: ssrContext || null,
|
|
226
|
+
ssrState,
|
|
227
|
+
fetchQuery: useCallback(
|
|
228
|
+
(pathAndInput, opts) => {
|
|
229
|
+
return queryClient.fetchQuery(
|
|
230
|
+
getArrayQueryKey(pathAndInput),
|
|
231
|
+
() =>
|
|
232
|
+
(client as any).query(...getClientArgs(pathAndInput, opts)),
|
|
233
|
+
opts,
|
|
234
|
+
);
|
|
235
|
+
},
|
|
236
|
+
[client, queryClient],
|
|
237
|
+
),
|
|
238
|
+
fetchInfiniteQuery: useCallback(
|
|
239
|
+
(pathAndInput, opts) => {
|
|
240
|
+
return queryClient.fetchInfiniteQuery(
|
|
241
|
+
getArrayQueryKey(pathAndInput),
|
|
242
|
+
({ pageParam }) => {
|
|
243
|
+
const [path, input] = pathAndInput;
|
|
244
|
+
const actualInput = { ...(input as any), cursor: pageParam };
|
|
245
|
+
return (client as any).query(
|
|
246
|
+
...getClientArgs([path, actualInput], opts),
|
|
247
|
+
);
|
|
248
|
+
},
|
|
249
|
+
opts,
|
|
250
|
+
);
|
|
251
|
+
},
|
|
252
|
+
[client, queryClient],
|
|
253
|
+
),
|
|
254
|
+
prefetchQuery: useCallback(
|
|
255
|
+
(pathAndInput, opts) => {
|
|
256
|
+
return queryClient.prefetchQuery(
|
|
257
|
+
getArrayQueryKey(pathAndInput),
|
|
258
|
+
() =>
|
|
259
|
+
(client as any).query(...getClientArgs(pathAndInput, opts)),
|
|
260
|
+
opts,
|
|
261
|
+
);
|
|
262
|
+
},
|
|
263
|
+
[client, queryClient],
|
|
264
|
+
),
|
|
265
|
+
prefetchInfiniteQuery: useCallback(
|
|
266
|
+
(pathAndInput, opts) => {
|
|
267
|
+
return queryClient.prefetchInfiniteQuery(
|
|
268
|
+
getArrayQueryKey(pathAndInput),
|
|
269
|
+
({ pageParam }) => {
|
|
270
|
+
const [path, input] = pathAndInput;
|
|
271
|
+
const actualInput = { ...(input as any), cursor: pageParam };
|
|
272
|
+
return (client as any).query(
|
|
273
|
+
...getClientArgs([path, actualInput], opts),
|
|
274
|
+
);
|
|
275
|
+
},
|
|
276
|
+
opts,
|
|
277
|
+
);
|
|
278
|
+
},
|
|
279
|
+
[client, queryClient],
|
|
280
|
+
),
|
|
281
|
+
invalidateQueries: useCallback(
|
|
282
|
+
(...args: any[]) => {
|
|
283
|
+
const [queryKey, ...rest] = args;
|
|
284
|
+
return queryClient.invalidateQueries(
|
|
285
|
+
getArrayQueryKey(queryKey),
|
|
286
|
+
...rest,
|
|
287
|
+
);
|
|
288
|
+
},
|
|
289
|
+
[queryClient],
|
|
290
|
+
),
|
|
291
|
+
refetchQueries: useCallback(
|
|
292
|
+
(...args: any[]) => {
|
|
293
|
+
const [queryKey, ...rest] = args;
|
|
294
|
+
|
|
295
|
+
return queryClient.refetchQueries(
|
|
296
|
+
getArrayQueryKey(queryKey),
|
|
297
|
+
...rest,
|
|
298
|
+
);
|
|
299
|
+
},
|
|
300
|
+
[queryClient],
|
|
301
|
+
),
|
|
302
|
+
cancelQuery: useCallback(
|
|
303
|
+
(pathAndInput) => {
|
|
304
|
+
return queryClient.cancelQueries(getArrayQueryKey(pathAndInput));
|
|
305
|
+
},
|
|
306
|
+
[queryClient],
|
|
307
|
+
),
|
|
308
|
+
setQueryData: useCallback(
|
|
309
|
+
(...args) => {
|
|
310
|
+
const [queryKey, ...rest] = args;
|
|
311
|
+
return queryClient.setQueryData(
|
|
312
|
+
getArrayQueryKey(queryKey),
|
|
313
|
+
...rest,
|
|
314
|
+
);
|
|
315
|
+
},
|
|
316
|
+
[queryClient],
|
|
317
|
+
),
|
|
318
|
+
getQueryData: useCallback(
|
|
319
|
+
(...args) => {
|
|
320
|
+
const [queryKey, ...rest] = args;
|
|
321
|
+
|
|
322
|
+
return queryClient.getQueryData(
|
|
323
|
+
getArrayQueryKey(queryKey),
|
|
324
|
+
...rest,
|
|
325
|
+
);
|
|
326
|
+
},
|
|
327
|
+
[queryClient],
|
|
328
|
+
),
|
|
329
|
+
setInfiniteQueryData: useCallback(
|
|
330
|
+
(...args) => {
|
|
331
|
+
const [queryKey, ...rest] = args;
|
|
332
|
+
|
|
333
|
+
return queryClient.setQueryData(
|
|
334
|
+
getArrayQueryKey(queryKey),
|
|
335
|
+
...rest,
|
|
336
|
+
);
|
|
337
|
+
},
|
|
338
|
+
[queryClient],
|
|
339
|
+
),
|
|
340
|
+
getInfiniteQueryData: useCallback(
|
|
341
|
+
(...args) => {
|
|
342
|
+
const [queryKey, ...rest] = args;
|
|
343
|
+
|
|
344
|
+
return queryClient.getQueryData(
|
|
345
|
+
getArrayQueryKey(queryKey),
|
|
346
|
+
...rest,
|
|
347
|
+
);
|
|
348
|
+
},
|
|
349
|
+
[queryClient],
|
|
350
|
+
),
|
|
351
|
+
}}
|
|
352
|
+
>
|
|
353
|
+
{props.children}
|
|
354
|
+
</Context.Provider>
|
|
355
|
+
);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
function useContext() {
|
|
359
|
+
return React.useContext(Context);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Hack to make sure errors return `status`='error` when doing SSR
|
|
364
|
+
* @link https://github.com/trpc/trpc/pull/1645
|
|
365
|
+
*/
|
|
366
|
+
function useSSRQueryOptionsIfNeeded<
|
|
367
|
+
TOptions extends { retryOnMount?: boolean } | undefined,
|
|
368
|
+
>(pathAndInput: unknown[], opts: TOptions): TOptions {
|
|
369
|
+
const { queryClient, ssrState } = useContext();
|
|
370
|
+
return ssrState &&
|
|
371
|
+
ssrState !== 'mounted' &&
|
|
372
|
+
queryClient.getQueryCache().find(getArrayQueryKey(pathAndInput))?.state
|
|
373
|
+
.status === 'error'
|
|
374
|
+
? {
|
|
375
|
+
retryOnMount: false,
|
|
376
|
+
...opts,
|
|
377
|
+
}
|
|
378
|
+
: opts;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function useQuery<
|
|
382
|
+
TPath extends keyof TQueryValues & string,
|
|
383
|
+
TQueryFnData = TQueryValues[TPath]['output'],
|
|
384
|
+
TData = TQueryValues[TPath]['output'],
|
|
385
|
+
>(
|
|
386
|
+
pathAndInput: [path: TPath, ...args: inferHandlerInput<TQueries[TPath]>],
|
|
387
|
+
opts?: UseTRPCQueryOptions<
|
|
388
|
+
TPath,
|
|
389
|
+
TQueryValues[TPath]['input'],
|
|
390
|
+
TQueryFnData,
|
|
391
|
+
TData,
|
|
392
|
+
TError
|
|
393
|
+
>,
|
|
394
|
+
): UseTRPCQueryResult<TData, TError> {
|
|
395
|
+
const { abortOnUnmount, client, ssrState, queryClient, prefetchQuery } =
|
|
396
|
+
useContext();
|
|
397
|
+
|
|
398
|
+
if (
|
|
399
|
+
typeof window === 'undefined' &&
|
|
400
|
+
ssrState === 'prepass' &&
|
|
401
|
+
opts?.trpc?.ssr !== false &&
|
|
402
|
+
opts?.enabled !== false &&
|
|
403
|
+
!queryClient.getQueryCache().find(getArrayQueryKey(pathAndInput))
|
|
404
|
+
) {
|
|
405
|
+
void prefetchQuery(pathAndInput as any, opts as any);
|
|
406
|
+
}
|
|
407
|
+
const ssrOpts = useSSRQueryOptionsIfNeeded(pathAndInput, opts);
|
|
408
|
+
// request option should take priority over global
|
|
409
|
+
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
|
|
410
|
+
|
|
411
|
+
const hook = __useQuery(
|
|
412
|
+
getArrayQueryKey(pathAndInput) as any,
|
|
413
|
+
(queryFunctionContext) => {
|
|
414
|
+
const actualOpts = {
|
|
415
|
+
...ssrOpts,
|
|
416
|
+
trpc: {
|
|
417
|
+
...ssrOpts?.trpc,
|
|
418
|
+
...(shouldAbortOnUnmount
|
|
419
|
+
? { signal: queryFunctionContext.signal }
|
|
420
|
+
: {}),
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
return (client as any).query(
|
|
425
|
+
...getClientArgs(pathAndInput, actualOpts),
|
|
426
|
+
);
|
|
427
|
+
},
|
|
428
|
+
ssrOpts,
|
|
429
|
+
) as UseTRPCQueryResult<TData, TError>;
|
|
430
|
+
hook.trpc = useHookResult({
|
|
431
|
+
path: pathAndInput[0],
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
return hook;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function useMutation<
|
|
438
|
+
TPath extends keyof TMutationValues & string,
|
|
439
|
+
TContext = unknown,
|
|
440
|
+
>(
|
|
441
|
+
path: TPath | [TPath],
|
|
442
|
+
opts?: UseTRPCMutationOptions<
|
|
443
|
+
TMutationValues[TPath]['input'],
|
|
444
|
+
TError,
|
|
445
|
+
TMutationValues[TPath]['output'],
|
|
446
|
+
TContext
|
|
447
|
+
>,
|
|
448
|
+
): UseTRPCMutationResult<
|
|
449
|
+
TMutationValues[TPath]['output'],
|
|
450
|
+
TError,
|
|
451
|
+
TMutationValues[TPath]['input'],
|
|
452
|
+
TContext
|
|
453
|
+
> {
|
|
454
|
+
const { client } = useContext();
|
|
455
|
+
const queryClient = useQueryClient();
|
|
456
|
+
|
|
457
|
+
const hook = __useMutation(
|
|
458
|
+
(input) => {
|
|
459
|
+
const actualPath = Array.isArray(path) ? path[0] : path;
|
|
460
|
+
|
|
461
|
+
return (client.mutation as any)(
|
|
462
|
+
...getClientArgs([actualPath, input], opts),
|
|
463
|
+
);
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
...opts,
|
|
467
|
+
onSuccess(...args) {
|
|
468
|
+
const originalFn = () => opts?.onSuccess?.(...args);
|
|
469
|
+
return mutationSuccessOverride({ originalFn, queryClient });
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
) as UseTRPCMutationResult<
|
|
473
|
+
TMutationValues[TPath]['output'],
|
|
474
|
+
TError,
|
|
475
|
+
TMutationValues[TPath]['input'],
|
|
476
|
+
TContext
|
|
477
|
+
>;
|
|
478
|
+
|
|
479
|
+
hook.trpc = useHookResult({
|
|
480
|
+
path: Array.isArray(path) ? path[0] : path,
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
return hook;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/* istanbul ignore next */
|
|
487
|
+
/**
|
|
488
|
+
* ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
|
|
489
|
+
* **Experimental.** API might change without major version bump
|
|
490
|
+
* ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠
|
|
491
|
+
*/
|
|
492
|
+
function useSubscription<
|
|
493
|
+
TPath extends keyof TSubscriptions & string,
|
|
494
|
+
TOutput extends inferSubscriptionOutput<TRouter, TPath>,
|
|
495
|
+
>(
|
|
496
|
+
pathAndInput: [
|
|
497
|
+
path: TPath,
|
|
498
|
+
...args: inferHandlerInput<TSubscriptions[TPath]>,
|
|
499
|
+
],
|
|
500
|
+
opts: UseTRPCSubscriptionOptions<
|
|
501
|
+
inferObservableValue<inferProcedureOutput<TSubscriptions[TPath]>>,
|
|
502
|
+
inferProcedureClientError<TSubscriptions[TPath]>
|
|
503
|
+
>,
|
|
504
|
+
) {
|
|
505
|
+
const enabled = opts?.enabled ?? true;
|
|
506
|
+
const queryKey = hashQueryKey(pathAndInput);
|
|
507
|
+
const { client } = useContext();
|
|
508
|
+
|
|
509
|
+
return useEffect(() => {
|
|
510
|
+
if (!enabled) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const [path, input] = pathAndInput;
|
|
514
|
+
let isStopped = false;
|
|
515
|
+
const subscription = client.subscription<
|
|
516
|
+
TRouter['_def']['subscriptions'],
|
|
517
|
+
TPath,
|
|
518
|
+
TOutput,
|
|
519
|
+
inferProcedureInput<TRouter['_def']['subscriptions'][TPath]>
|
|
520
|
+
>(path, (input ?? undefined) as any, {
|
|
521
|
+
onStarted: () => {
|
|
522
|
+
if (!isStopped) {
|
|
523
|
+
opts.onStarted?.();
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
onData: (data) => {
|
|
527
|
+
if (!isStopped) {
|
|
528
|
+
opts.onData(data);
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
onError: (err) => {
|
|
532
|
+
if (!isStopped) {
|
|
533
|
+
opts.onError?.(err);
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
return () => {
|
|
538
|
+
isStopped = true;
|
|
539
|
+
subscription.unsubscribe();
|
|
540
|
+
};
|
|
541
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
542
|
+
}, [queryKey, enabled]);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function useInfiniteQuery<TPath extends TInfiniteQueryNames & string>(
|
|
546
|
+
pathAndInput: [
|
|
547
|
+
path: TPath,
|
|
548
|
+
input: Omit<TQueryValues[TPath]['input'], 'cursor'>,
|
|
549
|
+
],
|
|
550
|
+
opts?: UseTRPCInfiniteQueryOptions<
|
|
551
|
+
TPath,
|
|
552
|
+
Omit<TQueryValues[TPath]['input'], 'cursor'>,
|
|
553
|
+
TQueryValues[TPath]['output'],
|
|
554
|
+
TError
|
|
555
|
+
>,
|
|
556
|
+
): UseTRPCInfiniteQueryResult<TQueryValues[TPath]['output'], TError> {
|
|
557
|
+
const [path, input] = pathAndInput;
|
|
558
|
+
const {
|
|
559
|
+
client,
|
|
560
|
+
ssrState,
|
|
561
|
+
prefetchInfiniteQuery,
|
|
562
|
+
queryClient,
|
|
563
|
+
abortOnUnmount,
|
|
564
|
+
} = useContext();
|
|
565
|
+
|
|
566
|
+
if (
|
|
567
|
+
typeof window === 'undefined' &&
|
|
568
|
+
ssrState === 'prepass' &&
|
|
569
|
+
opts?.trpc?.ssr !== false &&
|
|
570
|
+
opts?.enabled !== false &&
|
|
571
|
+
!queryClient.getQueryCache().find(getArrayQueryKey(pathAndInput))
|
|
572
|
+
) {
|
|
573
|
+
void prefetchInfiniteQuery(pathAndInput as any, opts as any);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const ssrOpts = useSSRQueryOptionsIfNeeded(pathAndInput, opts);
|
|
577
|
+
|
|
578
|
+
// request option should take priority over global
|
|
579
|
+
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
|
|
580
|
+
|
|
581
|
+
const hook = __useInfiniteQuery(
|
|
582
|
+
getArrayQueryKey(pathAndInput) as any,
|
|
583
|
+
(queryFunctionContext) => {
|
|
584
|
+
const actualOpts = {
|
|
585
|
+
...ssrOpts,
|
|
586
|
+
trpc: {
|
|
587
|
+
...ssrOpts?.trpc,
|
|
588
|
+
...(shouldAbortOnUnmount
|
|
589
|
+
? { signal: queryFunctionContext.signal }
|
|
590
|
+
: {}),
|
|
591
|
+
},
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
const actualInput = {
|
|
595
|
+
...((input as any) ?? {}),
|
|
596
|
+
cursor: queryFunctionContext.pageParam,
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
return (client as any).query(
|
|
600
|
+
...getClientArgs([path, actualInput], actualOpts),
|
|
601
|
+
);
|
|
602
|
+
},
|
|
603
|
+
ssrOpts,
|
|
604
|
+
) as UseTRPCInfiniteQueryResult<TQueryValues[TPath]['output'], TError>;
|
|
605
|
+
|
|
606
|
+
hook.trpc = useHookResult({
|
|
607
|
+
path,
|
|
608
|
+
});
|
|
609
|
+
return hook;
|
|
610
|
+
}
|
|
611
|
+
const useDehydratedState: UseDehydratedState<TRouter> = (
|
|
612
|
+
client,
|
|
613
|
+
trpcState,
|
|
614
|
+
) => {
|
|
615
|
+
const transformed: DehydratedState | undefined = useMemo(() => {
|
|
616
|
+
if (!trpcState) {
|
|
617
|
+
return trpcState;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return client.runtime.transformer.deserialize(trpcState);
|
|
621
|
+
}, [trpcState, client]);
|
|
622
|
+
return transformed;
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
return {
|
|
626
|
+
Provider: TRPCProvider,
|
|
627
|
+
createClient,
|
|
628
|
+
useContext,
|
|
629
|
+
useQuery,
|
|
630
|
+
useMutation,
|
|
631
|
+
useSubscription,
|
|
632
|
+
useDehydratedState,
|
|
633
|
+
useInfiniteQuery,
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Hack to infer the type of `createReactQueryHooks`
|
|
639
|
+
* @link https://stackoverflow.com/a/59072991
|
|
640
|
+
*/
|
|
641
|
+
class GnClass<TRouter extends AnyRouter, TSSRContext = unknown> {
|
|
642
|
+
fn() {
|
|
643
|
+
return createHooksInternal<TRouter, TSSRContext>();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
type returnTypeInferer<TType> = TType extends (
|
|
648
|
+
a: Record<string, string>,
|
|
649
|
+
) => infer U
|
|
650
|
+
? U
|
|
651
|
+
: never;
|
|
652
|
+
type fooType<TRouter extends AnyRouter, TSSRContext = unknown> = GnClass<
|
|
653
|
+
TRouter,
|
|
654
|
+
TSSRContext
|
|
655
|
+
>['fn'];
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Infer the type of a `createReactQueryHooks` function
|
|
659
|
+
* @internal
|
|
660
|
+
*/
|
|
661
|
+
export type CreateReactQueryHooks<
|
|
662
|
+
TRouter extends AnyRouter,
|
|
663
|
+
TSSRContext = unknown,
|
|
664
|
+
> = returnTypeInferer<fooType<TRouter, TSSRContext>>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AnyRouter } from '@trpc/server';
|
|
2
|
+
import { createRecursiveProxy } from '@trpc/server/shared';
|
|
3
|
+
import { getQueryKey } from '../../internals/getQueryKey';
|
|
4
|
+
import { CreateReactQueryHooks } from '../hooks/createHooksInternal';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create proxy for decorating procedures
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export function createReactProxyDecoration<
|
|
11
|
+
TRouter extends AnyRouter,
|
|
12
|
+
TSSRContext = unknown,
|
|
13
|
+
>(name: string, hooks: CreateReactQueryHooks<TRouter, TSSRContext>) {
|
|
14
|
+
return createRecursiveProxy((opts) => {
|
|
15
|
+
const args = opts.args;
|
|
16
|
+
|
|
17
|
+
const pathCopy = [name, ...opts.path];
|
|
18
|
+
|
|
19
|
+
// The last arg is for instance `.useMutation` or `.useQuery()`
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
21
|
+
const lastArg = pathCopy.pop()!;
|
|
22
|
+
|
|
23
|
+
// The `path` ends up being something like `post.byId`
|
|
24
|
+
const path = pathCopy.join('.');
|
|
25
|
+
if (lastArg === 'useMutation') {
|
|
26
|
+
return (hooks as any)[lastArg](path, ...args);
|
|
27
|
+
}
|
|
28
|
+
const [input, ...rest] = args;
|
|
29
|
+
|
|
30
|
+
const queryKey = getQueryKey(path, input);
|
|
31
|
+
return (hooks as any)[lastArg](queryKey, ...rest);
|
|
32
|
+
});
|
|
33
|
+
}
|