@falcondev-oss/trpc-vue-query 0.5.0-rc.0 → 0.5.0-rc.10

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/README.md CHANGED
@@ -20,9 +20,10 @@ pnpm add @falcondev-oss/trpc-vue-query
20
20
 
21
21
  ```ts
22
22
  import { createTRPCVueQueryClient } from '@falcondev-oss/trpc-vue-query'
23
- import type { AppRouter } from '../your_server/trpc'
24
23
  import { VueQueryPlugin, useQueryClient } from '@tanstack/vue-query'
25
24
 
25
+ import type { AppRouter } from '../your_server/trpc'
26
+
26
27
  app.use(VueQueryPlugin)
27
28
  app.use({
28
29
  install(app) {
@@ -45,6 +46,7 @@ app.use({
45
46
 
46
47
  ```ts
47
48
  import { createTRPCVueQueryClient } from '@falcondev-oss/trpc-vue-query'
49
+
48
50
  import type { AppRouter } from '../your_server/trpc'
49
51
 
50
52
  export function useTRPC() {
@@ -116,6 +118,7 @@ Setup `trpc-nuxt` as described in their [documentation](https://trpc-nuxt.vercel
116
118
  import { createTRPCVueQueryClient } from '@falcondev-oss/trpc-vue-query'
117
119
  import { useQueryClient } from '@tanstack/vue-query'
118
120
  import { httpBatchLink } from 'trpc-nuxt/client'
121
+
119
122
  import type { AppRouter } from '~/server/trpc/routers'
120
123
 
121
124
  export default defineNuxtPlugin(() => {
@@ -149,4 +152,4 @@ export function useTRPC() {
149
152
 
150
153
  ## Acknowledgements
151
154
 
152
- Huge thanks to [Robert Soriano](https://github.com/wobsoriano) for creating `nuxt-trpc`! We just adapted his work to work with Vue Query.
155
+ Huge thanks to [Robert Soriano](https://github.com/wobsoriano) for creating `trpc-nuxt`! We just adapted his work to work with Vue Query.
package/dist/index.cjs CHANGED
@@ -29,60 +29,138 @@ var import_server = require("@trpc/server");
29
29
  var import_unstable_core_do_not_import = require("@trpc/server/unstable-core-do-not-import");
30
30
  var import_core = require("@vueuse/core");
31
31
  var import_vue = require("vue");
32
- function getQueryKey(path, input) {
33
- return input === void 0 ? path : [...path, input];
32
+ function getQueryKey(path, input, type) {
33
+ const splitPath = path.flatMap((part) => part.split("."));
34
+ if (input === void 0 && !type) {
35
+ return splitPath.length > 0 ? [splitPath] : [];
36
+ }
37
+ return [
38
+ splitPath,
39
+ {
40
+ ...input !== void 0 && input !== import_vue_query.skipToken && { input },
41
+ ...type && { type }
42
+ }
43
+ ];
34
44
  }
35
45
  function maybeToRefs(obj) {
36
46
  return (0, import_vue.isReactive)(obj) ? (0, import_core.toRefs)(obj) : (0, import_core.toRefs)((0, import_core.toRef)(obj));
37
47
  }
38
- function createVueQueryProxyDecoration(name, client, queryClient) {
39
- return (0, import_unstable_core_do_not_import.createRecursiveProxy)((opts) => {
40
- const args = opts.args;
41
- const path = [name, ...opts.path];
42
- const lastProperty = path.pop();
48
+ function createVueQueryProxyDecoration(name, trpc, queryClient) {
49
+ return (0, import_unstable_core_do_not_import.createRecursiveProxy)(({ args, path: _path }) => {
50
+ const path = [name, ..._path];
51
+ const prop = path.pop();
43
52
  const joinedPath = path.join(".");
44
- const [firstParam, secondParam] = args;
45
- if (lastProperty === "_def") {
53
+ const [firstArg, ...rest] = args;
54
+ const opts = rest[0] || {};
55
+ if (prop === "_def") {
46
56
  return { path };
47
57
  }
48
- if (lastProperty === "useQuery") {
49
- const { trpc, ...queryOptions } = secondParam || {};
50
- return (0, import_vue_query.useQuery)({
51
- queryKey: (0, import_vue.computed)(() => getQueryKey(path, (0, import_core.toValue)(firstParam))),
52
- queryFn: ({ queryKey, signal }) => client[joinedPath].query(queryKey.at(-1), {
53
- signal,
54
- ...trpc
58
+ if (prop === "query") {
59
+ return trpc.query(joinedPath, firstArg, opts);
60
+ }
61
+ function createQuery(_input, { trpcOptions, queryOptions }) {
62
+ const input = (0, import_core.toValue)(_input);
63
+ return (0, import_vue_query.queryOptions)({
64
+ queryKey: (0, import_vue.computed)(() => getQueryKey(path, input, "query")),
65
+ queryFn: async ({ signal }) => ({
66
+ output: await trpc.query(joinedPath, input, {
67
+ signal,
68
+ ...trpcOptions
69
+ }),
70
+ input
55
71
  }),
56
72
  ...maybeToRefs(queryOptions)
57
73
  });
58
74
  }
59
- if (lastProperty === "invalidate") {
75
+ if (prop === "useQuery") {
76
+ const { trpc: trpcOptions, ...queryOptions } = opts;
77
+ const input = firstArg;
78
+ return (0, import_vue_query.useQuery)(createQuery(input, { trpcOptions, queryOptions }));
79
+ }
80
+ if (prop === "useQueries") {
81
+ const { trpc: trpcOptions, combine, shallow, ...queryOptions } = opts;
82
+ const inputs = firstArg;
83
+ return (0, import_vue_query.useQueries)({
84
+ queries: (0, import_vue.computed)(
85
+ () => (0, import_core.toValue)(inputs).map((i) => createQuery(i, { trpcOptions, queryOptions }))
86
+ ),
87
+ combine,
88
+ ...maybeToRefs({ shallow })
89
+ });
90
+ }
91
+ if (prop === "invalidate") {
60
92
  return queryClient.invalidateQueries({
61
- queryKey: getQueryKey(path, (0, import_core.toValue)(firstParam))
93
+ queryKey: getQueryKey(path, (0, import_core.toValue)(firstArg), "query")
62
94
  });
63
95
  }
64
- if (lastProperty === "setQueryData") {
65
- return queryClient.setQueryData(getQueryKey(path, (0, import_core.toValue)(secondParam)), firstParam);
96
+ if (prop === "setQueryData") {
97
+ return queryClient.setQueryData(getQueryKey(path, (0, import_core.toValue)(opts), "query"), firstArg);
66
98
  }
67
- if (lastProperty === "key") {
68
- return getQueryKey(path, (0, import_core.toValue)(firstParam));
99
+ if (prop === "key") {
100
+ return getQueryKey(path, (0, import_core.toValue)(firstArg), "query");
69
101
  }
70
- if (lastProperty === "useMutation") {
71
- const { trpc, ...mutationOptions } = firstParam || {};
102
+ if (prop === "mutate") {
103
+ return trpc.mutation(joinedPath, firstArg, opts);
104
+ }
105
+ if (prop === "useMutation") {
106
+ const { trpc: trpcOptions, ...mutationOptions } = firstArg || {};
72
107
  return (0, import_vue_query.useMutation)({
73
- mutationFn: (payload) => client[joinedPath].mutate(payload, {
74
- ...trpc
108
+ mutationKey: (0, import_vue.computed)(() => getQueryKey(path, void 0)),
109
+ mutationFn: async (payload) => trpc.mutation(joinedPath, payload, {
110
+ ...trpcOptions
75
111
  }),
76
112
  ...maybeToRefs(mutationOptions)
77
113
  });
78
114
  }
79
- return client[joinedPath][lastProperty](...args);
115
+ if (prop === "subscribe") {
116
+ return trpc.subscription(joinedPath, firstArg, opts);
117
+ }
118
+ if (prop === "useSubscription") {
119
+ const inputData = (0, import_core.toRef)(firstArg);
120
+ const subscription = (0, import_vue.shallowRef)();
121
+ (0, import_vue.watch)(
122
+ inputData,
123
+ () => {
124
+ subscription.value?.unsubscribe();
125
+ subscription.value = trpc.subscription(joinedPath, inputData.value, {
126
+ ...opts
127
+ });
128
+ },
129
+ { immediate: true }
130
+ );
131
+ (0, import_vue.onScopeDispose)(() => {
132
+ subscription.value?.unsubscribe();
133
+ }, true);
134
+ return subscription.value;
135
+ }
136
+ if (prop === "useInfiniteQuery") {
137
+ const { trpc: trpcOptions, ...queryOptions } = opts;
138
+ return (0, import_vue_query.useInfiniteQuery)({
139
+ queryKey: (0, import_vue.computed)(() => getQueryKey(path, (0, import_core.toValue)(firstArg), "infinite")),
140
+ queryFn: async ({ queryKey, pageParam, signal }) => trpc.query(
141
+ joinedPath,
142
+ {
143
+ ...queryKey[1]?.input,
144
+ cursor: pageParam
145
+ },
146
+ {
147
+ signal,
148
+ ...trpcOptions
149
+ }
150
+ ),
151
+ ...maybeToRefs(queryOptions)
152
+ });
153
+ }
154
+ throw new Error(`Method '.${prop}()' not supported`);
80
155
  });
81
156
  }
82
- function createTRPCVueQueryClient(opts) {
83
- const client = (0, import_client.createTRPCClient)(opts.trpc);
157
+ function createTRPCVueQueryClient({
158
+ trpc,
159
+ queryClient
160
+ }) {
161
+ const client = (0, import_client.createTRPCUntypedClient)(trpc);
84
162
  const decoratedClient = (0, import_server.createTRPCFlatProxy)((key) => {
85
- return createVueQueryProxyDecoration(key, client, opts.queryClient);
163
+ return createVueQueryProxyDecoration(key, client, queryClient);
86
164
  });
87
165
  return decoratedClient;
88
166
  }
package/dist/index.d.cts CHANGED
@@ -1,36 +1,59 @@
1
- import { QueryKey, UseQueryOptions, UseQueryReturnType, QueryClient, UseMutationOptions, UseMutationReturnType } from '@tanstack/vue-query';
2
- import { TRPCClientErrorLike, TRPCRequestOptions, CreateTRPCClientOptions } from '@trpc/client';
1
+ import { QueryKey, UseQueryOptions, UseQueryReturnType, UseQueriesResults, QueryClient, InfiniteData, UseInfiniteQueryOptions, InitialPageParam, UseInfiniteQueryReturnType, UseMutationOptions, UseMutationReturnType } from '@tanstack/vue-query';
2
+ import { TRPCClientErrorLike, TRPCRequestOptions, OperationContext, CreateTRPCClientOptions } from '@trpc/client';
3
3
  import { AnyTRPCRouter, AnyTRPCProcedure, AnyTRPCQueryProcedure, inferTransformedProcedureOutput, inferProcedureInput, AnyTRPCMutationProcedure, AnyTRPCSubscriptionProcedure, inferProcedureOutput } from '@trpc/server';
4
- import { inferObservableValue, Unsubscribable } from '@trpc/server/observable';
4
+ import { Unsubscribable } from '@trpc/server/observable';
5
5
  import { ProcedureOptions } from '@trpc/server/unstable-core-do-not-import';
6
- import { MaybeRefOrGetter, UnwrapRef } from 'vue';
6
+ import { MaybeRefOrGetter, UnwrapRef, Ref } from 'vue';
7
7
 
8
+ type inferAsyncIterableYield<T> = T extends AsyncIterable<infer U> ? U : T;
8
9
  type TRPCSubscriptionObserver<TValue, TError> = {
9
- onStarted: () => void;
10
- onData: (value: TValue) => void;
10
+ onStarted: (opts: {
11
+ context: OperationContext | undefined;
12
+ }) => void;
13
+ onData: (value: inferAsyncIterableYield<TValue>) => void;
11
14
  onError: (err: TError) => void;
12
15
  onStopped: () => void;
13
16
  onComplete: () => void;
14
17
  };
15
- type Resolver<TRouter extends AnyTRPCRouter, TProcedure extends AnyTRPCProcedure> = (input: inferProcedureInput<TProcedure>, opts?: ProcedureOptions) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>;
16
- type SubscriptionResolver<TProcedure extends AnyTRPCProcedure, TRouter extends AnyTRPCRouter> = (input: inferProcedureInput<TProcedure>, opts: ProcedureOptions & Partial<TRPCSubscriptionObserver<inferObservableValue<inferProcedureOutput<TProcedure>>, TRPCClientErrorLike<TRouter>>>) => Unsubscribable;
18
+ type ArrayElement<T> = T extends readonly unknown[] ? T[number] : never;
19
+ type Primitive = null | undefined | string | number | boolean | symbol | bigint;
20
+ type Exact<Shape, T extends Shape> = Shape extends Primitive ? Shape : Shape extends object ? {
21
+ [Key in keyof T]: Key extends keyof Shape ? T[Key] extends Date ? T[Key] : T[Key] extends unknown[] ? Array<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>> : T[Key] extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>> : T[Key] extends object ? Exact<Shape[Key], T[Key]> : T[Key] : never;
22
+ } : Shape;
17
23
  type DecorateProcedure<TProcedure extends AnyTRPCProcedure, TRouter extends AnyTRPCRouter> = TProcedure extends AnyTRPCQueryProcedure ? {
18
- useQuery: <TQueryFnData = inferTransformedProcedureOutput<TRouter, TProcedure>, TError = TRPCClientErrorLike<TRouter>, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(input: MaybeRefOrGetter<inferProcedureInput<TProcedure>>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, 'queryKey'> & {
24
+ useQuery: <TQueryFnData extends inferTransformedProcedureOutput<TRouter, TProcedure>, TError extends TRPCClientErrorLike<TRouter>, TData extends TQueryFnData, TQueryData extends TQueryFnData, TQueryKey extends QueryKey, TInput extends inferProcedureInput<TProcedure>>(input: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, 'queryKey'> & {
19
25
  trpc?: TRPCRequestOptions;
20
26
  queryKey?: TQueryKey;
21
27
  }>) => UseQueryReturnType<TData, TError>;
22
- query: Resolver<TRouter, TProcedure>;
23
- invalidate: (input?: MaybeRefOrGetter<inferProcedureInput<TProcedure>>) => Promise<void>;
24
- setQueryData: (updater: inferTransformedProcedureOutput<TRouter, TProcedure>, input?: MaybeRefOrGetter<inferProcedureInput<TProcedure>>) => ReturnType<QueryClient['setQueryData']>;
25
- key: (input?: MaybeRefOrGetter<inferProcedureInput<TProcedure>>) => QueryKey;
26
- } : TProcedure extends AnyTRPCMutationProcedure ? {
27
- mutate: Resolver<TRouter, TProcedure>;
28
+ useQueries: <TQueryFnData extends {
29
+ output: inferTransformedProcedureOutput<TRouter, TProcedure>;
30
+ input: inferProcedureInput<TProcedure>;
31
+ }, TError extends TRPCClientErrorLike<TRouter>, TData extends TQueryFnData, TQueryData extends TQueryFnData, TQueryKey extends QueryKey, TInput extends inferProcedureInput<TProcedure>, TQueries extends UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, TCombinedResult = UseQueriesResults<TQueries[]>>(inputs: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>[]>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<TQueries>, 'queryKey'> & {
32
+ trpc?: TRPCRequestOptions;
33
+ queryKey?: never;
34
+ combine?: (result: UseQueriesResults<TQueries[]>) => TCombinedResult;
35
+ shallow?: boolean;
36
+ }>) => Readonly<Ref<TCombinedResult>>;
37
+ query: <TInput extends inferProcedureInput<TProcedure>>(input: Exact<inferProcedureInput<TProcedure>, TInput>, opts?: ProcedureOptions) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>;
38
+ invalidate: <TInput extends inferProcedureInput<TProcedure>>(input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>) => Promise<void>;
39
+ setQueryData: <TInput extends inferProcedureInput<TProcedure>>(updater: inferTransformedProcedureOutput<TRouter, TProcedure>, input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>) => ReturnType<QueryClient['setQueryData']>;
40
+ key: <TInput extends inferProcedureInput<TProcedure>>(input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>) => QueryKey;
41
+ } & (TProcedure['_def']['$types']['input'] extends {
42
+ cursor?: infer CursorType;
43
+ } ? {
44
+ useInfiniteQuery: <TQueryFnData extends inferTransformedProcedureOutput<TRouter, TProcedure>, TError extends TRPCClientErrorLike<TRouter>, TData extends InfiniteData<TQueryFnData>, TQueryData extends TQueryFnData, TQueryKey extends QueryKey, TInput extends inferProcedureInput<TProcedure>>(input: MaybeRefOrGetter<Exact<Omit<inferProcedureInput<TProcedure>, 'cursor'>, TInput>>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, 'queryKey' | keyof InitialPageParam> & {
45
+ trpc?: TRPCRequestOptions;
46
+ queryKey?: TQueryKey;
47
+ } & (undefined extends TProcedure['_def']['$types']['input']['cursor'] ? Partial<InitialPageParam<CursorType>> : InitialPageParam<CursorType>)>) => UseInfiniteQueryReturnType<TData, TError>;
48
+ } : object) : TProcedure extends AnyTRPCMutationProcedure ? {
49
+ mutate: <TInput extends inferProcedureInput<TProcedure>>(input: Exact<inferProcedureInput<TProcedure>, TInput>, opts?: ProcedureOptions) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>;
28
50
  useMutation: <TData = inferTransformedProcedureOutput<TRouter, TProcedure>, TError = TRPCClientErrorLike<TRouter>, TVariables = inferProcedureInput<TProcedure>, TContext = unknown>(opts?: MaybeRefOrGetter<UseMutationOptions<TData, TError, TVariables, TContext> & {
29
51
  trpc?: TRPCRequestOptions;
30
52
  }>) => UseMutationReturnType<TData, TError, TVariables, TContext>;
31
53
  } : TProcedure extends AnyTRPCSubscriptionProcedure ? {
32
- subscribe: SubscriptionResolver<TProcedure, TRouter>;
33
- } : 'test';
54
+ subscribe: <TInput extends inferProcedureInput<TProcedure>>(input: Exact<inferProcedureInput<TProcedure>, TInput>, opts: ProcedureOptions & Partial<TRPCSubscriptionObserver<inferProcedureOutput<TProcedure>, TRPCClientErrorLike<TRouter>>>) => Unsubscribable;
55
+ useSubscription: <TInput extends inferProcedureInput<TProcedure>>(input: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>, opts: ProcedureOptions & Partial<TRPCSubscriptionObserver<inferProcedureOutput<TProcedure>, TRPCClientErrorLike<TRouter>>>) => Unsubscribable;
56
+ } : never;
34
57
  /**
35
58
  * @internal
36
59
  */
@@ -38,9 +61,15 @@ type DecoratedProcedureRecord<TProcedures extends Record<string, any>, TRouter e
38
61
  [K in keyof TProcedures]: TProcedures[K] extends AnyTRPCProcedure ? DecorateProcedure<TProcedures[K], TRouter> : DecoratedProcedureRecord<TProcedures[K], TRouter>;
39
62
  };
40
63
 
41
- declare function createTRPCVueQueryClient<TRouter extends AnyTRPCRouter>(opts: {
64
+ type QueryType = 'query' | 'infinite';
65
+ type TRPCQueryKey = [readonly string[], {
66
+ input?: unknown;
67
+ type?: QueryType;
68
+ }?];
69
+
70
+ declare function createTRPCVueQueryClient<TRouter extends AnyTRPCRouter>({ trpc, queryClient, }: {
42
71
  queryClient: QueryClient;
43
72
  trpc: CreateTRPCClientOptions<TRouter>;
44
73
  }): DecoratedProcedureRecord<TRouter["_def"]["record"], TRouter>;
45
74
 
46
- export { createTRPCVueQueryClient };
75
+ export { type Exact, type TRPCQueryKey, createTRPCVueQueryClient };
package/dist/index.d.ts CHANGED
@@ -1,36 +1,59 @@
1
- import { QueryKey, UseQueryOptions, UseQueryReturnType, QueryClient, UseMutationOptions, UseMutationReturnType } from '@tanstack/vue-query';
2
- import { TRPCClientErrorLike, TRPCRequestOptions, CreateTRPCClientOptions } from '@trpc/client';
1
+ import { QueryKey, UseQueryOptions, UseQueryReturnType, UseQueriesResults, QueryClient, InfiniteData, UseInfiniteQueryOptions, InitialPageParam, UseInfiniteQueryReturnType, UseMutationOptions, UseMutationReturnType } from '@tanstack/vue-query';
2
+ import { TRPCClientErrorLike, TRPCRequestOptions, OperationContext, CreateTRPCClientOptions } from '@trpc/client';
3
3
  import { AnyTRPCRouter, AnyTRPCProcedure, AnyTRPCQueryProcedure, inferTransformedProcedureOutput, inferProcedureInput, AnyTRPCMutationProcedure, AnyTRPCSubscriptionProcedure, inferProcedureOutput } from '@trpc/server';
4
- import { inferObservableValue, Unsubscribable } from '@trpc/server/observable';
4
+ import { Unsubscribable } from '@trpc/server/observable';
5
5
  import { ProcedureOptions } from '@trpc/server/unstable-core-do-not-import';
6
- import { MaybeRefOrGetter, UnwrapRef } from 'vue';
6
+ import { MaybeRefOrGetter, UnwrapRef, Ref } from 'vue';
7
7
 
8
+ type inferAsyncIterableYield<T> = T extends AsyncIterable<infer U> ? U : T;
8
9
  type TRPCSubscriptionObserver<TValue, TError> = {
9
- onStarted: () => void;
10
- onData: (value: TValue) => void;
10
+ onStarted: (opts: {
11
+ context: OperationContext | undefined;
12
+ }) => void;
13
+ onData: (value: inferAsyncIterableYield<TValue>) => void;
11
14
  onError: (err: TError) => void;
12
15
  onStopped: () => void;
13
16
  onComplete: () => void;
14
17
  };
15
- type Resolver<TRouter extends AnyTRPCRouter, TProcedure extends AnyTRPCProcedure> = (input: inferProcedureInput<TProcedure>, opts?: ProcedureOptions) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>;
16
- type SubscriptionResolver<TProcedure extends AnyTRPCProcedure, TRouter extends AnyTRPCRouter> = (input: inferProcedureInput<TProcedure>, opts: ProcedureOptions & Partial<TRPCSubscriptionObserver<inferObservableValue<inferProcedureOutput<TProcedure>>, TRPCClientErrorLike<TRouter>>>) => Unsubscribable;
18
+ type ArrayElement<T> = T extends readonly unknown[] ? T[number] : never;
19
+ type Primitive = null | undefined | string | number | boolean | symbol | bigint;
20
+ type Exact<Shape, T extends Shape> = Shape extends Primitive ? Shape : Shape extends object ? {
21
+ [Key in keyof T]: Key extends keyof Shape ? T[Key] extends Date ? T[Key] : T[Key] extends unknown[] ? Array<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>> : T[Key] extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<Shape[Key]>, ArrayElement<T[Key]>>> : T[Key] extends object ? Exact<Shape[Key], T[Key]> : T[Key] : never;
22
+ } : Shape;
17
23
  type DecorateProcedure<TProcedure extends AnyTRPCProcedure, TRouter extends AnyTRPCRouter> = TProcedure extends AnyTRPCQueryProcedure ? {
18
- useQuery: <TQueryFnData = inferTransformedProcedureOutput<TRouter, TProcedure>, TError = TRPCClientErrorLike<TRouter>, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(input: MaybeRefOrGetter<inferProcedureInput<TProcedure>>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, 'queryKey'> & {
24
+ useQuery: <TQueryFnData extends inferTransformedProcedureOutput<TRouter, TProcedure>, TError extends TRPCClientErrorLike<TRouter>, TData extends TQueryFnData, TQueryData extends TQueryFnData, TQueryKey extends QueryKey, TInput extends inferProcedureInput<TProcedure>>(input: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, 'queryKey'> & {
19
25
  trpc?: TRPCRequestOptions;
20
26
  queryKey?: TQueryKey;
21
27
  }>) => UseQueryReturnType<TData, TError>;
22
- query: Resolver<TRouter, TProcedure>;
23
- invalidate: (input?: MaybeRefOrGetter<inferProcedureInput<TProcedure>>) => Promise<void>;
24
- setQueryData: (updater: inferTransformedProcedureOutput<TRouter, TProcedure>, input?: MaybeRefOrGetter<inferProcedureInput<TProcedure>>) => ReturnType<QueryClient['setQueryData']>;
25
- key: (input?: MaybeRefOrGetter<inferProcedureInput<TProcedure>>) => QueryKey;
26
- } : TProcedure extends AnyTRPCMutationProcedure ? {
27
- mutate: Resolver<TRouter, TProcedure>;
28
+ useQueries: <TQueryFnData extends {
29
+ output: inferTransformedProcedureOutput<TRouter, TProcedure>;
30
+ input: inferProcedureInput<TProcedure>;
31
+ }, TError extends TRPCClientErrorLike<TRouter>, TData extends TQueryFnData, TQueryData extends TQueryFnData, TQueryKey extends QueryKey, TInput extends inferProcedureInput<TProcedure>, TQueries extends UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, TCombinedResult = UseQueriesResults<TQueries[]>>(inputs: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>[]>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<TQueries>, 'queryKey'> & {
32
+ trpc?: TRPCRequestOptions;
33
+ queryKey?: never;
34
+ combine?: (result: UseQueriesResults<TQueries[]>) => TCombinedResult;
35
+ shallow?: boolean;
36
+ }>) => Readonly<Ref<TCombinedResult>>;
37
+ query: <TInput extends inferProcedureInput<TProcedure>>(input: Exact<inferProcedureInput<TProcedure>, TInput>, opts?: ProcedureOptions) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>;
38
+ invalidate: <TInput extends inferProcedureInput<TProcedure>>(input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>) => Promise<void>;
39
+ setQueryData: <TInput extends inferProcedureInput<TProcedure>>(updater: inferTransformedProcedureOutput<TRouter, TProcedure>, input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>) => ReturnType<QueryClient['setQueryData']>;
40
+ key: <TInput extends inferProcedureInput<TProcedure>>(input?: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>) => QueryKey;
41
+ } & (TProcedure['_def']['$types']['input'] extends {
42
+ cursor?: infer CursorType;
43
+ } ? {
44
+ useInfiniteQuery: <TQueryFnData extends inferTransformedProcedureOutput<TRouter, TProcedure>, TError extends TRPCClientErrorLike<TRouter>, TData extends InfiniteData<TQueryFnData>, TQueryData extends TQueryFnData, TQueryKey extends QueryKey, TInput extends inferProcedureInput<TProcedure>>(input: MaybeRefOrGetter<Exact<Omit<inferProcedureInput<TProcedure>, 'cursor'>, TInput>>, opts?: MaybeRefOrGetter<Omit<UnwrapRef<UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, 'queryKey' | keyof InitialPageParam> & {
45
+ trpc?: TRPCRequestOptions;
46
+ queryKey?: TQueryKey;
47
+ } & (undefined extends TProcedure['_def']['$types']['input']['cursor'] ? Partial<InitialPageParam<CursorType>> : InitialPageParam<CursorType>)>) => UseInfiniteQueryReturnType<TData, TError>;
48
+ } : object) : TProcedure extends AnyTRPCMutationProcedure ? {
49
+ mutate: <TInput extends inferProcedureInput<TProcedure>>(input: Exact<inferProcedureInput<TProcedure>, TInput>, opts?: ProcedureOptions) => Promise<inferTransformedProcedureOutput<TRouter, TProcedure>>;
28
50
  useMutation: <TData = inferTransformedProcedureOutput<TRouter, TProcedure>, TError = TRPCClientErrorLike<TRouter>, TVariables = inferProcedureInput<TProcedure>, TContext = unknown>(opts?: MaybeRefOrGetter<UseMutationOptions<TData, TError, TVariables, TContext> & {
29
51
  trpc?: TRPCRequestOptions;
30
52
  }>) => UseMutationReturnType<TData, TError, TVariables, TContext>;
31
53
  } : TProcedure extends AnyTRPCSubscriptionProcedure ? {
32
- subscribe: SubscriptionResolver<TProcedure, TRouter>;
33
- } : 'test';
54
+ subscribe: <TInput extends inferProcedureInput<TProcedure>>(input: Exact<inferProcedureInput<TProcedure>, TInput>, opts: ProcedureOptions & Partial<TRPCSubscriptionObserver<inferProcedureOutput<TProcedure>, TRPCClientErrorLike<TRouter>>>) => Unsubscribable;
55
+ useSubscription: <TInput extends inferProcedureInput<TProcedure>>(input: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>>, opts: ProcedureOptions & Partial<TRPCSubscriptionObserver<inferProcedureOutput<TProcedure>, TRPCClientErrorLike<TRouter>>>) => Unsubscribable;
56
+ } : never;
34
57
  /**
35
58
  * @internal
36
59
  */
@@ -38,9 +61,15 @@ type DecoratedProcedureRecord<TProcedures extends Record<string, any>, TRouter e
38
61
  [K in keyof TProcedures]: TProcedures[K] extends AnyTRPCProcedure ? DecorateProcedure<TProcedures[K], TRouter> : DecoratedProcedureRecord<TProcedures[K], TRouter>;
39
62
  };
40
63
 
41
- declare function createTRPCVueQueryClient<TRouter extends AnyTRPCRouter>(opts: {
64
+ type QueryType = 'query' | 'infinite';
65
+ type TRPCQueryKey = [readonly string[], {
66
+ input?: unknown;
67
+ type?: QueryType;
68
+ }?];
69
+
70
+ declare function createTRPCVueQueryClient<TRouter extends AnyTRPCRouter>({ trpc, queryClient, }: {
42
71
  queryClient: QueryClient;
43
72
  trpc: CreateTRPCClientOptions<TRouter>;
44
73
  }): DecoratedProcedureRecord<TRouter["_def"]["record"], TRouter>;
45
74
 
46
- export { createTRPCVueQueryClient };
75
+ export { type Exact, type TRPCQueryKey, createTRPCVueQueryClient };
package/dist/index.mjs CHANGED
@@ -1,66 +1,151 @@
1
1
  // src/index.ts
2
- import { useMutation, useQuery } from "@tanstack/vue-query";
3
2
  import {
4
- createTRPCClient
3
+ queryOptions as defineQueryOptions,
4
+ skipToken,
5
+ useInfiniteQuery,
6
+ useMutation,
7
+ useQueries,
8
+ useQuery
9
+ } from "@tanstack/vue-query";
10
+ import {
11
+ createTRPCUntypedClient
5
12
  } from "@trpc/client";
6
13
  import { createTRPCFlatProxy } from "@trpc/server";
7
14
  import { createRecursiveProxy } from "@trpc/server/unstable-core-do-not-import";
8
15
  import { toRef, toRefs, toValue } from "@vueuse/core";
9
- import { computed, isReactive } from "vue";
10
- function getQueryKey(path, input) {
11
- return input === void 0 ? path : [...path, input];
16
+ import { computed, isReactive, onScopeDispose, shallowRef, watch } from "vue";
17
+ function getQueryKey(path, input, type) {
18
+ const splitPath = path.flatMap((part) => part.split("."));
19
+ if (input === void 0 && !type) {
20
+ return splitPath.length > 0 ? [splitPath] : [];
21
+ }
22
+ return [
23
+ splitPath,
24
+ {
25
+ ...input !== void 0 && input !== skipToken && { input },
26
+ ...type && { type }
27
+ }
28
+ ];
12
29
  }
13
30
  function maybeToRefs(obj) {
14
31
  return isReactive(obj) ? toRefs(obj) : toRefs(toRef(obj));
15
32
  }
16
- function createVueQueryProxyDecoration(name, client, queryClient) {
17
- return createRecursiveProxy((opts) => {
18
- const args = opts.args;
19
- const path = [name, ...opts.path];
20
- const lastProperty = path.pop();
33
+ function createVueQueryProxyDecoration(name, trpc, queryClient) {
34
+ return createRecursiveProxy(({ args, path: _path }) => {
35
+ const path = [name, ..._path];
36
+ const prop = path.pop();
21
37
  const joinedPath = path.join(".");
22
- const [firstParam, secondParam] = args;
23
- if (lastProperty === "_def") {
38
+ const [firstArg, ...rest] = args;
39
+ const opts = rest[0] || {};
40
+ if (prop === "_def") {
24
41
  return { path };
25
42
  }
26
- if (lastProperty === "useQuery") {
27
- const { trpc, ...queryOptions } = secondParam || {};
28
- return useQuery({
29
- queryKey: computed(() => getQueryKey(path, toValue(firstParam))),
30
- queryFn: ({ queryKey, signal }) => client[joinedPath].query(queryKey.at(-1), {
31
- signal,
32
- ...trpc
43
+ if (prop === "query") {
44
+ return trpc.query(joinedPath, firstArg, opts);
45
+ }
46
+ function createQuery(_input, { trpcOptions, queryOptions }) {
47
+ const input = toValue(_input);
48
+ return defineQueryOptions({
49
+ queryKey: computed(() => getQueryKey(path, input, "query")),
50
+ queryFn: async ({ signal }) => ({
51
+ output: await trpc.query(joinedPath, input, {
52
+ signal,
53
+ ...trpcOptions
54
+ }),
55
+ input
33
56
  }),
34
57
  ...maybeToRefs(queryOptions)
35
58
  });
36
59
  }
37
- if (lastProperty === "invalidate") {
60
+ if (prop === "useQuery") {
61
+ const { trpc: trpcOptions, ...queryOptions } = opts;
62
+ const input = firstArg;
63
+ return useQuery(createQuery(input, { trpcOptions, queryOptions }));
64
+ }
65
+ if (prop === "useQueries") {
66
+ const { trpc: trpcOptions, combine, shallow, ...queryOptions } = opts;
67
+ const inputs = firstArg;
68
+ return useQueries({
69
+ queries: computed(
70
+ () => toValue(inputs).map((i) => createQuery(i, { trpcOptions, queryOptions }))
71
+ ),
72
+ combine,
73
+ ...maybeToRefs({ shallow })
74
+ });
75
+ }
76
+ if (prop === "invalidate") {
38
77
  return queryClient.invalidateQueries({
39
- queryKey: getQueryKey(path, toValue(firstParam))
78
+ queryKey: getQueryKey(path, toValue(firstArg), "query")
40
79
  });
41
80
  }
42
- if (lastProperty === "setQueryData") {
43
- return queryClient.setQueryData(getQueryKey(path, toValue(secondParam)), firstParam);
81
+ if (prop === "setQueryData") {
82
+ return queryClient.setQueryData(getQueryKey(path, toValue(opts), "query"), firstArg);
44
83
  }
45
- if (lastProperty === "key") {
46
- return getQueryKey(path, toValue(firstParam));
84
+ if (prop === "key") {
85
+ return getQueryKey(path, toValue(firstArg), "query");
47
86
  }
48
- if (lastProperty === "useMutation") {
49
- const { trpc, ...mutationOptions } = firstParam || {};
87
+ if (prop === "mutate") {
88
+ return trpc.mutation(joinedPath, firstArg, opts);
89
+ }
90
+ if (prop === "useMutation") {
91
+ const { trpc: trpcOptions, ...mutationOptions } = firstArg || {};
50
92
  return useMutation({
51
- mutationFn: (payload) => client[joinedPath].mutate(payload, {
52
- ...trpc
93
+ mutationKey: computed(() => getQueryKey(path, void 0)),
94
+ mutationFn: async (payload) => trpc.mutation(joinedPath, payload, {
95
+ ...trpcOptions
53
96
  }),
54
97
  ...maybeToRefs(mutationOptions)
55
98
  });
56
99
  }
57
- return client[joinedPath][lastProperty](...args);
100
+ if (prop === "subscribe") {
101
+ return trpc.subscription(joinedPath, firstArg, opts);
102
+ }
103
+ if (prop === "useSubscription") {
104
+ const inputData = toRef(firstArg);
105
+ const subscription = shallowRef();
106
+ watch(
107
+ inputData,
108
+ () => {
109
+ subscription.value?.unsubscribe();
110
+ subscription.value = trpc.subscription(joinedPath, inputData.value, {
111
+ ...opts
112
+ });
113
+ },
114
+ { immediate: true }
115
+ );
116
+ onScopeDispose(() => {
117
+ subscription.value?.unsubscribe();
118
+ }, true);
119
+ return subscription.value;
120
+ }
121
+ if (prop === "useInfiniteQuery") {
122
+ const { trpc: trpcOptions, ...queryOptions } = opts;
123
+ return useInfiniteQuery({
124
+ queryKey: computed(() => getQueryKey(path, toValue(firstArg), "infinite")),
125
+ queryFn: async ({ queryKey, pageParam, signal }) => trpc.query(
126
+ joinedPath,
127
+ {
128
+ ...queryKey[1]?.input,
129
+ cursor: pageParam
130
+ },
131
+ {
132
+ signal,
133
+ ...trpcOptions
134
+ }
135
+ ),
136
+ ...maybeToRefs(queryOptions)
137
+ });
138
+ }
139
+ throw new Error(`Method '.${prop}()' not supported`);
58
140
  });
59
141
  }
60
- function createTRPCVueQueryClient(opts) {
61
- const client = createTRPCClient(opts.trpc);
142
+ function createTRPCVueQueryClient({
143
+ trpc,
144
+ queryClient
145
+ }) {
146
+ const client = createTRPCUntypedClient(trpc);
62
147
  const decoratedClient = createTRPCFlatProxy((key) => {
63
- return createVueQueryProxyDecoration(key, client, opts.queryClient);
148
+ return createVueQueryProxyDecoration(key, client, queryClient);
64
149
  });
65
150
  return decoratedClient;
66
151
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@falcondev-oss/trpc-vue-query",
3
3
  "type": "module",
4
- "version": "0.5.0-rc.0",
4
+ "version": "0.5.0-rc.10",
5
5
  "description": "A tRPC wrapper around '@tanstack/vue-query'",
6
6
  "license": "MIT",
7
7
  "repository": "github:falcondev-oss/trpc-vue-query",
@@ -21,40 +21,46 @@
21
21
  "files": [
22
22
  "dist"
23
23
  ],
24
+ "engines": {
25
+ "node": "20",
26
+ "pnpm": "9"
27
+ },
24
28
  "peerDependencies": {
25
29
  "@tanstack/vue-query": "^5.22.2",
26
- "@trpc/client": "^10.45.1",
27
- "@trpc/server": "^10.45.1",
30
+ "@trpc/client": "next",
31
+ "@trpc/server": "next",
28
32
  "vue": "^3.4.19"
29
33
  },
30
34
  "dependencies": {
31
- "@vueuse/core": "^11.0.3"
35
+ "@vueuse/core": "^11.1.0"
32
36
  },
33
37
  "devDependencies": {
34
- "@commitlint/cli": "^19.4.1",
38
+ "@commitlint/cli": "^19.5.0",
35
39
  "@eslint/eslintrc": "^3.1.0",
36
40
  "@louishaftmann/commitlint-config": "^4.0.3",
37
41
  "@louishaftmann/eslint-config": "^4.0.3",
38
42
  "@louishaftmann/lintstaged-config": "^4.0.3",
39
43
  "@louishaftmann/prettier-config": "^4.0.3",
40
- "@tanstack/vue-query": "^5.53.1",
41
- "@trpc/client": "11.0.0-rc.490",
42
- "@trpc/server": "11.0.0-rc.490",
44
+ "@tanstack/vue-query": "^5.59.6",
45
+ "@trpc/client": "11.0.0-rc.566",
46
+ "@trpc/server": "11.0.0-rc.566",
43
47
  "@types/eslint": "^9.6.1",
44
48
  "@types/eslint__eslintrc": "^2.1.2",
45
- "@vitest/ui": "^2.0.5",
46
- "eslint": "^9.9.1",
47
- "happy-dom": "^15.7.2",
48
- "husky": "^9.1.5",
49
- "lint-staged": "^15.2.9",
49
+ "@types/ws": "^8.5.12",
50
+ "@vitest/ui": "^2.1.2",
51
+ "eslint": "^9.12.0",
52
+ "husky": "^9.1.6",
53
+ "lint-staged": "^15.2.10",
50
54
  "prettier": "^3.3.3",
51
- "start-server-and-test": "^2.0.5",
52
- "tsup": "^8.2.4",
53
- "tsx": "^4.19.0",
54
- "typescript": "^5.5.4",
55
- "vitest": "^2.0.5",
56
- "vue": "^3.4.38",
57
- "vue-demi": "^0.14.10"
55
+ "start-server-and-test": "^2.0.8",
56
+ "tsup": "^8.3.0",
57
+ "tsx": "^4.19.1",
58
+ "type-fest": "^4.26.1",
59
+ "typescript": "^5.6.3",
60
+ "vitest": "^2.1.2",
61
+ "vue": "^3.5.11",
62
+ "ws": "^8.18.0",
63
+ "zod": "^3.23.8"
58
64
  },
59
65
  "changelogithub": {
60
66
  "extends": "gh:falcondev-it/configs/changelogithub"