@trpc/react-query 11.0.0-alpha-tmp-issues-5851-take-two.499 → 11.0.0-alpha-tmp-subscription-connection-state.485
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/bundle-analysis.json +76 -54
- package/dist/createTRPCReact.d.ts +3 -3
- package/dist/createTRPCReact.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -1
- package/dist/internals/context.d.ts +18 -2
- package/dist/internals/context.d.ts.map +1 -1
- package/dist/internals/getQueryKey.d.ts +8 -0
- package/dist/internals/getQueryKey.d.ts.map +1 -1
- package/dist/internals/getQueryKey.js +15 -0
- package/dist/internals/getQueryKey.mjs +14 -1
- package/dist/shared/hooks/createHooksInternal.d.ts +2 -2
- package/dist/shared/hooks/createHooksInternal.d.ts.map +1 -1
- package/dist/shared/hooks/createHooksInternal.js +67 -3
- package/dist/shared/hooks/createHooksInternal.mjs +68 -4
- package/dist/shared/hooks/types.d.ts +171 -2
- package/dist/shared/hooks/types.d.ts.map +1 -1
- package/dist/shared/hooks/types.js +133 -0
- package/dist/shared/hooks/types.mjs +126 -0
- package/dist/shared/index.js +7 -0
- package/dist/shared/index.mjs +1 -0
- package/dist/shared/proxy/utilsProxy.d.ts +12 -4
- package/dist/shared/proxy/utilsProxy.d.ts.map +1 -1
- package/dist/shared/proxy/utilsProxy.js +14 -2
- package/dist/shared/proxy/utilsProxy.mjs +15 -3
- package/dist/utils/createUtilityFunctions.d.ts.map +1 -1
- package/dist/utils/createUtilityFunctions.js +23 -0
- package/dist/utils/createUtilityFunctions.mjs +23 -0
- package/package.json +6 -6
- package/src/createTRPCReact.tsx +11 -2
- package/src/index.ts +1 -1
- package/src/internals/context.tsx +26 -1
- package/src/internals/getQueryKey.ts +21 -0
- package/src/shared/hooks/createHooksInternal.tsx +146 -18
- package/src/shared/hooks/types.ts +365 -1
- package/src/shared/proxy/utilsProxy.ts +47 -6
- package/src/utils/createUtilityFunctions.ts +26 -0
|
@@ -19,7 +19,10 @@ import type { SSRState, TRPCContextState } from '../../internals/context';
|
|
|
19
19
|
import { TRPCContext } from '../../internals/context';
|
|
20
20
|
import { getClientArgs } from '../../internals/getClientArgs';
|
|
21
21
|
import type { TRPCQueryKey } from '../../internals/getQueryKey';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
getMutationKeyInternal,
|
|
24
|
+
getQueryKeyInternal,
|
|
25
|
+
} from '../../internals/getQueryKey';
|
|
23
26
|
import { useHookResult } from '../../internals/useHookResult';
|
|
24
27
|
import type {
|
|
25
28
|
TRPCUseQueries,
|
|
@@ -28,23 +31,46 @@ import type {
|
|
|
28
31
|
import { createUtilityFunctions } from '../../utils/createUtilityFunctions';
|
|
29
32
|
import { createUseQueries } from '../proxy/useQueriesProxy';
|
|
30
33
|
import type { CreateTRPCReactOptions, UseMutationOverride } from '../types';
|
|
31
|
-
import type {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
// import type { restartSubscriptionFn } from './types';
|
|
35
|
+
import {
|
|
36
|
+
getConnectingResult,
|
|
37
|
+
getErrorResult,
|
|
38
|
+
getIdleResult,
|
|
39
|
+
getPendingResult,
|
|
40
|
+
getStartingResult,
|
|
41
|
+
type CreateClient,
|
|
42
|
+
type TRPCProvider,
|
|
43
|
+
type TRPCQueryOptions,
|
|
44
|
+
type UseTRPCInfiniteQueryOptions,
|
|
45
|
+
type UseTRPCInfiniteQueryResult,
|
|
46
|
+
type UseTRPCMutationOptions,
|
|
47
|
+
type UseTRPCMutationResult,
|
|
48
|
+
type UseTRPCQueryOptions,
|
|
49
|
+
type UseTRPCQueryResult,
|
|
50
|
+
type UseTRPCSubscriptionOptions,
|
|
51
|
+
type UseTRPCSubscriptionResult,
|
|
52
|
+
type UseTRPCSuspenseInfiniteQueryOptions,
|
|
53
|
+
type UseTRPCSuspenseInfiniteQueryResult,
|
|
54
|
+
type UseTRPCSuspenseQueryOptions,
|
|
55
|
+
type UseTRPCSuspenseQueryResult,
|
|
46
56
|
} from './types';
|
|
47
57
|
|
|
58
|
+
const trackResult = <
|
|
59
|
+
T extends UseTRPCSubscriptionResult<unknown, unknown, unknown>,
|
|
60
|
+
>(
|
|
61
|
+
result: T,
|
|
62
|
+
onTrackResult: (key: keyof T) => void,
|
|
63
|
+
): T => {
|
|
64
|
+
const trackedResult = new Proxy(result, {
|
|
65
|
+
get(target, prop) {
|
|
66
|
+
onTrackResult(prop as keyof T);
|
|
67
|
+
return target[prop as keyof T];
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return trackedResult;
|
|
72
|
+
};
|
|
73
|
+
|
|
48
74
|
/**
|
|
49
75
|
* @internal
|
|
50
76
|
*/
|
|
@@ -267,7 +293,7 @@ export function createRootHooks<
|
|
|
267
293
|
const { client } = useContext();
|
|
268
294
|
const queryClient = useQueryClient();
|
|
269
295
|
|
|
270
|
-
const mutationKey =
|
|
296
|
+
const mutationKey = getMutationKeyInternal(path);
|
|
271
297
|
|
|
272
298
|
const defaultOpts = queryClient.defaultMutationOptions(
|
|
273
299
|
queryClient.getMutationDefaults(mutationKey),
|
|
@@ -306,9 +332,69 @@ export function createRootHooks<
|
|
|
306
332
|
path: readonly string[],
|
|
307
333
|
input: unknown,
|
|
308
334
|
opts: UseTRPCSubscriptionOptions<unknown, TError>,
|
|
309
|
-
) {
|
|
335
|
+
): UseTRPCSubscriptionResult<unknown, unknown, TError> {
|
|
310
336
|
const enabled = opts?.enabled ?? input !== skipToken;
|
|
311
337
|
const queryKey = hashKey(getQueryKeyInternal(path, input, 'any'));
|
|
338
|
+
|
|
339
|
+
const trackedProps = React.useRef(
|
|
340
|
+
new Set<keyof UseTRPCSubscriptionResult<unknown, unknown, TError>>([]),
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
const addTrackedProp = React.useCallback(
|
|
344
|
+
(key: keyof UseTRPCSubscriptionResult<unknown, unknown, TError>) => {
|
|
345
|
+
trackedProps.current.add(key);
|
|
346
|
+
},
|
|
347
|
+
[],
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
// const restart = React.useRef<restartSubscriptionFn<unknown>>(() => {
|
|
351
|
+
// throw new Error('not implemented');
|
|
352
|
+
// });
|
|
353
|
+
|
|
354
|
+
const currentResult = React.useRef<
|
|
355
|
+
UseTRPCSubscriptionResult<unknown, unknown, TError>
|
|
356
|
+
>(
|
|
357
|
+
enabled
|
|
358
|
+
? getStartingResult(/* restart.current */)
|
|
359
|
+
: getIdleResult(/* restart.current */),
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const [subscriptionState, setSubscriptionState] = React.useState(
|
|
363
|
+
trackResult(currentResult.current, addTrackedProp),
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
const updateSubscriptionState = React.useCallback(
|
|
367
|
+
(
|
|
368
|
+
opts:
|
|
369
|
+
| UseTRPCSubscriptionResult<unknown, unknown, TError>
|
|
370
|
+
| ((
|
|
371
|
+
prev: UseTRPCSubscriptionResult<unknown, unknown, TError>,
|
|
372
|
+
) => UseTRPCSubscriptionResult<unknown, unknown, TError>),
|
|
373
|
+
) => {
|
|
374
|
+
const oldResult = currentResult.current;
|
|
375
|
+
|
|
376
|
+
const newResult =
|
|
377
|
+
typeof opts === 'function' ? opts(currentResult.current) : opts;
|
|
378
|
+
|
|
379
|
+
currentResult.current = newResult;
|
|
380
|
+
|
|
381
|
+
let shouldUpdate = false;
|
|
382
|
+
|
|
383
|
+
for (const key of trackedProps.current) {
|
|
384
|
+
if (oldResult[key] !== newResult[key]) {
|
|
385
|
+
shouldUpdate = true;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (shouldUpdate) {
|
|
391
|
+
setSubscriptionState(trackResult(newResult, addTrackedProp));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
[addTrackedProp],
|
|
396
|
+
);
|
|
397
|
+
|
|
312
398
|
const { client } = useContext();
|
|
313
399
|
|
|
314
400
|
const optsRef = React.useRef<typeof opts>(opts);
|
|
@@ -319,6 +405,7 @@ export function createRootHooks<
|
|
|
319
405
|
return;
|
|
320
406
|
}
|
|
321
407
|
let isStopped = false;
|
|
408
|
+
|
|
322
409
|
const subscription = client.subscription(
|
|
323
410
|
path.join('.'),
|
|
324
411
|
input ?? undefined,
|
|
@@ -331,6 +418,14 @@ export function createRootHooks<
|
|
|
331
418
|
onData: (data) => {
|
|
332
419
|
if (!isStopped) {
|
|
333
420
|
optsRef.current.onData(data);
|
|
421
|
+
|
|
422
|
+
updateSubscriptionState((prev) => {
|
|
423
|
+
if (prev.isPending) {
|
|
424
|
+
return getPendingResult(prev, data);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return prev;
|
|
428
|
+
});
|
|
334
429
|
}
|
|
335
430
|
},
|
|
336
431
|
onError: (err) => {
|
|
@@ -338,14 +433,47 @@ export function createRootHooks<
|
|
|
338
433
|
optsRef.current.onError?.(err);
|
|
339
434
|
}
|
|
340
435
|
},
|
|
436
|
+
onStateChange: (state) => {
|
|
437
|
+
if (state.state === 'idle') {
|
|
438
|
+
updateSubscriptionState(getIdleResult(/* restart.current */));
|
|
439
|
+
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (state.state === 'connecting') {
|
|
444
|
+
updateSubscriptionState((prev) => {
|
|
445
|
+
return getConnectingResult(prev, state.data ?? null);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (state.state === 'pending') {
|
|
452
|
+
updateSubscriptionState((prev) => getPendingResult(prev));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (state.state === 'error') {
|
|
456
|
+
updateSubscriptionState((prev) => {
|
|
457
|
+
return getErrorResult(prev, state.data);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
},
|
|
341
461
|
},
|
|
342
462
|
);
|
|
463
|
+
|
|
464
|
+
// const effectRestart = restart.current;
|
|
465
|
+
|
|
343
466
|
return () => {
|
|
344
467
|
isStopped = true;
|
|
345
468
|
subscription.unsubscribe();
|
|
469
|
+
|
|
470
|
+
updateSubscriptionState(getIdleResult(/* effectRestart */));
|
|
346
471
|
};
|
|
472
|
+
|
|
347
473
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
348
474
|
}, [queryKey, enabled]);
|
|
475
|
+
|
|
476
|
+
return subscriptionState;
|
|
349
477
|
}
|
|
350
478
|
|
|
351
479
|
function useInfiniteQuery(
|
|
@@ -18,7 +18,9 @@ import type {
|
|
|
18
18
|
UseSuspenseQueryResult,
|
|
19
19
|
} from '@tanstack/react-query';
|
|
20
20
|
import type {
|
|
21
|
+
ConnectionState,
|
|
21
22
|
CreateTRPCClientOptions,
|
|
23
|
+
TRPCConnectionStateMessage,
|
|
22
24
|
TRPCRequestOptions,
|
|
23
25
|
TRPCUntypedClient,
|
|
24
26
|
} from '@trpc/client';
|
|
@@ -139,9 +141,371 @@ export interface UseTRPCMutationOptions<
|
|
|
139
141
|
export interface UseTRPCSubscriptionOptions<TOutput, TError> {
|
|
140
142
|
enabled?: boolean;
|
|
141
143
|
onStarted?: () => void;
|
|
142
|
-
|
|
144
|
+
/**
|
|
145
|
+
* @deprecated use onStateChange instead
|
|
146
|
+
*/
|
|
143
147
|
onError?: (err: TError) => void;
|
|
148
|
+
onData: (data: TOutput) => void;
|
|
149
|
+
onStateChange?: (state: TRPCConnectionStateMessage<TError>) => void;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface restartSubscriptionOptionsBase {
|
|
153
|
+
/**
|
|
154
|
+
* Cancel the current subscription and re-establish a new one
|
|
155
|
+
* - Defaults to `true`
|
|
156
|
+
* - Set to `false` no new subscription will be established if there is already an active subscription
|
|
157
|
+
*/
|
|
158
|
+
cancelSubscription?: boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface restartSubscriptionOptionsWithLastEventId
|
|
162
|
+
extends restartSubscriptionOptionsBase {
|
|
163
|
+
/**
|
|
164
|
+
* Defaults to `true` in case of failure or if the subscription is still active
|
|
165
|
+
* - When the susbscription has successfully completed, it will be set to `false`
|
|
166
|
+
*/
|
|
167
|
+
sendLastEventId?: boolean;
|
|
144
168
|
}
|
|
169
|
+
|
|
170
|
+
export type restartSubscriptionOptions<TInput> = TInput extends {
|
|
171
|
+
lastEventId?: string | null;
|
|
172
|
+
} | void
|
|
173
|
+
? restartSubscriptionOptionsWithLastEventId
|
|
174
|
+
: restartSubscriptionOptionsBase;
|
|
175
|
+
|
|
176
|
+
export type restartSubscriptionFn<TInput> = (
|
|
177
|
+
options?: restartSubscriptionOptions<TInput>,
|
|
178
|
+
) => void;
|
|
179
|
+
|
|
180
|
+
export interface TRPCSubscriptionBaseResult<_TInput, TOutput, TError> {
|
|
181
|
+
/**
|
|
182
|
+
* The last data received from the subscription
|
|
183
|
+
*/
|
|
184
|
+
data: TOutput | null;
|
|
185
|
+
/**
|
|
186
|
+
* The timestamp for when the connection was last (re-)established
|
|
187
|
+
*/
|
|
188
|
+
connectionStartedAt: number;
|
|
189
|
+
/**
|
|
190
|
+
* The timestamp for when the connection was initially established
|
|
191
|
+
*/
|
|
192
|
+
initialConnectionStartedAt: number;
|
|
193
|
+
/**
|
|
194
|
+
* The error that caused the subscription to stop
|
|
195
|
+
* - Defaults to `null`
|
|
196
|
+
* - Resets to `null` after the subscription is restarted and the connection is re-established
|
|
197
|
+
*/
|
|
198
|
+
error: TError | null;
|
|
199
|
+
/**
|
|
200
|
+
* The timestamp for when the last error was captured
|
|
201
|
+
*/
|
|
202
|
+
errorUpdatedAt: number;
|
|
203
|
+
/**
|
|
204
|
+
* The reason for the reconnection
|
|
205
|
+
* - Resets to `null` after the subscription is restarted and the connection is re-established
|
|
206
|
+
*/
|
|
207
|
+
connectionError: TError | null;
|
|
208
|
+
/**
|
|
209
|
+
* Reconnection attempts since last successful connection
|
|
210
|
+
*/
|
|
211
|
+
connectionAttemptCount: number;
|
|
212
|
+
/**
|
|
213
|
+
* The timestamp for when the last reconnection error was captured
|
|
214
|
+
*/
|
|
215
|
+
connectionErrorUpdatedAt: number;
|
|
216
|
+
/**
|
|
217
|
+
* Is `true` when the subscription is establishing the initial connection
|
|
218
|
+
*/
|
|
219
|
+
isStarting: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Is `true` when the subscription has successfully connected at least once
|
|
222
|
+
*/
|
|
223
|
+
isStarted: boolean;
|
|
224
|
+
/**
|
|
225
|
+
* Is `true` if the subscription is (re-)establishing a connection
|
|
226
|
+
* - Alias for `status === 'connecting'`
|
|
227
|
+
*/
|
|
228
|
+
isConnecting: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Is `true` when the subscription is connected and listening for data
|
|
231
|
+
* - Alias for `status === 'pending'`
|
|
232
|
+
*/
|
|
233
|
+
isPending: boolean;
|
|
234
|
+
/**
|
|
235
|
+
* Is `true` if the subscription is re-establishing a connection
|
|
236
|
+
* - Alias for `status === 'connecting' && isStarted === true`
|
|
237
|
+
*/
|
|
238
|
+
isReconnecting: boolean;
|
|
239
|
+
/**
|
|
240
|
+
* Is `true` if the subscription ended in an error state
|
|
241
|
+
* - Alias for `status === 'error'`
|
|
242
|
+
*/
|
|
243
|
+
isError: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* The current state of the subscription
|
|
246
|
+
* - Will be:
|
|
247
|
+
* - `'idle'` when the subscription is not enabled
|
|
248
|
+
* - `'connecting'` when the subscription is (re-)establishing the connection
|
|
249
|
+
* - `'pending'` when the subscription is connected and receiving data
|
|
250
|
+
* - `'error'` when the subscription has stopped due to an error
|
|
251
|
+
*/
|
|
252
|
+
status: ConnectionState;
|
|
253
|
+
/**
|
|
254
|
+
* Restart the subscription
|
|
255
|
+
*/
|
|
256
|
+
// restart: restartSubscriptionFn<TInput>;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface TRPCSubscriptionIdleResult<TInput, TOutput, TError>
|
|
260
|
+
extends TRPCSubscriptionBaseResult<TInput, TOutput, TError> {
|
|
261
|
+
data: null;
|
|
262
|
+
error: null;
|
|
263
|
+
errorUpdatedAt: 0;
|
|
264
|
+
connectionError: null;
|
|
265
|
+
isStarting: false;
|
|
266
|
+
isStarted: false;
|
|
267
|
+
isConnecting: false;
|
|
268
|
+
isPending: false;
|
|
269
|
+
isReconnecting: false;
|
|
270
|
+
isError: false;
|
|
271
|
+
connectionAttemptCount: 0;
|
|
272
|
+
connectionErrorUpdatedAt: 0;
|
|
273
|
+
connectionStartedAt: 0;
|
|
274
|
+
initialConnectionStartedAt: 0;
|
|
275
|
+
status: 'idle';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const defaultIdleResult: Omit<
|
|
279
|
+
TRPCSubscriptionIdleResult<unknown, unknown, unknown>,
|
|
280
|
+
'restart'
|
|
281
|
+
> = {
|
|
282
|
+
data: null,
|
|
283
|
+
connectionStartedAt: 0,
|
|
284
|
+
initialConnectionStartedAt: 0,
|
|
285
|
+
error: null,
|
|
286
|
+
errorUpdatedAt: 0,
|
|
287
|
+
connectionError: null,
|
|
288
|
+
connectionAttemptCount: 0,
|
|
289
|
+
isStarting: false,
|
|
290
|
+
isStarted: false,
|
|
291
|
+
isConnecting: false,
|
|
292
|
+
isPending: false,
|
|
293
|
+
isReconnecting: false,
|
|
294
|
+
isError: false,
|
|
295
|
+
connectionErrorUpdatedAt: 0,
|
|
296
|
+
status: 'idle',
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const getIdleResult = <
|
|
300
|
+
TInput,
|
|
301
|
+
TOutput,
|
|
302
|
+
TError,
|
|
303
|
+
>(): // restart: restartSubscriptionFn<TInput>,
|
|
304
|
+
TRPCSubscriptionIdleResult<TInput, TOutput, TError> => {
|
|
305
|
+
return {
|
|
306
|
+
...defaultIdleResult,
|
|
307
|
+
data: null,
|
|
308
|
+
// restart,
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export interface TRPCSubscriptionStartingResult<TInput, TOutput, TError>
|
|
313
|
+
extends TRPCSubscriptionBaseResult<TInput, TOutput, TError> {
|
|
314
|
+
connectionStartedAt: 0;
|
|
315
|
+
initialConnectionStartedAt: 0;
|
|
316
|
+
error: null;
|
|
317
|
+
data: null;
|
|
318
|
+
connectionError: TError | null;
|
|
319
|
+
isStarting: true;
|
|
320
|
+
isStarted: false;
|
|
321
|
+
isConnecting: true;
|
|
322
|
+
isPending: false;
|
|
323
|
+
isReconnecting: false;
|
|
324
|
+
isError: false;
|
|
325
|
+
status: 'connecting';
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export const getStartingResult = <TInput, TOutput, TError>(
|
|
329
|
+
// restart: restartSubscriptionFn<TInput>,
|
|
330
|
+
previous?:
|
|
331
|
+
| TRPCSubscriptionIdleResult<TInput, TOutput, TError>
|
|
332
|
+
| TRPCSubscriptionErrorResult<TInput, TOutput, TError>
|
|
333
|
+
| TRPCSubscriptionStartingResult<TInput, TOutput, TError>,
|
|
334
|
+
error?: TError | null,
|
|
335
|
+
): TRPCSubscriptionStartingResult<TInput, TOutput, TError> => {
|
|
336
|
+
const now = Date.now();
|
|
337
|
+
|
|
338
|
+
if (previous) {
|
|
339
|
+
return {
|
|
340
|
+
...defaultIdleResult,
|
|
341
|
+
...previous,
|
|
342
|
+
data: null,
|
|
343
|
+
connectionError: error ?? null,
|
|
344
|
+
isStarting: true,
|
|
345
|
+
isConnecting: true,
|
|
346
|
+
errorUpdatedAt: 0,
|
|
347
|
+
connectionAttemptCount: previous.connectionAttemptCount + 1,
|
|
348
|
+
connectionErrorUpdatedAt: error ? now : 0,
|
|
349
|
+
connectionStartedAt: 0,
|
|
350
|
+
initialConnectionStartedAt: 0,
|
|
351
|
+
error: null,
|
|
352
|
+
isStarted: false,
|
|
353
|
+
isError: false,
|
|
354
|
+
status: 'connecting',
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
...getIdleResult(/*restart*/),
|
|
360
|
+
connectionError: error ?? null,
|
|
361
|
+
isStarting: true,
|
|
362
|
+
isConnecting: true,
|
|
363
|
+
errorUpdatedAt: 0,
|
|
364
|
+
connectionAttemptCount: 0,
|
|
365
|
+
connectionErrorUpdatedAt: error ? now : 0,
|
|
366
|
+
status: 'connecting',
|
|
367
|
+
};
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
export interface TRPCSubscriptionPendingResult<TInput, TOutput, TError>
|
|
371
|
+
extends TRPCSubscriptionBaseResult<TInput, TOutput, TError> {
|
|
372
|
+
error: null;
|
|
373
|
+
connectionError: null;
|
|
374
|
+
connectionAttemptCount: 0;
|
|
375
|
+
isStarting: false;
|
|
376
|
+
isStarted: true;
|
|
377
|
+
isConnecting: false;
|
|
378
|
+
isPending: true;
|
|
379
|
+
isReconnecting: false;
|
|
380
|
+
isError: false;
|
|
381
|
+
status: 'pending';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export const getPendingResult = <TInput, TOutput, TError>(
|
|
385
|
+
previous: UseTRPCSubscriptionResult<TInput, TOutput, TError>,
|
|
386
|
+
data?: TOutput,
|
|
387
|
+
): TRPCSubscriptionPendingResult<TInput, TOutput, TError> => {
|
|
388
|
+
const time = Date.now();
|
|
389
|
+
|
|
390
|
+
if (previous.isStarting) {
|
|
391
|
+
return {
|
|
392
|
+
...previous,
|
|
393
|
+
error: null,
|
|
394
|
+
isStarting: false,
|
|
395
|
+
isStarted: true,
|
|
396
|
+
isConnecting: false,
|
|
397
|
+
isReconnecting: false,
|
|
398
|
+
isPending: true,
|
|
399
|
+
status: 'pending',
|
|
400
|
+
connectionStartedAt: time,
|
|
401
|
+
connectionAttemptCount: 0,
|
|
402
|
+
connectionError: null,
|
|
403
|
+
initialConnectionStartedAt: time,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
...previous,
|
|
409
|
+
data: data ?? previous.data,
|
|
410
|
+
error: null,
|
|
411
|
+
isError: false,
|
|
412
|
+
isStarting: false,
|
|
413
|
+
isStarted: true,
|
|
414
|
+
isConnecting: false,
|
|
415
|
+
isReconnecting: false,
|
|
416
|
+
isPending: true,
|
|
417
|
+
status: 'pending',
|
|
418
|
+
connectionStartedAt: time,
|
|
419
|
+
connectionAttemptCount: 0,
|
|
420
|
+
connectionError: null,
|
|
421
|
+
};
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
export interface TRPCSubscriptionReconnectingResult<TInput, TOutput, TError>
|
|
425
|
+
extends TRPCSubscriptionBaseResult<TInput, TOutput, TError> {
|
|
426
|
+
error: null;
|
|
427
|
+
connectionError: TError;
|
|
428
|
+
isStarting: false;
|
|
429
|
+
isStarted: true;
|
|
430
|
+
isConnecting: true;
|
|
431
|
+
isPending: false;
|
|
432
|
+
isReconnecting: true;
|
|
433
|
+
isError: false;
|
|
434
|
+
status: 'connecting';
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export const getReconnectingResult = <TInput, TOutput, TError>(
|
|
438
|
+
previous:
|
|
439
|
+
| TRPCSubscriptionPendingResult<TInput, TOutput, TError>
|
|
440
|
+
| TRPCSubscriptionReconnectingResult<TInput, TOutput, TError>,
|
|
441
|
+
error: TError,
|
|
442
|
+
): TRPCSubscriptionReconnectingResult<TInput, TOutput, TError> => {
|
|
443
|
+
return {
|
|
444
|
+
...previous,
|
|
445
|
+
isStarting: false,
|
|
446
|
+
isStarted: true,
|
|
447
|
+
isConnecting: true,
|
|
448
|
+
isReconnecting: true,
|
|
449
|
+
isPending: false,
|
|
450
|
+
status: 'connecting',
|
|
451
|
+
connectionError: error,
|
|
452
|
+
connectionAttemptCount: previous.connectionAttemptCount + 1,
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
export const getConnectingResult = <TInput, TOutput, TError>(
|
|
457
|
+
previous: UseTRPCSubscriptionResult<TInput, TOutput, TError>,
|
|
458
|
+
error: TError | null,
|
|
459
|
+
): TRPCSubscriptionConnectingResult<TInput, TOutput, TError> => {
|
|
460
|
+
if (previous.isReconnecting || previous.isPending) {
|
|
461
|
+
if (!error) throw new Error('Reconnecting without error?');
|
|
462
|
+
|
|
463
|
+
return getReconnectingResult(previous, error);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return getStartingResult(/*previous.restart, */ previous, error);
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
export interface TRPCSubscriptionErrorResult<TInput, TOutput, TError>
|
|
470
|
+
extends TRPCSubscriptionBaseResult<TInput, TOutput, TError> {
|
|
471
|
+
error: TError;
|
|
472
|
+
isStarting: false;
|
|
473
|
+
isStarted: true; // Not sure about this one
|
|
474
|
+
isConnecting: false;
|
|
475
|
+
isPending: false;
|
|
476
|
+
isReconnecting: false;
|
|
477
|
+
isError: true;
|
|
478
|
+
status: 'error';
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export const getErrorResult = <TInput, TOutput, TError>(
|
|
482
|
+
previous: UseTRPCSubscriptionResult<TInput, TOutput, TError>,
|
|
483
|
+
error: TError,
|
|
484
|
+
): TRPCSubscriptionErrorResult<TInput, TOutput, TError> => {
|
|
485
|
+
return {
|
|
486
|
+
...previous,
|
|
487
|
+
isStarting: false,
|
|
488
|
+
isStarted: true,
|
|
489
|
+
isConnecting: false,
|
|
490
|
+
isReconnecting: false,
|
|
491
|
+
isPending: false,
|
|
492
|
+
isError: true,
|
|
493
|
+
status: 'error',
|
|
494
|
+
error,
|
|
495
|
+
errorUpdatedAt: Date.now(),
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
export type TRPCSubscriptionConnectingResult<TInput, TOutput, TError> =
|
|
500
|
+
| TRPCSubscriptionStartingResult<TInput, TOutput, TError>
|
|
501
|
+
| TRPCSubscriptionReconnectingResult<TInput, TOutput, TError>;
|
|
502
|
+
|
|
503
|
+
export type UseTRPCSubscriptionResult<TInput, TOutput, TError> =
|
|
504
|
+
| TRPCSubscriptionIdleResult<TInput, TOutput, TError>
|
|
505
|
+
| TRPCSubscriptionPendingResult<TInput, TOutput, TError>
|
|
506
|
+
| TRPCSubscriptionConnectingResult<TInput, TOutput, TError>
|
|
507
|
+
| TRPCSubscriptionErrorResult<TInput, TOutput, TError>;
|
|
508
|
+
|
|
145
509
|
export interface TRPCProviderProps<TRouter extends AnyRouter, TSSRContext>
|
|
146
510
|
extends TRPCContextProps<TRouter, TSSRContext> {
|
|
147
511
|
children: ReactNode;
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
import type { TRPCClientError } from '@trpc/client';
|
|
16
16
|
import { createTRPCClientProxy } from '@trpc/client';
|
|
17
17
|
import type {
|
|
18
|
+
AnyMutationProcedure,
|
|
18
19
|
AnyQueryProcedure,
|
|
19
20
|
AnyRootTypes,
|
|
20
21
|
AnyRouter,
|
|
@@ -37,10 +38,14 @@ import type {
|
|
|
37
38
|
} from '../../internals/context';
|
|
38
39
|
import { contextProps } from '../../internals/context';
|
|
39
40
|
import type { QueryKeyKnown, QueryType } from '../../internals/getQueryKey';
|
|
40
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
getMutationKeyInternal,
|
|
43
|
+
getQueryKeyInternal,
|
|
44
|
+
} from '../../internals/getQueryKey';
|
|
45
|
+
import type { InferMutationOptions } from '../../utils/inferReactQueryProcedure';
|
|
41
46
|
import type { ExtractCursorType } from '../hooks/types';
|
|
42
47
|
|
|
43
|
-
type
|
|
48
|
+
type DecorateQueryProcedure<
|
|
44
49
|
TRoot extends AnyRootTypes,
|
|
45
50
|
TProcedure extends AnyQueryProcedure,
|
|
46
51
|
> = {
|
|
@@ -225,6 +230,25 @@ type DecorateProcedure<
|
|
|
225
230
|
| undefined;
|
|
226
231
|
};
|
|
227
232
|
|
|
233
|
+
type DecorateMutationProcedure<
|
|
234
|
+
TRoot extends AnyRootTypes,
|
|
235
|
+
TProcedure extends AnyMutationProcedure,
|
|
236
|
+
> = {
|
|
237
|
+
setMutationDefaults(
|
|
238
|
+
options:
|
|
239
|
+
| InferMutationOptions<TRoot, TProcedure>
|
|
240
|
+
| ((args: {
|
|
241
|
+
canonicalMutationFn: NonNullable<
|
|
242
|
+
InferMutationOptions<TRoot, TProcedure>['mutationFn']
|
|
243
|
+
>;
|
|
244
|
+
}) => InferMutationOptions<TRoot, TProcedure>),
|
|
245
|
+
): void;
|
|
246
|
+
|
|
247
|
+
getMutationDefaults(): InferMutationOptions<TRoot, TProcedure> | undefined;
|
|
248
|
+
|
|
249
|
+
isMutating(): number;
|
|
250
|
+
};
|
|
251
|
+
|
|
228
252
|
/**
|
|
229
253
|
* this is the type that is used to add in procedures that can be used on
|
|
230
254
|
* an entire router
|
|
@@ -252,14 +276,16 @@ export type DecoratedProcedureUtilsRecord<
|
|
|
252
276
|
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
|
|
253
277
|
? $Value extends RouterRecord
|
|
254
278
|
? DecoratedProcedureUtilsRecord<TRoot, $Value> & DecorateRouter
|
|
255
|
-
:
|
|
256
|
-
$Value
|
|
257
|
-
|
|
279
|
+
: $Value extends AnyQueryProcedure
|
|
280
|
+
? DecorateQueryProcedure<TRoot, $Value>
|
|
281
|
+
: $Value extends AnyMutationProcedure
|
|
282
|
+
? DecorateMutationProcedure<TRoot, $Value>
|
|
258
283
|
: never
|
|
259
284
|
: never;
|
|
260
285
|
}; // Add functions that should be available at utils root
|
|
261
286
|
|
|
262
|
-
type AnyDecoratedProcedure =
|
|
287
|
+
type AnyDecoratedProcedure = DecorateQueryProcedure<any, any> &
|
|
288
|
+
DecorateMutationProcedure<any, any>;
|
|
263
289
|
|
|
264
290
|
export type CreateReactUtils<
|
|
265
291
|
TRouter extends AnyRouter,
|
|
@@ -296,6 +322,9 @@ export const getQueryType = (
|
|
|
296
322
|
case 'setInfiniteData':
|
|
297
323
|
return 'infinite';
|
|
298
324
|
|
|
325
|
+
case 'setMutationDefaults':
|
|
326
|
+
case 'getMutationDefaults':
|
|
327
|
+
case 'isMutating':
|
|
299
328
|
case 'cancel':
|
|
300
329
|
case 'invalidate':
|
|
301
330
|
case 'refetch':
|
|
@@ -321,6 +350,9 @@ function createRecursiveUtilsProxy<TRouter extends AnyRouter>(
|
|
|
321
350
|
const queryKey = getQueryKeyInternal(path, input, queryType);
|
|
322
351
|
|
|
323
352
|
const contextMap: Record<keyof AnyDecoratedProcedure, () => unknown> = {
|
|
353
|
+
/**
|
|
354
|
+
* DecorateQueryProcedure
|
|
355
|
+
*/
|
|
324
356
|
fetch: () => context.fetchQuery(queryKey, ...args),
|
|
325
357
|
fetchInfinite: () => context.fetchInfiniteQuery(queryKey, args[0]),
|
|
326
358
|
prefetch: () => context.prefetchQuery(queryKey, ...args),
|
|
@@ -340,6 +372,15 @@ function createRecursiveUtilsProxy<TRouter extends AnyRouter>(
|
|
|
340
372
|
},
|
|
341
373
|
getData: () => context.getQueryData(queryKey),
|
|
342
374
|
getInfiniteData: () => context.getInfiniteQueryData(queryKey),
|
|
375
|
+
/**
|
|
376
|
+
* DecorateMutationProcedure
|
|
377
|
+
*/
|
|
378
|
+
setMutationDefaults: () =>
|
|
379
|
+
context.setMutationDefaults(getMutationKeyInternal(path), input),
|
|
380
|
+
getMutationDefaults: () =>
|
|
381
|
+
context.getMutationDefaults(getMutationKeyInternal(path)),
|
|
382
|
+
isMutating: () =>
|
|
383
|
+
context.isMutating({ mutationKey: getMutationKeyInternal(path) }),
|
|
343
384
|
};
|
|
344
385
|
|
|
345
386
|
return contextMap[utilName]();
|