@srpc.org/react-query 0.20.3

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.
@@ -0,0 +1,344 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { createContext, useContext, useMemo } from 'react';
4
+ import { createRecursiveProxy } from '@srpc/core/shared';
5
+ import { queryOptions, mutationOptions } from '@tanstack/react-query';
6
+
7
+ /**
8
+ * Transforms an SRPC client into React Query-compatible query and mutation options.
9
+ *
10
+ * This function takes an SRPC client and returns a proxy object where each procedure
11
+ * has `.queryOptions()` and `.mutationOptions()` methods that generate options for
12
+ * React Query's `useQuery` and `useMutation` hooks.
13
+ *
14
+ * The proxy automatically:
15
+ * - Generates query keys based on the procedure path and arguments
16
+ * - Wraps procedure calls in query/mutation functions
17
+ * - Preserves type safety throughout the chain
18
+ *
19
+ * @template TRouter - The SRPC router type
20
+ * @template TRoutes - The routes type (inferred automatically)
21
+ *
22
+ * @param options - Configuration object
23
+ * @param options.client - The SRPC client created with `createSRPCClient`
24
+ *
25
+ * @returns Decorated procedures with `.queryOptions()` and `.mutationOptions()` methods
26
+ *
27
+ * @example Basic usage
28
+ * ```typescript
29
+ * import { createSRPCClient } from "@srpc/core/client";
30
+ * import { createSRPCQueryOptions } from "@srpc.org/react-query";
31
+ * import { useQuery, useMutation } from "@tanstack/react-query";
32
+ * import type { AppRouter } from "./server";
33
+ *
34
+ * const client = createSRPCClient<AppRouter>({ endpoint: "/api" });
35
+ * const srpc = createSRPCQueryOptions({ client });
36
+ *
37
+ * function UserProfile({ userId }: { userId: number }) {
38
+ * // Use with useQuery
39
+ * const { data, isLoading } = useQuery(
40
+ * srpc.users.getUser.queryOptions(userId)
41
+ * );
42
+ *
43
+ * return <div>{data?.name}</div>;
44
+ * }
45
+ * ```
46
+ *
47
+ * @example With mutations
48
+ * ```typescript
49
+ * function CreateUserForm() {
50
+ * const createUser = useMutation(srpc.users.createUser.mutationOptions());
51
+ *
52
+ * const handleSubmit = (data: UserData) => {
53
+ * createUser.mutate(data);
54
+ * };
55
+ *
56
+ * return <form onSubmit={handleSubmit}>...</form>;
57
+ * }
58
+ * ```
59
+ *
60
+ * @example With query options
61
+ * ```typescript
62
+ * function UserList() {
63
+ * const { data } = useQuery({
64
+ * ...srpc.users.list.queryOptions(),
65
+ * staleTime: 5000,
66
+ * refetchInterval: 10000,
67
+ * });
68
+ *
69
+ * return <ul>{data?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
70
+ * }
71
+ * ```
72
+ *
73
+ * @example Nested routers
74
+ * ```typescript
75
+ * // Works with deeply nested routers
76
+ * const userQuery = useQuery(srpc.users.getUser.queryOptions(1));
77
+ * const adminQuery = useQuery(srpc.users.admin.getStats.queryOptions());
78
+ * const draftQuery = useQuery(srpc.posts.drafts.list.queryOptions());
79
+ * ```
80
+ */ function createSRPCQueryOptions({ client }) {
81
+ return createRecursiveProxy(({ path, args })=>{
82
+ const lastPath = path[path.length - 1];
83
+ const pathWithoutTarget = path.slice(0, -1);
84
+ const procedure = pathWithoutTarget.reduce((acc, key)=>acc[key], client);
85
+ if (typeof procedure !== "function") {
86
+ throw new Error(`Procedure at path ${pathWithoutTarget.join(".")} is not a function`);
87
+ }
88
+ if (lastPath === "queryOptions") {
89
+ return queryOptions({
90
+ queryKey: [
91
+ ...pathWithoutTarget,
92
+ args
93
+ ],
94
+ queryFn: ()=>procedure(...args)
95
+ });
96
+ }
97
+ if (lastPath === "mutationOptions") {
98
+ return mutationOptions({
99
+ mutationKey: [
100
+ ...pathWithoutTarget,
101
+ args
102
+ ],
103
+ mutationFn: (variables)=>procedure(...variables)
104
+ });
105
+ }
106
+ throw new Error(`Unknown target path at: ${path.join(".")}`);
107
+ });
108
+ }
109
+
110
+ /**
111
+ * @module
112
+ *
113
+ * React Context integration for SRPC with React Query.
114
+ *
115
+ * This module provides React Context-based access to SRPC procedures with React Query
116
+ * integration. It creates a Provider component and hooks for accessing RPC functionality
117
+ * throughout your React application.
118
+ *
119
+ * @example Complete setup
120
+ * ```typescript
121
+ * import { createSRPCClient } from "@srpc/core/client";
122
+ * import { createSRPCContext } from "@srpc/react-query/context";
123
+ * import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
124
+ * import type { AppRouter } from "./server";
125
+ *
126
+ * // Create client
127
+ * const client = createSRPCClient<AppRouter>({ endpoint: "/api" });
128
+ *
129
+ * // Create context and hooks
130
+ * export const { SRPCProvider, useSRPC, useSRPCClient } =
131
+ * createSRPCContext<AppRouter>();
132
+ *
133
+ * // Setup in app
134
+ * function App() {
135
+ * const [queryClient] = useState(() => new QueryClient());
136
+ *
137
+ * return (
138
+ * <QueryClientProvider client={queryClient}>
139
+ * <SRPCProvider client={client}>
140
+ * <YourApp />
141
+ * </SRPCProvider>
142
+ * </QueryClientProvider>
143
+ * );
144
+ * }
145
+ *
146
+ * // Use in components
147
+ * function UserProfile() {
148
+ * const srpc = useSRPC();
149
+ * const { data } = useQuery(srpc.users.getUser.queryOptions(1));
150
+ * return <div>{data?.name}</div>;
151
+ * }
152
+ * ```
153
+ */
154
+ /**
155
+ * Factory function to create SRPC React Context, Provider, and hooks.
156
+ *
157
+ * Creates a type-safe React Context system for accessing SRPC procedures throughout
158
+ * your React application. The returned hooks provide access to both React Query
159
+ * integrated procedures and the raw RPC client.
160
+ *
161
+ * @template TRouter - The SRPC router type from your server
162
+ *
163
+ * @returns Object containing:
164
+ * - `SRPCContext` - React Context (rarely needed directly)
165
+ * - `SRPCProvider` - Provider component that accepts `client` prop
166
+ * - `useSRPC()` - Hook returning decorated procedures with `.queryOptions()` and `.mutationOptions()`
167
+ * - `useSRPCClient()` - Hook returning the raw SRPC client for direct calls
168
+ *
169
+ * @example Basic setup
170
+ * ```typescript
171
+ * import { createSRPCClient } from "@srpc/core/client";
172
+ * import { createSRPCContext } from "@srpc.org/react-query";
173
+ * import type { AppRouter } from "./server";
174
+ *
175
+ * // Create client
176
+ * const rpcClient = createSRPCClient<AppRouter>({ endpoint: "/api" });
177
+ *
178
+ * // Create context utilities
179
+ * export const { SRPCProvider, useSRPC, useSRPCClient } =
180
+ * createSRPCContext<AppRouter>();
181
+ *
182
+ * // In root component
183
+ * function App() {
184
+ * return (
185
+ * <QueryClientProvider client={queryClient}>
186
+ * <SRPCProvider client={rpcClient}>
187
+ * <YourApp />
188
+ * </SRPCProvider>
189
+ * </QueryClientProvider>
190
+ * );
191
+ * }
192
+ * ```
193
+ *
194
+ * @example Using in components with queries
195
+ * ```typescript
196
+ * import { useSRPC } from "./rpc";
197
+ * import { useQuery } from "@tanstack/react-query";
198
+ *
199
+ * function UserProfile({ userId }: { userId: number }) {
200
+ * const srpc = useSRPC();
201
+ *
202
+ * const { data, isLoading, error } = useQuery(
203
+ * srpc.users.getUser.queryOptions(userId)
204
+ * );
205
+ *
206
+ * if (isLoading) return <div>Loading...</div>;
207
+ * if (error) return <div>Error: {error.message}</div>;
208
+ *
209
+ * return (
210
+ * <div>
211
+ * <h2>{data.name}</h2>
212
+ * <p>{data.email}</p>
213
+ * </div>
214
+ * );
215
+ * }
216
+ * ```
217
+ *
218
+ * @example Using in components with mutations
219
+ * ```typescript
220
+ * import { useSRPC } from "./rpc";
221
+ * import { useMutation, useQueryClient } from "@tanstack/react-query";
222
+ *
223
+ * function CreateUserForm() {
224
+ * const srpc = useSRPC();
225
+ * const queryClient = useQueryClient();
226
+ *
227
+ * const createUser = useMutation({
228
+ * ...srpc.users.createUser.mutationOptions(),
229
+ * onSuccess: () => {
230
+ * queryClient.invalidateQueries({ queryKey: ["users"] });
231
+ * },
232
+ * });
233
+ *
234
+ * return (
235
+ * <form onSubmit={(e) => {
236
+ * e.preventDefault();
237
+ * const formData = new FormData(e.currentTarget);
238
+ * createUser.mutate({
239
+ * name: formData.get("name") as string,
240
+ * email: formData.get("email") as string,
241
+ * });
242
+ * }}>
243
+ * <input name="name" required />
244
+ * <input name="email" type="email" required />
245
+ * <button disabled={createUser.isPending}>Create User</button>
246
+ * </form>
247
+ * );
248
+ * }
249
+ * ```
250
+ *
251
+ * @example Using raw client for direct calls
252
+ * ```typescript
253
+ * import { useSRPCClient } from "./rpc";
254
+ *
255
+ * function DirectCallExample() {
256
+ * const client = useSRPCClient();
257
+ *
258
+ * const handleClick = async () => {
259
+ * // Direct RPC call without React Query
260
+ * const result = await client.sayHello("World");
261
+ * console.log(result); // "Hello World!"
262
+ * };
263
+ *
264
+ * return <button onClick={handleClick}>Call RPC</button>;
265
+ * }
266
+ * ```
267
+ *
268
+ * @example Nested routers
269
+ * ```typescript
270
+ * function NestedRouterExample() {
271
+ * const srpc = useSRPC();
272
+ *
273
+ * // All nested paths are fully typed
274
+ * const userQuery = useQuery(srpc.users.getUser.queryOptions(1));
275
+ * const adminQuery = useQuery(srpc.users.admin.getStats.queryOptions());
276
+ * const postQuery = useQuery(srpc.posts.drafts.list.queryOptions());
277
+ *
278
+ * return <div>...</div>;
279
+ * }
280
+ * ```
281
+ *
282
+ * @example With Next.js App Router
283
+ * ```typescript
284
+ * // app/providers.tsx
285
+ * "use client";
286
+ *
287
+ * import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
288
+ * import { rpcClient, SRPCProvider } from "@/lib/rpc";
289
+ * import { useState } from "react";
290
+ *
291
+ * export function Providers({ children }: { children: React.ReactNode }) {
292
+ * const [queryClient] = useState(() => new QueryClient());
293
+ *
294
+ * return (
295
+ * <QueryClientProvider client={queryClient}>
296
+ * <SRPCProvider client={rpcClient}>
297
+ * {children}
298
+ * </SRPCProvider>
299
+ * </QueryClientProvider>
300
+ * );
301
+ * }
302
+ * ```
303
+ */ function createSRPCContext() {
304
+ // biome-ignore lint/style/noNonNullAssertion: <Asserting non null for context>
305
+ const SRPCContext = /*#__PURE__*/ createContext(null);
306
+ function SRPCProvider({ children, client }) {
307
+ const srpc = useMemo(()=>{
308
+ return createSRPCQueryOptions({
309
+ client: client
310
+ });
311
+ }, [
312
+ client
313
+ ]);
314
+ return /*#__PURE__*/ jsx(SRPCContext.Provider, {
315
+ value: {
316
+ client: client,
317
+ srpc
318
+ },
319
+ children: children
320
+ });
321
+ }
322
+ function useSRPC() {
323
+ const ctx = useContext(SRPCContext);
324
+ if (!ctx) {
325
+ throw new Error("useSRPC must be used within a SRPCProvider");
326
+ }
327
+ return ctx.srpc;
328
+ }
329
+ function useSRPCClient() {
330
+ const ctx = useContext(SRPCContext);
331
+ if (!ctx) {
332
+ throw new Error("useSRPCClient must be used within a SRPCProvider");
333
+ }
334
+ return ctx.client;
335
+ }
336
+ return {
337
+ SRPCContext,
338
+ SRPCProvider,
339
+ useSRPC,
340
+ useSRPCClient
341
+ };
342
+ }
343
+
344
+ export { createSRPCContext };
@@ -0,0 +1,205 @@
1
+ import { SRPC, AnySRPC } from '@srpc/core/server';
2
+ import { ClientProcedure, AnyRoutes, AnyProcedure, DecoratedProcedureRecord } from '@srpc/core/shared';
3
+ import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
4
+ export { SRPCContextFactory, SRPCContextValue, createSRPCContext } from './context.js';
5
+
6
+ /**
7
+ * @module
8
+ *
9
+ * React Query integration for SRPC - Type-safe RPC with automatic query and mutation options.
10
+ *
11
+ * This module provides the core functionality for integrating SRPC with TanStack React Query.
12
+ * It transforms SRPC client procedures into React Query-compatible options objects that can
13
+ * be used with `useQuery` and `useMutation` hooks.
14
+ *
15
+ * @example Basic usage
16
+ * ```typescript
17
+ * import { createSRPCClient } from "@srpc/core/client";
18
+ * import { createSRPCQueryOptions } from "@srpc.org/react-query";
19
+ * import { useQuery } from "@tanstack/react-query";
20
+ * import type { AppRouter } from "./server";
21
+ *
22
+ * // Create client
23
+ * const client = createSRPCClient<AppRouter>({ endpoint: "/api" });
24
+ *
25
+ * // Transform to React Query options
26
+ * const srpc = createSRPCQueryOptions({ client });
27
+ *
28
+ * // Use in components
29
+ * function MyComponent() {
30
+ * const { data } = useQuery(srpc.users.getUser.queryOptions(1));
31
+ * return <div>{data?.name}</div>;
32
+ * }
33
+ * ```
34
+ *
35
+ * @example With React Context
36
+ * ```typescript
37
+ * import { createSRPCContext } from "@srpc.org/react-query";
38
+ *
39
+ * // Create context and hooks
40
+ * const { SRPCProvider, useSRPC } = createSRPCContext<AppRouter>();
41
+ *
42
+ * // Setup provider
43
+ * function App() {
44
+ * return (
45
+ * <QueryClientProvider client={queryClient}>
46
+ * <SRPCProvider client={rpcClient}>
47
+ * <MyComponent />
48
+ * </SRPCProvider>
49
+ * </QueryClientProvider>
50
+ * );
51
+ * }
52
+ *
53
+ * // Use in components
54
+ * function MyComponent() {
55
+ * const srpc = useSRPC();
56
+ * const { data } = useQuery(srpc.users.getUser.queryOptions(1));
57
+ * }
58
+ * ```
59
+ */
60
+ /** biome-ignore-all lint/suspicious/noExplicitAny: <Allow any type cast> */
61
+
62
+ /**
63
+ * Type representing the query and mutation options factory for a single procedure.
64
+ *
65
+ * Each procedure in the SRPC router is transformed to have two methods:
66
+ * - `queryOptions(...args)` - Returns React Query options for `useQuery`
67
+ * - `mutationOptions()` - Returns React Query options for `useMutation`
68
+ *
69
+ * @template Procedure - The client procedure type
70
+ * @template TInput - Input parameters type (inferred from procedure)
71
+ * @template TOutput - Output/return type (inferred from procedure)
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * // For a procedure: getUser(id: number) => Promise<User>
76
+ * type GetUserOptions = OptionsFactory<typeof getUser>;
77
+ *
78
+ * // Has methods:
79
+ * const options: GetUserOptions = {
80
+ * queryOptions: (id: number) => UseQueryOptions<Promise<User>>,
81
+ * mutationOptions: () => UseMutationOptions<Promise<User>, Error, [number]>
82
+ * };
83
+ * ```
84
+ */
85
+ type OptionsFactory<Procedure extends ClientProcedure<any>, TInput = Parameters<Procedure>, TOutput = ReturnType<Procedure>> = {
86
+ queryOptions: (...args: Parameters<Procedure>) => UseQueryOptions<TOutput>;
87
+ mutationOptions: () => UseMutationOptions<TOutput, Error, TInput>;
88
+ };
89
+ /**
90
+ * Type that recursively transforms an SRPC router into a structure with React Query options.
91
+ *
92
+ * For each procedure in the router, adds `.queryOptions()` and `.mutationOptions()` methods.
93
+ * Handles nested routers recursively, preserving the router structure.
94
+ *
95
+ * @template TRouter - The SRPC router routes type
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * // Server router
100
+ * const appRouter = s.router({
101
+ * getUser: async (_, id: number) => ({ id, name: "John" }),
102
+ * users: s.router({
103
+ * createUser: async (_, data: UserData) => ({ id: 1, ...data })
104
+ * })
105
+ * });
106
+ *
107
+ * // Client with query options
108
+ * type QueryRouter = DecoratedQueryProcedureRecord<typeof appRouter["ipc"]>;
109
+ * // {
110
+ * // getUser: {
111
+ * // queryOptions: (id: number) => UseQueryOptions<User>,
112
+ * // mutationOptions: () => UseMutationOptions<User, Error, [number]>
113
+ * // },
114
+ * // users: {
115
+ * // createUser: {
116
+ * // queryOptions: (data: UserData) => UseQueryOptions<UserResult>,
117
+ * // mutationOptions: () => UseMutationOptions<UserResult, Error, [UserData]>
118
+ * // }
119
+ * // }
120
+ * // }
121
+ * ```
122
+ */
123
+ type DecoratedQueryProcedureRecord<TRouter extends AnyRoutes> = {
124
+ [TKey in keyof TRouter]: TRouter[TKey] extends AnyProcedure ? OptionsFactory<ClientProcedure<TRouter[TKey]>> : TRouter[TKey] extends SRPC<any> ? DecoratedQueryProcedureRecord<TRouter[TKey]["ipc"]> : never;
125
+ };
126
+ /**
127
+ * Transforms an SRPC client into React Query-compatible query and mutation options.
128
+ *
129
+ * This function takes an SRPC client and returns a proxy object where each procedure
130
+ * has `.queryOptions()` and `.mutationOptions()` methods that generate options for
131
+ * React Query's `useQuery` and `useMutation` hooks.
132
+ *
133
+ * The proxy automatically:
134
+ * - Generates query keys based on the procedure path and arguments
135
+ * - Wraps procedure calls in query/mutation functions
136
+ * - Preserves type safety throughout the chain
137
+ *
138
+ * @template TRouter - The SRPC router type
139
+ * @template TRoutes - The routes type (inferred automatically)
140
+ *
141
+ * @param options - Configuration object
142
+ * @param options.client - The SRPC client created with `createSRPCClient`
143
+ *
144
+ * @returns Decorated procedures with `.queryOptions()` and `.mutationOptions()` methods
145
+ *
146
+ * @example Basic usage
147
+ * ```typescript
148
+ * import { createSRPCClient } from "@srpc/core/client";
149
+ * import { createSRPCQueryOptions } from "@srpc.org/react-query";
150
+ * import { useQuery, useMutation } from "@tanstack/react-query";
151
+ * import type { AppRouter } from "./server";
152
+ *
153
+ * const client = createSRPCClient<AppRouter>({ endpoint: "/api" });
154
+ * const srpc = createSRPCQueryOptions({ client });
155
+ *
156
+ * function UserProfile({ userId }: { userId: number }) {
157
+ * // Use with useQuery
158
+ * const { data, isLoading } = useQuery(
159
+ * srpc.users.getUser.queryOptions(userId)
160
+ * );
161
+ *
162
+ * return <div>{data?.name}</div>;
163
+ * }
164
+ * ```
165
+ *
166
+ * @example With mutations
167
+ * ```typescript
168
+ * function CreateUserForm() {
169
+ * const createUser = useMutation(srpc.users.createUser.mutationOptions());
170
+ *
171
+ * const handleSubmit = (data: UserData) => {
172
+ * createUser.mutate(data);
173
+ * };
174
+ *
175
+ * return <form onSubmit={handleSubmit}>...</form>;
176
+ * }
177
+ * ```
178
+ *
179
+ * @example With query options
180
+ * ```typescript
181
+ * function UserList() {
182
+ * const { data } = useQuery({
183
+ * ...srpc.users.list.queryOptions(),
184
+ * staleTime: 5000,
185
+ * refetchInterval: 10000,
186
+ * });
187
+ *
188
+ * return <ul>{data?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
189
+ * }
190
+ * ```
191
+ *
192
+ * @example Nested routers
193
+ * ```typescript
194
+ * // Works with deeply nested routers
195
+ * const userQuery = useQuery(srpc.users.getUser.queryOptions(1));
196
+ * const adminQuery = useQuery(srpc.users.admin.getStats.queryOptions());
197
+ * const draftQuery = useQuery(srpc.posts.drafts.list.queryOptions());
198
+ * ```
199
+ */
200
+ declare function createSRPCQueryOptions<TRouter extends AnySRPC, TRoutes extends AnyRoutes = TRouter["ipc"]>({ client, }: {
201
+ client: DecoratedProcedureRecord<TRoutes>;
202
+ }): DecoratedQueryProcedureRecord<TRoutes>;
203
+
204
+ export { createSRPCQueryOptions };
205
+ export type { DecoratedQueryProcedureRecord, OptionsFactory };
package/dist/index.js ADDED
@@ -0,0 +1,108 @@
1
+ import { createRecursiveProxy } from '@srpc/core/shared';
2
+ import { queryOptions, mutationOptions } from '@tanstack/react-query';
3
+ export { createSRPCContext } from './context.js';
4
+
5
+ /**
6
+ * Transforms an SRPC client into React Query-compatible query and mutation options.
7
+ *
8
+ * This function takes an SRPC client and returns a proxy object where each procedure
9
+ * has `.queryOptions()` and `.mutationOptions()` methods that generate options for
10
+ * React Query's `useQuery` and `useMutation` hooks.
11
+ *
12
+ * The proxy automatically:
13
+ * - Generates query keys based on the procedure path and arguments
14
+ * - Wraps procedure calls in query/mutation functions
15
+ * - Preserves type safety throughout the chain
16
+ *
17
+ * @template TRouter - The SRPC router type
18
+ * @template TRoutes - The routes type (inferred automatically)
19
+ *
20
+ * @param options - Configuration object
21
+ * @param options.client - The SRPC client created with `createSRPCClient`
22
+ *
23
+ * @returns Decorated procedures with `.queryOptions()` and `.mutationOptions()` methods
24
+ *
25
+ * @example Basic usage
26
+ * ```typescript
27
+ * import { createSRPCClient } from "@srpc/core/client";
28
+ * import { createSRPCQueryOptions } from "@srpc.org/react-query";
29
+ * import { useQuery, useMutation } from "@tanstack/react-query";
30
+ * import type { AppRouter } from "./server";
31
+ *
32
+ * const client = createSRPCClient<AppRouter>({ endpoint: "/api" });
33
+ * const srpc = createSRPCQueryOptions({ client });
34
+ *
35
+ * function UserProfile({ userId }: { userId: number }) {
36
+ * // Use with useQuery
37
+ * const { data, isLoading } = useQuery(
38
+ * srpc.users.getUser.queryOptions(userId)
39
+ * );
40
+ *
41
+ * return <div>{data?.name}</div>;
42
+ * }
43
+ * ```
44
+ *
45
+ * @example With mutations
46
+ * ```typescript
47
+ * function CreateUserForm() {
48
+ * const createUser = useMutation(srpc.users.createUser.mutationOptions());
49
+ *
50
+ * const handleSubmit = (data: UserData) => {
51
+ * createUser.mutate(data);
52
+ * };
53
+ *
54
+ * return <form onSubmit={handleSubmit}>...</form>;
55
+ * }
56
+ * ```
57
+ *
58
+ * @example With query options
59
+ * ```typescript
60
+ * function UserList() {
61
+ * const { data } = useQuery({
62
+ * ...srpc.users.list.queryOptions(),
63
+ * staleTime: 5000,
64
+ * refetchInterval: 10000,
65
+ * });
66
+ *
67
+ * return <ul>{data?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
68
+ * }
69
+ * ```
70
+ *
71
+ * @example Nested routers
72
+ * ```typescript
73
+ * // Works with deeply nested routers
74
+ * const userQuery = useQuery(srpc.users.getUser.queryOptions(1));
75
+ * const adminQuery = useQuery(srpc.users.admin.getStats.queryOptions());
76
+ * const draftQuery = useQuery(srpc.posts.drafts.list.queryOptions());
77
+ * ```
78
+ */ function createSRPCQueryOptions({ client }) {
79
+ return createRecursiveProxy(({ path, args })=>{
80
+ const lastPath = path[path.length - 1];
81
+ const pathWithoutTarget = path.slice(0, -1);
82
+ const procedure = pathWithoutTarget.reduce((acc, key)=>acc[key], client);
83
+ if (typeof procedure !== "function") {
84
+ throw new Error(`Procedure at path ${pathWithoutTarget.join(".")} is not a function`);
85
+ }
86
+ if (lastPath === "queryOptions") {
87
+ return queryOptions({
88
+ queryKey: [
89
+ ...pathWithoutTarget,
90
+ args
91
+ ],
92
+ queryFn: ()=>procedure(...args)
93
+ });
94
+ }
95
+ if (lastPath === "mutationOptions") {
96
+ return mutationOptions({
97
+ mutationKey: [
98
+ ...pathWithoutTarget,
99
+ args
100
+ ],
101
+ mutationFn: (variables)=>procedure(...variables)
102
+ });
103
+ }
104
+ throw new Error(`Unknown target path at: ${path.join(".")}`);
105
+ });
106
+ }
107
+
108
+ export { createSRPCQueryOptions };