@trpc/tanstack-react-query 0.0.0-alpha.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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.mjs +3 -0
- package/dist/internals/Context.d.ts +14 -0
- package/dist/internals/Context.d.ts.map +1 -0
- package/dist/internals/Context.js +52 -0
- package/dist/internals/Context.mjs +31 -0
- package/dist/internals/createOptionsProxy.d.ts +107 -0
- package/dist/internals/createOptionsProxy.d.ts.map +1 -0
- package/dist/internals/createOptionsProxy.js +99 -0
- package/dist/internals/createOptionsProxy.mjs +97 -0
- package/dist/internals/infiniteQueryOptions.d.ts +49 -0
- package/dist/internals/infiniteQueryOptions.d.ts.map +1 -0
- package/dist/internals/infiniteQueryOptions.js +39 -0
- package/dist/internals/infiniteQueryOptions.mjs +37 -0
- package/dist/internals/mutationOptions.d.ts +38 -0
- package/dist/internals/mutationOptions.d.ts.map +1 -0
- package/dist/internals/mutationOptions.js +38 -0
- package/dist/internals/mutationOptions.mjs +36 -0
- package/dist/internals/queryOptions.d.ts +61 -0
- package/dist/internals/queryOptions.d.ts.map +1 -0
- package/dist/internals/queryOptions.js +40 -0
- package/dist/internals/queryOptions.mjs +38 -0
- package/dist/internals/subscriptionOptions.d.ts +77 -0
- package/dist/internals/subscriptionOptions.d.ts.map +1 -0
- package/dist/internals/subscriptionOptions.js +173 -0
- package/dist/internals/subscriptionOptions.mjs +151 -0
- package/dist/internals/types.d.ts +41 -0
- package/dist/internals/types.d.ts.map +1 -0
- package/dist/internals/utils.d.ts +28 -0
- package/dist/internals/utils.d.ts.map +1 -0
- package/dist/internals/utils.js +112 -0
- package/dist/internals/utils.mjs +105 -0
- package/package.json +81 -0
- package/src/index.ts +25 -0
- package/src/internals/Context.tsx +46 -0
- package/src/internals/createOptionsProxy.ts +309 -0
- package/src/internals/infiniteQueryOptions.ts +233 -0
- package/src/internals/mutationOptions.ts +113 -0
- package/src/internals/queryOptions.ts +199 -0
- package/src/internals/subscriptionOptions.ts +286 -0
- package/src/internals/types.ts +47 -0
- package/src/internals/utils.ts +140 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { hashKey, skipToken } from '@tanstack/react-query';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { createTRPCOptionsResult } from './utils.mjs';
|
|
4
|
+
|
|
5
|
+
const trpcSubscriptionOptions = (args)=>{
|
|
6
|
+
const { subscribe, path, queryKey, opts } = args;
|
|
7
|
+
const input = queryKey[1]?.input;
|
|
8
|
+
const enabled = opts?.enabled ?? input !== skipToken;
|
|
9
|
+
const _subscribe = (innerOpts)=>{
|
|
10
|
+
return subscribe(path.join('.'), input ?? undefined, innerOpts);
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
...opts,
|
|
14
|
+
enabled,
|
|
15
|
+
subscribe: _subscribe,
|
|
16
|
+
queryKey,
|
|
17
|
+
trpc: createTRPCOptionsResult({
|
|
18
|
+
path
|
|
19
|
+
})
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
function useSubscription(opts) {
|
|
23
|
+
const optsRef = React.useRef(opts);
|
|
24
|
+
optsRef.current = opts;
|
|
25
|
+
const trackedProps = React.useRef(new Set([]));
|
|
26
|
+
const addTrackedProp = React.useCallback((key)=>{
|
|
27
|
+
trackedProps.current.add(key);
|
|
28
|
+
}, []);
|
|
29
|
+
const currentSubscriptionRef = React.useRef();
|
|
30
|
+
const reset = React.useCallback(()=>{
|
|
31
|
+
// unsubscribe from the previous subscription
|
|
32
|
+
currentSubscriptionRef.current?.();
|
|
33
|
+
updateState(getInitialState);
|
|
34
|
+
if (!opts.enabled) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let isStopped = false;
|
|
38
|
+
const subscription = opts.subscribe({
|
|
39
|
+
onStarted: ()=>{
|
|
40
|
+
if (!isStopped) {
|
|
41
|
+
optsRef.current.onStarted?.();
|
|
42
|
+
updateState((prev)=>({
|
|
43
|
+
...prev,
|
|
44
|
+
status: 'pending',
|
|
45
|
+
error: null
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
onData: (data)=>{
|
|
50
|
+
if (!isStopped) {
|
|
51
|
+
optsRef.current.onData?.(data);
|
|
52
|
+
updateState((prev)=>({
|
|
53
|
+
...prev,
|
|
54
|
+
status: 'pending',
|
|
55
|
+
data,
|
|
56
|
+
error: null
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
onError: (error)=>{
|
|
61
|
+
if (!isStopped) {
|
|
62
|
+
optsRef.current.onError?.(error);
|
|
63
|
+
updateState((prev)=>({
|
|
64
|
+
...prev,
|
|
65
|
+
status: 'error',
|
|
66
|
+
error
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
onConnectionStateChange: (result)=>{
|
|
71
|
+
const delta = {
|
|
72
|
+
status: result.state,
|
|
73
|
+
error: result.error
|
|
74
|
+
};
|
|
75
|
+
updateState((prev)=>{
|
|
76
|
+
return {
|
|
77
|
+
...prev,
|
|
78
|
+
...delta
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
currentSubscriptionRef.current = ()=>{
|
|
84
|
+
isStopped = true;
|
|
85
|
+
subscription.unsubscribe();
|
|
86
|
+
};
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
}, [
|
|
89
|
+
hashKey(opts.queryKey),
|
|
90
|
+
opts.enabled
|
|
91
|
+
]);
|
|
92
|
+
const getInitialState = React.useCallback(()=>{
|
|
93
|
+
return opts.enabled ? {
|
|
94
|
+
data: undefined,
|
|
95
|
+
error: null,
|
|
96
|
+
status: 'connecting',
|
|
97
|
+
reset
|
|
98
|
+
} : {
|
|
99
|
+
data: undefined,
|
|
100
|
+
error: null,
|
|
101
|
+
status: 'idle',
|
|
102
|
+
reset
|
|
103
|
+
};
|
|
104
|
+
}, [
|
|
105
|
+
opts.enabled,
|
|
106
|
+
reset
|
|
107
|
+
]);
|
|
108
|
+
const resultRef = React.useRef(getInitialState());
|
|
109
|
+
const [state, setState] = React.useState(trackResult(resultRef.current, addTrackedProp));
|
|
110
|
+
state.reset = reset;
|
|
111
|
+
const updateState = React.useCallback((callback)=>{
|
|
112
|
+
const prev = resultRef.current;
|
|
113
|
+
const next = resultRef.current = callback(prev);
|
|
114
|
+
let shouldUpdate = false;
|
|
115
|
+
for (const key of trackedProps.current){
|
|
116
|
+
if (prev[key] !== next[key]) {
|
|
117
|
+
shouldUpdate = true;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (shouldUpdate) {
|
|
122
|
+
setState(trackResult(next, addTrackedProp));
|
|
123
|
+
}
|
|
124
|
+
}, [
|
|
125
|
+
addTrackedProp
|
|
126
|
+
]);
|
|
127
|
+
React.useEffect(()=>{
|
|
128
|
+
if (!opts.enabled) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
reset();
|
|
132
|
+
return ()=>{
|
|
133
|
+
currentSubscriptionRef.current?.();
|
|
134
|
+
};
|
|
135
|
+
}, [
|
|
136
|
+
reset,
|
|
137
|
+
opts.enabled
|
|
138
|
+
]);
|
|
139
|
+
return state;
|
|
140
|
+
}
|
|
141
|
+
function trackResult(result, onTrackResult) {
|
|
142
|
+
const trackedResult = new Proxy(result, {
|
|
143
|
+
get (target, prop) {
|
|
144
|
+
onTrackResult(prop);
|
|
145
|
+
return target[prop];
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return trackedResult;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export { trpcSubscriptionOptions, useSubscription };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TRPCRequestOptions } from '@trpc/client';
|
|
2
|
+
export type ResolverDef = {
|
|
3
|
+
input: any;
|
|
4
|
+
output: any;
|
|
5
|
+
transformer: boolean;
|
|
6
|
+
errorShape: any;
|
|
7
|
+
};
|
|
8
|
+
export type ExtractCursorType<TInput> = TInput extends {
|
|
9
|
+
cursor?: any;
|
|
10
|
+
} ? TInput['cursor'] : unknown;
|
|
11
|
+
export interface TRPCReactRequestOptions extends Omit<TRPCRequestOptions, 'signal'> {
|
|
12
|
+
/**
|
|
13
|
+
* Opt out of SSR for this query by passing `ssr: false`
|
|
14
|
+
*/
|
|
15
|
+
ssr?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Opt out or into aborting request on unmount
|
|
18
|
+
*/
|
|
19
|
+
abortOnUnmount?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface TRPCQueryBaseOptions {
|
|
22
|
+
/**
|
|
23
|
+
* tRPC-related options
|
|
24
|
+
*/
|
|
25
|
+
trpc?: TRPCReactRequestOptions;
|
|
26
|
+
}
|
|
27
|
+
export interface TRPCQueryOptionsResult {
|
|
28
|
+
trpc: {
|
|
29
|
+
path: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export type QueryType = 'any' | 'infinite' | 'query';
|
|
33
|
+
export type TRPCQueryKey = [
|
|
34
|
+
readonly string[],
|
|
35
|
+
{
|
|
36
|
+
input?: unknown;
|
|
37
|
+
type?: Exclude<QueryType, 'any'>;
|
|
38
|
+
}?
|
|
39
|
+
];
|
|
40
|
+
export type TRPCMutationKey = [readonly string[]];
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/internals/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,GAAG,CAAC;IACX,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,GAAG,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,MAAM,IAAI,MAAM,SAAS;IAAE,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,GACnE,MAAM,CAAC,QAAQ,CAAC,GAChB,OAAO,CAAC;AAEZ,MAAM,WAAW,uBAEf,SAAQ,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC;IAC1C;;OAEG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,IAAI,CAAC,EAAE,uBAAuB,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,CAAC;AAErD,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,MAAM,EAAE;IACjB;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;KAAE,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import type { QueryType, TRPCMutationKey, TRPCQueryKey, TRPCQueryOptionsResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare function createTRPCOptionsResult(value: {
|
|
7
|
+
path: readonly string[];
|
|
8
|
+
}): TRPCQueryOptionsResult['trpc'];
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function getClientArgs<TOptions>(queryKey: TRPCQueryKey, opts: TOptions, infiniteParams?: {
|
|
13
|
+
pageParam: any;
|
|
14
|
+
direction: 'forward' | 'backward';
|
|
15
|
+
}): readonly [string, unknown, any];
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildQueryFromAsyncIterable(asyncIterable: AsyncIterable<unknown>, queryClient: QueryClient, queryKey: TRPCQueryKey): Promise<unknown[]>;
|
|
20
|
+
/**
|
|
21
|
+
* To allow easy interactions with groups of related queries, such as
|
|
22
|
+
* invalidating all queries of a router, we use an array as the path when
|
|
23
|
+
* storing in tanstack query.
|
|
24
|
+
**/
|
|
25
|
+
export declare function getQueryKeyInternal(path: readonly string[], input: unknown, type: QueryType): TRPCQueryKey;
|
|
26
|
+
export declare function getMutationKeyInternal(path: readonly string[]): TRPCMutationKey;
|
|
27
|
+
export declare function unwrapLazyArg<T>(valueOrLazy: T | (() => T)): T;
|
|
28
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/internals/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,YAAY,EACZ,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACzB,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAMjC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EACpC,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,EACd,cAAc,CAAC,EAAE;IACf,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;CACnC,mCAYF;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,EACrC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,YAAY,sBAsBvB;AAED;;;;IAII;AACJ,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,GACd,YAAY,CA0Cd;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,eAAe,CAKjB;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAE9D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var reactQuery = require('@tanstack/react-query');
|
|
4
|
+
var unstableCoreDoNotImport = require('@trpc/server/unstable-core-do-not-import');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
*/ function createTRPCOptionsResult(value) {
|
|
9
|
+
const path = value.path.join('.');
|
|
10
|
+
return {
|
|
11
|
+
path
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @internal
|
|
16
|
+
*/ function getClientArgs(queryKey, opts, infiniteParams) {
|
|
17
|
+
const path = queryKey[0];
|
|
18
|
+
let input = queryKey[1]?.input;
|
|
19
|
+
if (infiniteParams) {
|
|
20
|
+
input = {
|
|
21
|
+
...input ?? {},
|
|
22
|
+
...infiniteParams.pageParam ? {
|
|
23
|
+
cursor: infiniteParams.pageParam
|
|
24
|
+
} : {},
|
|
25
|
+
direction: infiniteParams.direction
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return [
|
|
29
|
+
path.join('.'),
|
|
30
|
+
input,
|
|
31
|
+
opts?.trpc
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*/ async function buildQueryFromAsyncIterable(asyncIterable, queryClient, queryKey) {
|
|
37
|
+
const queryCache = queryClient.getQueryCache();
|
|
38
|
+
const query = queryCache.build(queryClient, {
|
|
39
|
+
queryKey
|
|
40
|
+
});
|
|
41
|
+
query.setState({
|
|
42
|
+
data: [],
|
|
43
|
+
status: 'success'
|
|
44
|
+
});
|
|
45
|
+
const aggregate = [];
|
|
46
|
+
for await (const value of asyncIterable){
|
|
47
|
+
aggregate.push(value);
|
|
48
|
+
query.setState({
|
|
49
|
+
data: [
|
|
50
|
+
...aggregate
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return aggregate;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* To allow easy interactions with groups of related queries, such as
|
|
58
|
+
* invalidating all queries of a router, we use an array as the path when
|
|
59
|
+
* storing in tanstack query.
|
|
60
|
+
**/ function getQueryKeyInternal(path, input, type) {
|
|
61
|
+
// Construct a query key that is easy to destructure and flexible for
|
|
62
|
+
// partial selecting etc.
|
|
63
|
+
// https://github.com/trpc/trpc/issues/3128
|
|
64
|
+
// some parts of the path may be dot-separated, split them up
|
|
65
|
+
const splitPath = path.flatMap((part)=>part.split('.'));
|
|
66
|
+
if (!input && (!type || type === 'any')) {
|
|
67
|
+
// this matches also all mutations (see `getMutationKeyInternal`)
|
|
68
|
+
// for `utils.invalidate()` to match all queries (including vanilla react-query)
|
|
69
|
+
// we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
|
|
70
|
+
return splitPath.length ? [
|
|
71
|
+
splitPath
|
|
72
|
+
] : [];
|
|
73
|
+
}
|
|
74
|
+
if (type === 'infinite' && unstableCoreDoNotImport.isObject(input) && ('direction' in input || 'cursor' in input)) {
|
|
75
|
+
const { cursor: _, direction: __, ...inputWithoutCursorAndDirection } = input;
|
|
76
|
+
return [
|
|
77
|
+
splitPath,
|
|
78
|
+
{
|
|
79
|
+
input: inputWithoutCursorAndDirection,
|
|
80
|
+
type: 'infinite'
|
|
81
|
+
}
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
return [
|
|
85
|
+
splitPath,
|
|
86
|
+
{
|
|
87
|
+
...typeof input !== 'undefined' && input !== reactQuery.skipToken && {
|
|
88
|
+
input: input
|
|
89
|
+
},
|
|
90
|
+
...type && type !== 'any' && {
|
|
91
|
+
type: type
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
function getMutationKeyInternal(path) {
|
|
97
|
+
// some parts of the path may be dot-separated, split them up
|
|
98
|
+
const splitPath = path.flatMap((part)=>part.split('.'));
|
|
99
|
+
return splitPath.length ? [
|
|
100
|
+
splitPath
|
|
101
|
+
] : [];
|
|
102
|
+
}
|
|
103
|
+
function unwrapLazyArg(valueOrLazy) {
|
|
104
|
+
return unstableCoreDoNotImport.isFunction(valueOrLazy) ? valueOrLazy() : valueOrLazy;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
exports.buildQueryFromAsyncIterable = buildQueryFromAsyncIterable;
|
|
108
|
+
exports.createTRPCOptionsResult = createTRPCOptionsResult;
|
|
109
|
+
exports.getClientArgs = getClientArgs;
|
|
110
|
+
exports.getMutationKeyInternal = getMutationKeyInternal;
|
|
111
|
+
exports.getQueryKeyInternal = getQueryKeyInternal;
|
|
112
|
+
exports.unwrapLazyArg = unwrapLazyArg;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { skipToken } from '@tanstack/react-query';
|
|
2
|
+
import { isObject, isFunction } from '@trpc/server/unstable-core-do-not-import';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
*/ function createTRPCOptionsResult(value) {
|
|
7
|
+
const path = value.path.join('.');
|
|
8
|
+
return {
|
|
9
|
+
path
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/ function getClientArgs(queryKey, opts, infiniteParams) {
|
|
15
|
+
const path = queryKey[0];
|
|
16
|
+
let input = queryKey[1]?.input;
|
|
17
|
+
if (infiniteParams) {
|
|
18
|
+
input = {
|
|
19
|
+
...input ?? {},
|
|
20
|
+
...infiniteParams.pageParam ? {
|
|
21
|
+
cursor: infiniteParams.pageParam
|
|
22
|
+
} : {},
|
|
23
|
+
direction: infiniteParams.direction
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return [
|
|
27
|
+
path.join('.'),
|
|
28
|
+
input,
|
|
29
|
+
opts?.trpc
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @internal
|
|
34
|
+
*/ async function buildQueryFromAsyncIterable(asyncIterable, queryClient, queryKey) {
|
|
35
|
+
const queryCache = queryClient.getQueryCache();
|
|
36
|
+
const query = queryCache.build(queryClient, {
|
|
37
|
+
queryKey
|
|
38
|
+
});
|
|
39
|
+
query.setState({
|
|
40
|
+
data: [],
|
|
41
|
+
status: 'success'
|
|
42
|
+
});
|
|
43
|
+
const aggregate = [];
|
|
44
|
+
for await (const value of asyncIterable){
|
|
45
|
+
aggregate.push(value);
|
|
46
|
+
query.setState({
|
|
47
|
+
data: [
|
|
48
|
+
...aggregate
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return aggregate;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* To allow easy interactions with groups of related queries, such as
|
|
56
|
+
* invalidating all queries of a router, we use an array as the path when
|
|
57
|
+
* storing in tanstack query.
|
|
58
|
+
**/ function getQueryKeyInternal(path, input, type) {
|
|
59
|
+
// Construct a query key that is easy to destructure and flexible for
|
|
60
|
+
// partial selecting etc.
|
|
61
|
+
// https://github.com/trpc/trpc/issues/3128
|
|
62
|
+
// some parts of the path may be dot-separated, split them up
|
|
63
|
+
const splitPath = path.flatMap((part)=>part.split('.'));
|
|
64
|
+
if (!input && (!type || type === 'any')) {
|
|
65
|
+
// this matches also all mutations (see `getMutationKeyInternal`)
|
|
66
|
+
// for `utils.invalidate()` to match all queries (including vanilla react-query)
|
|
67
|
+
// we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
|
|
68
|
+
return splitPath.length ? [
|
|
69
|
+
splitPath
|
|
70
|
+
] : [];
|
|
71
|
+
}
|
|
72
|
+
if (type === 'infinite' && isObject(input) && ('direction' in input || 'cursor' in input)) {
|
|
73
|
+
const { cursor: _, direction: __, ...inputWithoutCursorAndDirection } = input;
|
|
74
|
+
return [
|
|
75
|
+
splitPath,
|
|
76
|
+
{
|
|
77
|
+
input: inputWithoutCursorAndDirection,
|
|
78
|
+
type: 'infinite'
|
|
79
|
+
}
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
return [
|
|
83
|
+
splitPath,
|
|
84
|
+
{
|
|
85
|
+
...typeof input !== 'undefined' && input !== skipToken && {
|
|
86
|
+
input: input
|
|
87
|
+
},
|
|
88
|
+
...type && type !== 'any' && {
|
|
89
|
+
type: type
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
function getMutationKeyInternal(path) {
|
|
95
|
+
// some parts of the path may be dot-separated, split them up
|
|
96
|
+
const splitPath = path.flatMap((part)=>part.split('.'));
|
|
97
|
+
return splitPath.length ? [
|
|
98
|
+
splitPath
|
|
99
|
+
] : [];
|
|
100
|
+
}
|
|
101
|
+
function unwrapLazyArg(valueOrLazy) {
|
|
102
|
+
return isFunction(valueOrLazy) ? valueOrLazy() : valueOrLazy;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { buildQueryFromAsyncIterable, createTRPCOptionsResult, getClientArgs, getMutationKeyInternal, getQueryKeyInternal, unwrapLazyArg };
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trpc/tanstack-react-query",
|
|
3
|
+
"version": "0.0.0-alpha.0",
|
|
4
|
+
"description": "Tanstack React Query Integration for tRPC",
|
|
5
|
+
"author": "juliusmarminge",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"typings": "dist/index.d.ts",
|
|
10
|
+
"homepage": "https://trpc.io",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/trpc/trpc.git",
|
|
14
|
+
"directory": "packages/tanstack-react-query"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
"./package.json": "./package.json",
|
|
18
|
+
".": {
|
|
19
|
+
"import": "./dist/index.mjs",
|
|
20
|
+
"require": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"src",
|
|
27
|
+
"README.md",
|
|
28
|
+
"package.json",
|
|
29
|
+
"!**/*.test.*",
|
|
30
|
+
"!**/__tests__"
|
|
31
|
+
],
|
|
32
|
+
"eslintConfig": {
|
|
33
|
+
"rules": {
|
|
34
|
+
"react-hooks/exhaustive-deps": "error",
|
|
35
|
+
"no-restricted-imports": [
|
|
36
|
+
"error",
|
|
37
|
+
"@trpc/tanstack-react-query"
|
|
38
|
+
],
|
|
39
|
+
"@typescript-eslint/prefer-function-type": "off"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@tanstack/react-query": "^5.59.15",
|
|
45
|
+
"@trpc/client": "10.45.1",
|
|
46
|
+
"@trpc/server": "^10.45.1",
|
|
47
|
+
"react": ">=18.2.0",
|
|
48
|
+
"react-dom": ">=18.2.0",
|
|
49
|
+
"typescript": ">=5.6.2"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@tanstack/react-query": "^5.59.15",
|
|
53
|
+
"@trpc/client": "10.45.1",
|
|
54
|
+
"@trpc/server": "^10.45.1",
|
|
55
|
+
"@types/node": "^20.10.0",
|
|
56
|
+
"@types/react": "^18.3.1",
|
|
57
|
+
"eslint": "^8.57.0",
|
|
58
|
+
"konn": "^0.7.0",
|
|
59
|
+
"react": "^18.3.1",
|
|
60
|
+
"react-dom": "^18.3.1",
|
|
61
|
+
"rollup": "^4.9.5",
|
|
62
|
+
"tsx": "^4.0.0",
|
|
63
|
+
"typescript": "^5.6.2",
|
|
64
|
+
"vitest": "^2.0.4",
|
|
65
|
+
"zod": "^3.0.0"
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"funding": [
|
|
71
|
+
"https://trpc.io/sponsor"
|
|
72
|
+
],
|
|
73
|
+
"scripts": {
|
|
74
|
+
"build": "rollup --config rollup.config.ts --configPlugin rollup-plugin-swc3",
|
|
75
|
+
"dev": "pnpm build --watch",
|
|
76
|
+
"codegen-entrypoints": "tsx entrypoints.script.ts",
|
|
77
|
+
"lint": "eslint --cache src",
|
|
78
|
+
"test-run:tsc": "tsc --noEmit --pretty",
|
|
79
|
+
"ts-watch": "tsc --watch"
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export { createTRPCContext } from './internals/Context';
|
|
2
|
+
export type {
|
|
3
|
+
TRPCOptionsProxy,
|
|
4
|
+
InferInput,
|
|
5
|
+
InferOutput,
|
|
6
|
+
DecorateMutationProcedure,
|
|
7
|
+
DecorateProcedure,
|
|
8
|
+
DecorateQueryKeyable,
|
|
9
|
+
DecorateQueryProcedure,
|
|
10
|
+
DecorateSubscriptionProcedure,
|
|
11
|
+
} from './internals/createOptionsProxy';
|
|
12
|
+
export type { TRPCQueryOptions } from './internals/queryOptions';
|
|
13
|
+
export type { TRPCInfiniteQueryOptions } from './internals/infiniteQueryOptions';
|
|
14
|
+
export type { TRPCMutationOptions } from './internals/mutationOptions';
|
|
15
|
+
export type {
|
|
16
|
+
TRPCSubscriptionOptions,
|
|
17
|
+
TRPCSubscriptionStatus,
|
|
18
|
+
TRPCSubscriptionConnectingResult,
|
|
19
|
+
TRPCSubscriptionErrorResult,
|
|
20
|
+
TRPCSubscriptionIdleResult,
|
|
21
|
+
TRPCSubscriptionPendingResult,
|
|
22
|
+
TRPCSubscriptionResult,
|
|
23
|
+
} from './internals/subscriptionOptions';
|
|
24
|
+
export { createTRPCOptionsProxy } from './internals/createOptionsProxy';
|
|
25
|
+
export { useSubscription } from './internals/subscriptionOptions';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { type CreateTRPCClient } from '@trpc/client';
|
|
3
|
+
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import {
|
|
6
|
+
createTRPCOptionsProxy,
|
|
7
|
+
type TRPCOptionsProxy,
|
|
8
|
+
} from './createOptionsProxy';
|
|
9
|
+
|
|
10
|
+
export function createTRPCContext<TRouter extends AnyRouter>() {
|
|
11
|
+
const TRPCContext = React.createContext<TRPCOptionsProxy<TRouter> | null>(
|
|
12
|
+
null,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
function TRPCProvider(
|
|
16
|
+
props: Readonly<{
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
queryClient: QueryClient;
|
|
19
|
+
trpcClient: CreateTRPCClient<TRouter>;
|
|
20
|
+
}>,
|
|
21
|
+
) {
|
|
22
|
+
const value = React.useMemo(
|
|
23
|
+
() =>
|
|
24
|
+
createTRPCOptionsProxy({
|
|
25
|
+
client: props.trpcClient,
|
|
26
|
+
queryClient: props.queryClient,
|
|
27
|
+
}),
|
|
28
|
+
[props.trpcClient, props.queryClient],
|
|
29
|
+
);
|
|
30
|
+
return (
|
|
31
|
+
<TRPCContext.Provider value={value}>
|
|
32
|
+
{props.children}
|
|
33
|
+
</TRPCContext.Provider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function useTRPC() {
|
|
38
|
+
const utils = React.useContext(TRPCContext);
|
|
39
|
+
if (!utils) {
|
|
40
|
+
throw new Error('useTRPC() can only be used inside of a <TRPCProvider>');
|
|
41
|
+
}
|
|
42
|
+
return utils;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { TRPCProvider, useTRPC };
|
|
46
|
+
}
|