@trpc/tanstack-react-query 11.6.1-canary.5 → 11.7.0
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 +117 -38
- package/dist/index.d.cts +119 -74
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +119 -74
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +118 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/internals/Context.tsx +36 -19
- package/src/internals/createOptionsProxy.ts +111 -44
- package/src/internals/infiniteQueryOptions.ts +72 -33
- package/src/internals/mutationOptions.ts +47 -31
- package/src/internals/queryOptions.ts +95 -45
- package/src/internals/subscriptionOptions.ts +30 -20
- package/src/internals/types.ts +75 -4
- package/src/internals/utils.ts +108 -56
|
@@ -6,11 +6,13 @@ import type { Unsubscribable } from '@trpc/server/observable';
|
|
|
6
6
|
import type { inferAsyncIterableYield } from '@trpc/server/unstable-core-do-not-import';
|
|
7
7
|
import * as React from 'react';
|
|
8
8
|
import type {
|
|
9
|
+
DefaultFeatureFlags,
|
|
10
|
+
FeatureFlags,
|
|
9
11
|
ResolverDef,
|
|
10
12
|
TRPCQueryKey,
|
|
11
13
|
TRPCQueryOptionsResult,
|
|
12
14
|
} from './types';
|
|
13
|
-
import { createTRPCOptionsResult } from './utils';
|
|
15
|
+
import { createTRPCOptionsResult, readQueryKey } from './utils';
|
|
14
16
|
|
|
15
17
|
interface BaseTRPCSubscriptionOptionsIn<TOutput, TError> {
|
|
16
18
|
enabled?: boolean;
|
|
@@ -27,17 +29,23 @@ interface UnusedSkipTokenTRPCSubscriptionOptionsIn<TOutput, TError> {
|
|
|
27
29
|
onConnectionStateChange?: (state: TRPCConnectionState<TError>) => void;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
interface TRPCSubscriptionOptionsOut<
|
|
31
|
-
|
|
32
|
+
interface TRPCSubscriptionOptionsOut<
|
|
33
|
+
TOutput,
|
|
34
|
+
TError,
|
|
35
|
+
TFeatureFlags extends FeatureFlags,
|
|
36
|
+
> extends UnusedSkipTokenTRPCSubscriptionOptionsIn<TOutput, TError>,
|
|
32
37
|
TRPCQueryOptionsResult {
|
|
33
38
|
enabled: boolean;
|
|
34
|
-
queryKey: TRPCQueryKey
|
|
39
|
+
queryKey: TRPCQueryKey<TFeatureFlags['keyPrefix']>;
|
|
35
40
|
subscribe: (
|
|
36
41
|
innerOpts: UnusedSkipTokenTRPCSubscriptionOptionsIn<TOutput, TError>,
|
|
37
42
|
) => Unsubscribable;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
export interface TRPCSubscriptionOptions<
|
|
45
|
+
export interface TRPCSubscriptionOptions<
|
|
46
|
+
TDef extends ResolverDef,
|
|
47
|
+
TFeatureFlags extends FeatureFlags = DefaultFeatureFlags,
|
|
48
|
+
> {
|
|
41
49
|
(
|
|
42
50
|
input: TDef['input'],
|
|
43
51
|
opts?: UnusedSkipTokenTRPCSubscriptionOptionsIn<
|
|
@@ -46,7 +54,8 @@ export interface TRPCSubscriptionOptions<TDef extends ResolverDef> {
|
|
|
46
54
|
>,
|
|
47
55
|
): TRPCSubscriptionOptionsOut<
|
|
48
56
|
inferAsyncIterableYield<TDef['output']>,
|
|
49
|
-
TRPCClientErrorLike<TDef
|
|
57
|
+
TRPCClientErrorLike<TDef>,
|
|
58
|
+
TFeatureFlags
|
|
50
59
|
>;
|
|
51
60
|
(
|
|
52
61
|
input: TDef['input'] | SkipToken,
|
|
@@ -56,7 +65,8 @@ export interface TRPCSubscriptionOptions<TDef extends ResolverDef> {
|
|
|
56
65
|
>,
|
|
57
66
|
): TRPCSubscriptionOptionsOut<
|
|
58
67
|
inferAsyncIterableYield<TDef['output']>,
|
|
59
|
-
TRPCClientErrorLike<TDef
|
|
68
|
+
TRPCClientErrorLike<TDef>,
|
|
69
|
+
TFeatureFlags
|
|
60
70
|
>;
|
|
61
71
|
}
|
|
62
72
|
export type TRPCSubscriptionStatus =
|
|
@@ -113,27 +123,27 @@ type AnyTRPCSubscriptionOptionsIn =
|
|
|
113
123
|
| BaseTRPCSubscriptionOptionsIn<unknown, unknown>
|
|
114
124
|
| UnusedSkipTokenTRPCSubscriptionOptionsIn<unknown, unknown>;
|
|
115
125
|
|
|
116
|
-
type AnyTRPCSubscriptionOptionsOut =
|
|
117
|
-
unknown,
|
|
118
|
-
unknown
|
|
119
|
-
>;
|
|
126
|
+
type AnyTRPCSubscriptionOptionsOut<TFeatureFlags extends FeatureFlags> =
|
|
127
|
+
TRPCSubscriptionOptionsOut<unknown, unknown, TFeatureFlags>;
|
|
120
128
|
|
|
121
129
|
/**
|
|
122
130
|
* @internal
|
|
123
131
|
*/
|
|
124
|
-
export const trpcSubscriptionOptions =
|
|
132
|
+
export const trpcSubscriptionOptions = <
|
|
133
|
+
TFeatureFlags extends FeatureFlags,
|
|
134
|
+
>(args: {
|
|
125
135
|
subscribe: typeof TRPCUntypedClient.prototype.subscription;
|
|
126
|
-
path:
|
|
127
|
-
queryKey: TRPCQueryKey
|
|
136
|
+
path: string[];
|
|
137
|
+
queryKey: TRPCQueryKey<TFeatureFlags['keyPrefix']>;
|
|
128
138
|
opts?: AnyTRPCSubscriptionOptionsIn;
|
|
129
|
-
}): AnyTRPCSubscriptionOptionsOut => {
|
|
139
|
+
}): AnyTRPCSubscriptionOptionsOut<TFeatureFlags> => {
|
|
130
140
|
const { subscribe, path, queryKey, opts = {} } = args;
|
|
131
|
-
const input = queryKey
|
|
141
|
+
const input = readQueryKey(queryKey)?.args?.input;
|
|
132
142
|
const enabled = 'enabled' in opts ? !!opts.enabled : input !== skipToken;
|
|
133
143
|
|
|
134
|
-
const _subscribe: ReturnType<
|
|
135
|
-
|
|
136
|
-
) => {
|
|
144
|
+
const _subscribe: ReturnType<
|
|
145
|
+
TRPCSubscriptionOptions<any, TFeatureFlags>
|
|
146
|
+
>['subscribe'] = (innerOpts) => {
|
|
137
147
|
return subscribe(path.join('.'), input ?? undefined, innerOpts);
|
|
138
148
|
};
|
|
139
149
|
|
|
@@ -147,7 +157,7 @@ export const trpcSubscriptionOptions = (args: {
|
|
|
147
157
|
};
|
|
148
158
|
|
|
149
159
|
export function useSubscription<TOutput, TError>(
|
|
150
|
-
opts: TRPCSubscriptionOptionsOut<TOutput, TError>,
|
|
160
|
+
opts: TRPCSubscriptionOptionsOut<TOutput, TError, any>,
|
|
151
161
|
): TRPCSubscriptionResult<TOutput, TError> {
|
|
152
162
|
type $Result = TRPCSubscriptionResult<TOutput, TError>;
|
|
153
163
|
|
package/src/internals/types.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type ResolverDef = {
|
|
|
17
17
|
output: any;
|
|
18
18
|
transformer: boolean;
|
|
19
19
|
errorShape: any;
|
|
20
|
+
featureFlags: FeatureFlags;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -83,12 +84,82 @@ export type QueryType = 'any' | 'infinite' | 'query';
|
|
|
83
84
|
/**
|
|
84
85
|
* @public
|
|
85
86
|
*/
|
|
86
|
-
export type
|
|
87
|
-
|
|
88
|
-
{ input?: unknown; type?: Exclude<QueryType, 'any'> }
|
|
87
|
+
export type TRPCQueryKeyWithoutPrefix = [
|
|
88
|
+
path: string[],
|
|
89
|
+
opts?: { input?: unknown; type?: Exclude<QueryType, 'any'> },
|
|
89
90
|
];
|
|
90
91
|
|
|
91
92
|
/**
|
|
92
93
|
* @public
|
|
93
94
|
*/
|
|
94
|
-
export type
|
|
95
|
+
export type TRPCQueryKeyWithPrefix = [
|
|
96
|
+
prefix: string[],
|
|
97
|
+
...TRPCQueryKeyWithoutPrefix,
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
export type TRPCQueryKey<TPrefixEnabled extends boolean = false> =
|
|
101
|
+
TPrefixEnabled extends true
|
|
102
|
+
? TRPCQueryKeyWithPrefix
|
|
103
|
+
: TRPCQueryKeyWithoutPrefix;
|
|
104
|
+
|
|
105
|
+
export type AnyTRPCQueryKey =
|
|
106
|
+
| TRPCQueryKeyWithoutPrefix
|
|
107
|
+
| TRPCQueryKeyWithPrefix;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
export type TRPCMutationKeyWithPrefix = [
|
|
113
|
+
prefix: string[],
|
|
114
|
+
...TRPCMutationKeyWithoutPrefix,
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @public
|
|
119
|
+
*/
|
|
120
|
+
export type TRPCMutationKeyWithoutPrefix = [path: string[]];
|
|
121
|
+
|
|
122
|
+
export type AnyTRPCMutationKey =
|
|
123
|
+
| TRPCMutationKeyWithoutPrefix
|
|
124
|
+
| TRPCMutationKeyWithPrefix;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @public
|
|
128
|
+
*/
|
|
129
|
+
export type TRPCMutationKey<TPrefixEnabled extends boolean = false> =
|
|
130
|
+
TPrefixEnabled extends true
|
|
131
|
+
? TRPCMutationKeyWithPrefix
|
|
132
|
+
: TRPCMutationKeyWithoutPrefix;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Feature flags for configuring tRPC behavior
|
|
136
|
+
* @public
|
|
137
|
+
*/
|
|
138
|
+
export type FeatureFlags = { keyPrefix: boolean };
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @internal
|
|
142
|
+
*/
|
|
143
|
+
export type ofFeatureFlags<T extends FeatureFlags> = T;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
export type KeyPrefixOptions<TFeatureFlags extends FeatureFlags> =
|
|
149
|
+
TFeatureFlags['keyPrefix'] extends true
|
|
150
|
+
? {
|
|
151
|
+
keyPrefix: string;
|
|
152
|
+
}
|
|
153
|
+
: {
|
|
154
|
+
/**
|
|
155
|
+
* In order to use a query key prefix, you have to initialize the context with the `keyPrefix`
|
|
156
|
+
*/
|
|
157
|
+
keyPrefix?: never;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Default feature flags with query key prefix disabled
|
|
161
|
+
* @public
|
|
162
|
+
*/
|
|
163
|
+
export type DefaultFeatureFlags = ofFeatureFlags<{
|
|
164
|
+
keyPrefix: false;
|
|
165
|
+
}>;
|
package/src/internals/utils.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { skipToken, type QueryClient } from '@tanstack/react-query';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
isFunction,
|
|
4
|
+
isObject,
|
|
5
|
+
run,
|
|
6
|
+
} from '@trpc/server/unstable-core-do-not-import';
|
|
3
7
|
import type {
|
|
8
|
+
AnyTRPCMutationKey,
|
|
9
|
+
AnyTRPCQueryKey,
|
|
10
|
+
FeatureFlags,
|
|
4
11
|
QueryType,
|
|
5
|
-
|
|
12
|
+
TRPCMutationKeyWithoutPrefix,
|
|
6
13
|
TRPCQueryKey,
|
|
14
|
+
TRPCQueryKeyWithoutPrefix,
|
|
15
|
+
TRPCQueryKeyWithPrefix,
|
|
7
16
|
TRPCQueryOptionsResult,
|
|
8
17
|
} from './types';
|
|
9
18
|
|
|
@@ -11,7 +20,7 @@ import type {
|
|
|
11
20
|
* @internal
|
|
12
21
|
*/
|
|
13
22
|
export function createTRPCOptionsResult(value: {
|
|
14
|
-
path:
|
|
23
|
+
path: string[];
|
|
15
24
|
}): TRPCQueryOptionsResult['trpc'] {
|
|
16
25
|
const path = value.path.join('.');
|
|
17
26
|
|
|
@@ -20,38 +29,65 @@ export function createTRPCOptionsResult(value: {
|
|
|
20
29
|
};
|
|
21
30
|
}
|
|
22
31
|
|
|
32
|
+
export function isPrefixedQueryKey(
|
|
33
|
+
queryKey: TRPCQueryKey<any>,
|
|
34
|
+
): queryKey is TRPCQueryKeyWithPrefix {
|
|
35
|
+
return queryKey.length >= 3;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function readQueryKey(queryKey: AnyTRPCQueryKey) {
|
|
39
|
+
if (isPrefixedQueryKey(queryKey)) {
|
|
40
|
+
return {
|
|
41
|
+
type: 'prefixed' as const,
|
|
42
|
+
prefix: queryKey[0],
|
|
43
|
+
path: queryKey[1],
|
|
44
|
+
args: queryKey[2],
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
return {
|
|
48
|
+
type: 'unprefixed' as const,
|
|
49
|
+
prefix: undefined,
|
|
50
|
+
path: queryKey[0],
|
|
51
|
+
args: queryKey[1],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
/**
|
|
24
57
|
* @internal
|
|
25
58
|
*/
|
|
26
|
-
export function getClientArgs<TOptions>(
|
|
27
|
-
queryKey: TRPCQueryKey
|
|
59
|
+
export function getClientArgs<TOptions, TFeatureFlags extends FeatureFlags>(
|
|
60
|
+
queryKey: TRPCQueryKey<TFeatureFlags['keyPrefix']>,
|
|
28
61
|
opts: TOptions,
|
|
29
62
|
infiniteParams?: {
|
|
30
63
|
pageParam: any;
|
|
31
64
|
direction: 'forward' | 'backward';
|
|
32
65
|
},
|
|
33
66
|
) {
|
|
34
|
-
const
|
|
35
|
-
|
|
67
|
+
const queryKeyData = readQueryKey(queryKey);
|
|
68
|
+
|
|
69
|
+
let input = queryKeyData.args?.input;
|
|
36
70
|
if (infiniteParams) {
|
|
37
71
|
input = {
|
|
38
|
-
...(input ?? {}),
|
|
72
|
+
...(queryKeyData.args?.input ?? {}),
|
|
39
73
|
...(infiniteParams.pageParam !== undefined
|
|
40
74
|
? { cursor: infiniteParams.pageParam }
|
|
41
75
|
: {}),
|
|
42
76
|
direction: infiniteParams.direction,
|
|
43
77
|
};
|
|
44
78
|
}
|
|
45
|
-
return [path.join('.'), input, (opts as any)?.trpc] as const;
|
|
79
|
+
return [queryKeyData.path.join('.'), input, (opts as any)?.trpc] as const;
|
|
46
80
|
}
|
|
47
81
|
|
|
48
82
|
/**
|
|
49
83
|
* @internal
|
|
50
84
|
*/
|
|
51
|
-
export async function buildQueryFromAsyncIterable
|
|
85
|
+
export async function buildQueryFromAsyncIterable<
|
|
86
|
+
TQueryKey extends TRPCQueryKey<any>,
|
|
87
|
+
>(
|
|
52
88
|
asyncIterable: AsyncIterable<unknown>,
|
|
53
89
|
queryClient: QueryClient,
|
|
54
|
-
queryKey:
|
|
90
|
+
queryKey: TQueryKey,
|
|
55
91
|
) {
|
|
56
92
|
const queryCache = queryClient.getQueryCache();
|
|
57
93
|
|
|
@@ -82,65 +118,81 @@ export async function buildQueryFromAsyncIterable(
|
|
|
82
118
|
*
|
|
83
119
|
* @internal
|
|
84
120
|
*/
|
|
85
|
-
export function getQueryKeyInternal(
|
|
86
|
-
path:
|
|
87
|
-
input?: unknown
|
|
88
|
-
type
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
121
|
+
export function getQueryKeyInternal(opts: {
|
|
122
|
+
path: string[];
|
|
123
|
+
input?: unknown;
|
|
124
|
+
type: QueryType;
|
|
125
|
+
prefix: string | undefined;
|
|
126
|
+
}): AnyTRPCQueryKey {
|
|
127
|
+
const key = run((): TRPCQueryKeyWithoutPrefix => {
|
|
128
|
+
const { input, type } = opts;
|
|
129
|
+
|
|
130
|
+
// Construct a query key that is easy to destructure and flexible for
|
|
131
|
+
// partial selecting etc.
|
|
132
|
+
// https://github.com/trpc/trpc/issues/3128
|
|
133
|
+
|
|
134
|
+
// some parts of the path may be dot-separated, split them up
|
|
135
|
+
const splitPath = opts.path.flatMap((part) => part.split('.'));
|
|
136
|
+
|
|
137
|
+
if (!input && type === 'any') {
|
|
138
|
+
// this matches also all mutations (see `getMutationKeyInternal`)
|
|
139
|
+
|
|
140
|
+
// for `utils.invalidate()` to match all queries (including vanilla react-query)
|
|
141
|
+
// we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
|
|
142
|
+
return splitPath.length ? [splitPath] : ([] as unknown as TRPCQueryKey);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
type === 'infinite' &&
|
|
147
|
+
isObject(input) &&
|
|
148
|
+
('direction' in input || 'cursor' in input)
|
|
149
|
+
) {
|
|
150
|
+
const {
|
|
151
|
+
cursor: _,
|
|
152
|
+
direction: __,
|
|
153
|
+
...inputWithoutCursorAndDirection
|
|
154
|
+
} = input;
|
|
155
|
+
return [
|
|
156
|
+
splitPath,
|
|
157
|
+
{
|
|
158
|
+
input: inputWithoutCursorAndDirection,
|
|
159
|
+
type: 'infinite',
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
}
|
|
96
163
|
|
|
97
|
-
if (!input && (!type || type === 'any')) {
|
|
98
|
-
// this matches also all mutations (see `getMutationKeyInternal`)
|
|
99
|
-
|
|
100
|
-
// for `utils.invalidate()` to match all queries (including vanilla react-query)
|
|
101
|
-
// we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
|
|
102
|
-
return splitPath.length ? [splitPath] : ([] as unknown as TRPCQueryKey);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
type === 'infinite' &&
|
|
107
|
-
isObject(input) &&
|
|
108
|
-
('direction' in input || 'cursor' in input)
|
|
109
|
-
) {
|
|
110
|
-
const {
|
|
111
|
-
cursor: _,
|
|
112
|
-
direction: __,
|
|
113
|
-
...inputWithoutCursorAndDirection
|
|
114
|
-
} = input;
|
|
115
164
|
return [
|
|
116
165
|
splitPath,
|
|
117
166
|
{
|
|
118
|
-
input
|
|
119
|
-
|
|
167
|
+
...(typeof input !== 'undefined' &&
|
|
168
|
+
input !== skipToken && { input: input }),
|
|
169
|
+
...(type && type !== 'any' && { type: type }),
|
|
120
170
|
},
|
|
121
171
|
];
|
|
122
|
-
}
|
|
172
|
+
});
|
|
123
173
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
input !== skipToken && { input: input }),
|
|
129
|
-
...(type && type !== 'any' && { type: type }),
|
|
130
|
-
},
|
|
131
|
-
];
|
|
174
|
+
if (opts.prefix) {
|
|
175
|
+
key.unshift([opts.prefix]);
|
|
176
|
+
}
|
|
177
|
+
return key;
|
|
132
178
|
}
|
|
133
179
|
|
|
134
180
|
/**
|
|
135
181
|
* @internal
|
|
136
182
|
*/
|
|
137
|
-
export function getMutationKeyInternal(
|
|
138
|
-
|
|
139
|
-
|
|
183
|
+
export function getMutationKeyInternal(opts: {
|
|
184
|
+
prefix: string | undefined;
|
|
185
|
+
path: string[];
|
|
186
|
+
}): AnyTRPCMutationKey {
|
|
140
187
|
// some parts of the path may be dot-separated, split them up
|
|
141
|
-
const
|
|
188
|
+
const key: TRPCMutationKeyWithoutPrefix = [
|
|
189
|
+
opts.path.flatMap((part) => part.split('.')),
|
|
190
|
+
];
|
|
142
191
|
|
|
143
|
-
|
|
192
|
+
if (opts.prefix) {
|
|
193
|
+
key.unshift([opts.prefix]);
|
|
194
|
+
}
|
|
195
|
+
return key;
|
|
144
196
|
}
|
|
145
197
|
|
|
146
198
|
/**
|