@veloxts/client 0.4.1 → 0.4.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.
- package/README.md +22 -236
- package/dist/react/__tests__/hooks.test.d.ts +5 -0
- package/dist/react/__tests__/hooks.test.d.ts.map +1 -0
- package/dist/react/__tests__/hooks.test.js +230 -0
- package/dist/react/__tests__/hooks.test.js.map +1 -0
- package/dist/react/__tests__/provider.test.d.ts +5 -0
- package/dist/react/__tests__/provider.test.d.ts.map +1 -0
- package/dist/react/__tests__/provider.test.js +77 -0
- package/dist/react/__tests__/provider.test.js.map +1 -0
- package/dist/react/hooks.d.ts +182 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +224 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/index.d.ts +63 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +67 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/provider.d.ts +108 -0
- package/dist/react/provider.d.ts.map +1 -0
- package/dist/react/provider.js +162 -0
- package/dist/react/provider.js.map +1 -0
- package/dist/react/types.d.ts +83 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/react/types.js +10 -0
- package/dist/react/types.js.map +1 -0
- package/dist/react/utils.d.ts +151 -0
- package/dist/react/utils.d.ts.map +1 -0
- package/dist/react/utils.js +181 -0
- package/dist/react/utils.js.map +1 -0
- package/dist/test-setup.d.ts +7 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +7 -0
- package/dist/test-setup.js.map +1 -0
- package/package.json +27 -3
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React hooks for VeloxTS API calls
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe hooks for queries and mutations
|
|
5
|
+
* with full integration with React Query.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/hooks
|
|
8
|
+
*/
|
|
9
|
+
import { type QueryClient, type UseMutationResult, type UseQueryResult } from '@tanstack/react-query';
|
|
10
|
+
import type { InferProcedureInput, InferProcedureOutput } from '../types.js';
|
|
11
|
+
import type { GetProcedure, GetProceduresFromCollection, VeloxUseMutationOptions, VeloxUseQueryOptions } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Type-safe query hook for VeloxTS procedures
|
|
14
|
+
*
|
|
15
|
+
* Wraps React Query's useQuery with automatic type inference from
|
|
16
|
+
* your backend procedure definitions. The hook automatically:
|
|
17
|
+
* - Builds a stable query key from namespace, procedure, and input
|
|
18
|
+
* - Provides full type safety for input and output
|
|
19
|
+
* - Integrates with React Query's caching and refetching
|
|
20
|
+
*
|
|
21
|
+
* @template TRouter - The router type (typeof imported procedures)
|
|
22
|
+
* @template TNamespace - The namespace key (e.g., 'users', 'posts')
|
|
23
|
+
* @template TProcedureName - The procedure name (e.g., 'getUser', 'listUsers')
|
|
24
|
+
*
|
|
25
|
+
* @param namespace - Resource namespace (e.g., 'users')
|
|
26
|
+
* @param procedureName - Procedure name (e.g., 'getUser')
|
|
27
|
+
* @param input - Input matching the procedure's input schema
|
|
28
|
+
* @param options - React Query options (optional)
|
|
29
|
+
*
|
|
30
|
+
* @returns UseQueryResult with typed data and error
|
|
31
|
+
*
|
|
32
|
+
* @example Basic usage
|
|
33
|
+
* ```tsx
|
|
34
|
+
* function UserProfile({ userId }: { userId: string }) {
|
|
35
|
+
* const { data: user, isLoading, error } = useQuery(
|
|
36
|
+
* 'users',
|
|
37
|
+
* 'getUser',
|
|
38
|
+
* { id: userId }
|
|
39
|
+
* );
|
|
40
|
+
*
|
|
41
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
42
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
43
|
+
* if (!user) return <div>User not found</div>;
|
|
44
|
+
*
|
|
45
|
+
* return <div>{user.name}</div>;
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example With options
|
|
50
|
+
* ```tsx
|
|
51
|
+
* const { data } = useQuery(
|
|
52
|
+
* 'users',
|
|
53
|
+
* 'listUsers',
|
|
54
|
+
* { page: 1, limit: 10 },
|
|
55
|
+
* {
|
|
56
|
+
* staleTime: 60_000,
|
|
57
|
+
* refetchOnWindowFocus: true,
|
|
58
|
+
* }
|
|
59
|
+
* );
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Conditional query
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const { data } = useQuery(
|
|
65
|
+
* 'users',
|
|
66
|
+
* 'getUser',
|
|
67
|
+
* { id: userId },
|
|
68
|
+
* { enabled: !!userId }
|
|
69
|
+
* );
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function useQuery<TRouter, TNamespace extends keyof TRouter, TProcedureName extends keyof GetProceduresFromCollection<TRouter[TNamespace]>>(namespace: TNamespace, procedureName: TProcedureName, input: InferProcedureInput<GetProcedure<TRouter, TNamespace, TProcedureName>>, options?: VeloxUseQueryOptions<InferProcedureOutput<GetProcedure<TRouter, TNamespace, TProcedureName>>>): UseQueryResult<InferProcedureOutput<GetProcedure<TRouter, TNamespace, TProcedureName>>, Error>;
|
|
73
|
+
/**
|
|
74
|
+
* Type-safe mutation hook for VeloxTS procedures
|
|
75
|
+
*
|
|
76
|
+
* Wraps React Query's useMutation with automatic type inference from
|
|
77
|
+
* your backend procedure definitions. The hook provides:
|
|
78
|
+
* - Full type safety for input and output
|
|
79
|
+
* - Access to mutation lifecycle callbacks (onSuccess, onError, etc.)
|
|
80
|
+
* - Optimistic update support via context
|
|
81
|
+
*
|
|
82
|
+
* @template TRouter - The router type
|
|
83
|
+
* @template TNamespace - The namespace key
|
|
84
|
+
* @template TProcedureName - The procedure name (should be a mutation)
|
|
85
|
+
*
|
|
86
|
+
* @param namespace - Resource namespace (e.g., 'users')
|
|
87
|
+
* @param procedureName - Procedure name (e.g., 'createUser')
|
|
88
|
+
* @param options - React Query mutation options (optional)
|
|
89
|
+
*
|
|
90
|
+
* @returns UseMutationResult with typed variables, data, and error
|
|
91
|
+
*
|
|
92
|
+
* @example Basic usage
|
|
93
|
+
* ```tsx
|
|
94
|
+
* function CreateUserForm() {
|
|
95
|
+
* const { mutate: createUser, isPending, error } = useMutation(
|
|
96
|
+
* 'users',
|
|
97
|
+
* 'createUser'
|
|
98
|
+
* );
|
|
99
|
+
*
|
|
100
|
+
* const handleSubmit = (e: FormEvent) => {
|
|
101
|
+
* e.preventDefault();
|
|
102
|
+
* createUser({ name: 'Alice', email: 'alice@example.com' });
|
|
103
|
+
* };
|
|
104
|
+
*
|
|
105
|
+
* return (
|
|
106
|
+
* <form onSubmit={handleSubmit}>
|
|
107
|
+
* <button type="submit" disabled={isPending}>
|
|
108
|
+
* {isPending ? 'Creating...' : 'Create User'}
|
|
109
|
+
* </button>
|
|
110
|
+
* {error && <div>{error.message}</div>}
|
|
111
|
+
* </form>
|
|
112
|
+
* );
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @example With cache invalidation
|
|
117
|
+
* ```tsx
|
|
118
|
+
* const queryClient = useQueryClient();
|
|
119
|
+
*
|
|
120
|
+
* const { mutate } = useMutation('users', 'createUser', {
|
|
121
|
+
* onSuccess: () => {
|
|
122
|
+
* queryClient.invalidateQueries({ queryKey: ['users', 'listUsers'] });
|
|
123
|
+
* },
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @example With optimistic update
|
|
128
|
+
* ```tsx
|
|
129
|
+
* const { mutate } = useMutation('users', 'updateUser', {
|
|
130
|
+
* onMutate: async (newUser) => {
|
|
131
|
+
* await queryClient.cancelQueries({ queryKey: ['users', 'getUser', { id: newUser.id }] });
|
|
132
|
+
* const previousUser = queryClient.getQueryData(['users', 'getUser', { id: newUser.id }]);
|
|
133
|
+
* queryClient.setQueryData(['users', 'getUser', { id: newUser.id }], newUser);
|
|
134
|
+
* return { previousUser };
|
|
135
|
+
* },
|
|
136
|
+
* onError: (err, newUser, context) => {
|
|
137
|
+
* if (context?.previousUser) {
|
|
138
|
+
* queryClient.setQueryData(['users', 'getUser', { id: newUser.id }], context.previousUser);
|
|
139
|
+
* }
|
|
140
|
+
* },
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function useMutation<TRouter, TNamespace extends keyof TRouter, TProcedureName extends keyof GetProceduresFromCollection<TRouter[TNamespace]>, TContext = unknown>(namespace: TNamespace, procedureName: TProcedureName, options?: VeloxUseMutationOptions<InferProcedureOutput<GetProcedure<TRouter, TNamespace, TProcedureName>>, InferProcedureInput<GetProcedure<TRouter, TNamespace, TProcedureName>>, Error, TContext>): UseMutationResult<InferProcedureOutput<GetProcedure<TRouter, TNamespace, TProcedureName>>, Error, InferProcedureInput<GetProcedure<TRouter, TNamespace, TProcedureName>>, TContext>;
|
|
145
|
+
/**
|
|
146
|
+
* Hook to access React Query's QueryClient for manual cache operations
|
|
147
|
+
*
|
|
148
|
+
* This is a direct re-export of React Query's useQueryClient for convenience.
|
|
149
|
+
* Use this for manual cache invalidation, prefetching, or optimistic updates.
|
|
150
|
+
*
|
|
151
|
+
* @returns The QueryClient instance
|
|
152
|
+
*
|
|
153
|
+
* @example Cache invalidation
|
|
154
|
+
* ```tsx
|
|
155
|
+
* function MyComponent() {
|
|
156
|
+
* const queryClient = useQueryClient();
|
|
157
|
+
* const { mutate } = useMutation('users', 'createUser', {
|
|
158
|
+
* onSuccess: () => {
|
|
159
|
+
* // Invalidate and refetch users list
|
|
160
|
+
* queryClient.invalidateQueries({ queryKey: ['users', 'listUsers'] });
|
|
161
|
+
* },
|
|
162
|
+
* });
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* @example Prefetching
|
|
167
|
+
* ```tsx
|
|
168
|
+
* function UserListItem({ userId }: { userId: string }) {
|
|
169
|
+
* const queryClient = useQueryClient();
|
|
170
|
+
*
|
|
171
|
+
* const handleMouseEnter = () => {
|
|
172
|
+
* // Prefetch user data on hover
|
|
173
|
+
* queryClient.prefetchQuery({
|
|
174
|
+
* queryKey: ['users', 'getUser', { id: userId }],
|
|
175
|
+
* queryFn: () => api.users.getUser({ id: userId }),
|
|
176
|
+
* });
|
|
177
|
+
* };
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare function useQueryClient(): QueryClient;
|
|
182
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/react/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAIpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,KAAK,EACV,YAAY,EACZ,2BAA2B,EAC3B,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EACP,UAAU,SAAS,MAAM,OAAO,EAChC,cAAc,SAAS,MAAM,2BAA2B,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAE7E,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,EAC7B,KAAK,EAAE,mBAAmB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,EAC7E,OAAO,CAAC,EAAE,oBAAoB,CAC5B,oBAAoB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,CACxE,GACA,cAAc,CAAC,oBAAoB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CA2BhG;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,wBAAgB,WAAW,CACzB,OAAO,EACP,UAAU,SAAS,MAAM,OAAO,EAChC,cAAc,SAAS,MAAM,2BAA2B,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAC7E,QAAQ,GAAG,OAAO,EAElB,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,EAC7B,OAAO,CAAC,EAAE,uBAAuB,CAC/B,oBAAoB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,EACvE,mBAAmB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,EACtE,KAAK,EACL,QAAQ,CACT,GACA,iBAAiB,CAClB,oBAAoB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,EACvE,KAAK,EACL,mBAAmB,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,EACtE,QAAQ,CACT,CAwBA;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAE5C"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React hooks for VeloxTS API calls
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe hooks for queries and mutations
|
|
5
|
+
* with full integration with React Query.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/hooks
|
|
8
|
+
*/
|
|
9
|
+
import { useMutation as useReactMutation, useQuery as useReactQuery, useQueryClient as useReactQueryClient, } from '@tanstack/react-query';
|
|
10
|
+
import { useVeloxContext } from './provider.js';
|
|
11
|
+
import { buildQueryKey } from './utils.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// useQuery Hook
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Type-safe query hook for VeloxTS procedures
|
|
17
|
+
*
|
|
18
|
+
* Wraps React Query's useQuery with automatic type inference from
|
|
19
|
+
* your backend procedure definitions. The hook automatically:
|
|
20
|
+
* - Builds a stable query key from namespace, procedure, and input
|
|
21
|
+
* - Provides full type safety for input and output
|
|
22
|
+
* - Integrates with React Query's caching and refetching
|
|
23
|
+
*
|
|
24
|
+
* @template TRouter - The router type (typeof imported procedures)
|
|
25
|
+
* @template TNamespace - The namespace key (e.g., 'users', 'posts')
|
|
26
|
+
* @template TProcedureName - The procedure name (e.g., 'getUser', 'listUsers')
|
|
27
|
+
*
|
|
28
|
+
* @param namespace - Resource namespace (e.g., 'users')
|
|
29
|
+
* @param procedureName - Procedure name (e.g., 'getUser')
|
|
30
|
+
* @param input - Input matching the procedure's input schema
|
|
31
|
+
* @param options - React Query options (optional)
|
|
32
|
+
*
|
|
33
|
+
* @returns UseQueryResult with typed data and error
|
|
34
|
+
*
|
|
35
|
+
* @example Basic usage
|
|
36
|
+
* ```tsx
|
|
37
|
+
* function UserProfile({ userId }: { userId: string }) {
|
|
38
|
+
* const { data: user, isLoading, error } = useQuery(
|
|
39
|
+
* 'users',
|
|
40
|
+
* 'getUser',
|
|
41
|
+
* { id: userId }
|
|
42
|
+
* );
|
|
43
|
+
*
|
|
44
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
45
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
46
|
+
* if (!user) return <div>User not found</div>;
|
|
47
|
+
*
|
|
48
|
+
* return <div>{user.name}</div>;
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @example With options
|
|
53
|
+
* ```tsx
|
|
54
|
+
* const { data } = useQuery(
|
|
55
|
+
* 'users',
|
|
56
|
+
* 'listUsers',
|
|
57
|
+
* { page: 1, limit: 10 },
|
|
58
|
+
* {
|
|
59
|
+
* staleTime: 60_000,
|
|
60
|
+
* refetchOnWindowFocus: true,
|
|
61
|
+
* }
|
|
62
|
+
* );
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example Conditional query
|
|
66
|
+
* ```tsx
|
|
67
|
+
* const { data } = useQuery(
|
|
68
|
+
* 'users',
|
|
69
|
+
* 'getUser',
|
|
70
|
+
* { id: userId },
|
|
71
|
+
* { enabled: !!userId }
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function useQuery(namespace, procedureName, input, options) {
|
|
76
|
+
const { client } = useVeloxContext();
|
|
77
|
+
// Build stable query key
|
|
78
|
+
const queryKey = buildQueryKey(namespace, procedureName, input);
|
|
79
|
+
return useReactQuery({
|
|
80
|
+
queryKey,
|
|
81
|
+
queryFn: async () => {
|
|
82
|
+
// Access the namespace client
|
|
83
|
+
// Use unknown intermediate cast for type safety with generic constraints
|
|
84
|
+
const namespaceClient = client[namespace];
|
|
85
|
+
// Get the procedure function
|
|
86
|
+
const procedure = namespaceClient[procedureName];
|
|
87
|
+
// Call the procedure with input
|
|
88
|
+
return procedure(input);
|
|
89
|
+
},
|
|
90
|
+
...options,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// useMutation Hook
|
|
95
|
+
// ============================================================================
|
|
96
|
+
/**
|
|
97
|
+
* Type-safe mutation hook for VeloxTS procedures
|
|
98
|
+
*
|
|
99
|
+
* Wraps React Query's useMutation with automatic type inference from
|
|
100
|
+
* your backend procedure definitions. The hook provides:
|
|
101
|
+
* - Full type safety for input and output
|
|
102
|
+
* - Access to mutation lifecycle callbacks (onSuccess, onError, etc.)
|
|
103
|
+
* - Optimistic update support via context
|
|
104
|
+
*
|
|
105
|
+
* @template TRouter - The router type
|
|
106
|
+
* @template TNamespace - The namespace key
|
|
107
|
+
* @template TProcedureName - The procedure name (should be a mutation)
|
|
108
|
+
*
|
|
109
|
+
* @param namespace - Resource namespace (e.g., 'users')
|
|
110
|
+
* @param procedureName - Procedure name (e.g., 'createUser')
|
|
111
|
+
* @param options - React Query mutation options (optional)
|
|
112
|
+
*
|
|
113
|
+
* @returns UseMutationResult with typed variables, data, and error
|
|
114
|
+
*
|
|
115
|
+
* @example Basic usage
|
|
116
|
+
* ```tsx
|
|
117
|
+
* function CreateUserForm() {
|
|
118
|
+
* const { mutate: createUser, isPending, error } = useMutation(
|
|
119
|
+
* 'users',
|
|
120
|
+
* 'createUser'
|
|
121
|
+
* );
|
|
122
|
+
*
|
|
123
|
+
* const handleSubmit = (e: FormEvent) => {
|
|
124
|
+
* e.preventDefault();
|
|
125
|
+
* createUser({ name: 'Alice', email: 'alice@example.com' });
|
|
126
|
+
* };
|
|
127
|
+
*
|
|
128
|
+
* return (
|
|
129
|
+
* <form onSubmit={handleSubmit}>
|
|
130
|
+
* <button type="submit" disabled={isPending}>
|
|
131
|
+
* {isPending ? 'Creating...' : 'Create User'}
|
|
132
|
+
* </button>
|
|
133
|
+
* {error && <div>{error.message}</div>}
|
|
134
|
+
* </form>
|
|
135
|
+
* );
|
|
136
|
+
* }
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @example With cache invalidation
|
|
140
|
+
* ```tsx
|
|
141
|
+
* const queryClient = useQueryClient();
|
|
142
|
+
*
|
|
143
|
+
* const { mutate } = useMutation('users', 'createUser', {
|
|
144
|
+
* onSuccess: () => {
|
|
145
|
+
* queryClient.invalidateQueries({ queryKey: ['users', 'listUsers'] });
|
|
146
|
+
* },
|
|
147
|
+
* });
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @example With optimistic update
|
|
151
|
+
* ```tsx
|
|
152
|
+
* const { mutate } = useMutation('users', 'updateUser', {
|
|
153
|
+
* onMutate: async (newUser) => {
|
|
154
|
+
* await queryClient.cancelQueries({ queryKey: ['users', 'getUser', { id: newUser.id }] });
|
|
155
|
+
* const previousUser = queryClient.getQueryData(['users', 'getUser', { id: newUser.id }]);
|
|
156
|
+
* queryClient.setQueryData(['users', 'getUser', { id: newUser.id }], newUser);
|
|
157
|
+
* return { previousUser };
|
|
158
|
+
* },
|
|
159
|
+
* onError: (err, newUser, context) => {
|
|
160
|
+
* if (context?.previousUser) {
|
|
161
|
+
* queryClient.setQueryData(['users', 'getUser', { id: newUser.id }], context.previousUser);
|
|
162
|
+
* }
|
|
163
|
+
* },
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export function useMutation(namespace, procedureName, options) {
|
|
168
|
+
const { client } = useVeloxContext();
|
|
169
|
+
return useReactMutation({
|
|
170
|
+
mutationFn: async (input) => {
|
|
171
|
+
// Access the namespace client
|
|
172
|
+
// Use unknown intermediate cast for type safety with generic constraints
|
|
173
|
+
const namespaceClient = client[namespace];
|
|
174
|
+
// Get the procedure function
|
|
175
|
+
const procedure = namespaceClient[procedureName];
|
|
176
|
+
// Call the procedure with input
|
|
177
|
+
return procedure(input);
|
|
178
|
+
},
|
|
179
|
+
...options,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// useQueryClient Hook
|
|
184
|
+
// ============================================================================
|
|
185
|
+
/**
|
|
186
|
+
* Hook to access React Query's QueryClient for manual cache operations
|
|
187
|
+
*
|
|
188
|
+
* This is a direct re-export of React Query's useQueryClient for convenience.
|
|
189
|
+
* Use this for manual cache invalidation, prefetching, or optimistic updates.
|
|
190
|
+
*
|
|
191
|
+
* @returns The QueryClient instance
|
|
192
|
+
*
|
|
193
|
+
* @example Cache invalidation
|
|
194
|
+
* ```tsx
|
|
195
|
+
* function MyComponent() {
|
|
196
|
+
* const queryClient = useQueryClient();
|
|
197
|
+
* const { mutate } = useMutation('users', 'createUser', {
|
|
198
|
+
* onSuccess: () => {
|
|
199
|
+
* // Invalidate and refetch users list
|
|
200
|
+
* queryClient.invalidateQueries({ queryKey: ['users', 'listUsers'] });
|
|
201
|
+
* },
|
|
202
|
+
* });
|
|
203
|
+
* }
|
|
204
|
+
* ```
|
|
205
|
+
*
|
|
206
|
+
* @example Prefetching
|
|
207
|
+
* ```tsx
|
|
208
|
+
* function UserListItem({ userId }: { userId: string }) {
|
|
209
|
+
* const queryClient = useQueryClient();
|
|
210
|
+
*
|
|
211
|
+
* const handleMouseEnter = () => {
|
|
212
|
+
* // Prefetch user data on hover
|
|
213
|
+
* queryClient.prefetchQuery({
|
|
214
|
+
* queryKey: ['users', 'getUser', { id: userId }],
|
|
215
|
+
* queryFn: () => api.users.getUser({ id: userId }),
|
|
216
|
+
* });
|
|
217
|
+
* };
|
|
218
|
+
* }
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export function useQueryClient() {
|
|
222
|
+
return useReactQueryClient();
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/react/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAIL,WAAW,IAAI,gBAAgB,EAC/B,QAAQ,IAAI,aAAa,EACzB,cAAc,IAAI,mBAAmB,GACtC,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOhD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,MAAM,UAAU,QAAQ,CAKtB,SAAqB,EACrB,aAA6B,EAC7B,KAA6E,EAC7E,OAEC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAW,CAAC;IAK9C,yBAAyB;IACzB,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAmB,EAAE,aAAuB,EAAE,KAAK,CAAC,CAAC;IAEpF,OAAO,aAAa,CAAiB;QACnC,QAAQ;QACR,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,8BAA8B;YAC9B,yEAAyE;YACzE,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAGvC,CAAC;YAEF,6BAA6B;YAC7B,MAAM,SAAS,GAAG,eAAe,CAAC,aAAuB,CAAC,CAAC;YAE3D,gCAAgC;YAChC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,MAAM,UAAU,WAAW,CAMzB,SAAqB,EACrB,aAA6B,EAC7B,OAKC;IAOD,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAW,CAAC;IAM9C,OAAO,gBAAgB,CAAmC;QACxD,UAAU,EAAE,KAAK,EAAE,KAAa,EAAE,EAAE;YAClC,8BAA8B;YAC9B,yEAAyE;YACzE,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAGvC,CAAC;YAEF,6BAA6B;YAC7B,MAAM,SAAS,GAAG,eAAe,CAAC,aAAuB,CAAC,CAAC;YAE3D,gCAAgC;YAChC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,mBAAmB,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @veloxts/client/react - React hooks for VeloxTS
|
|
3
|
+
*
|
|
4
|
+
* Type-safe React Query integration for VeloxTS procedures.
|
|
5
|
+
* Provides hooks that automatically infer types from your backend
|
|
6
|
+
* procedure definitions without any code generation.
|
|
7
|
+
*
|
|
8
|
+
* @example Quick Start
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // 1. Define your router type (imports backend procedure types)
|
|
11
|
+
* import type { userProcedures, postProcedures } from '../server/procedures';
|
|
12
|
+
*
|
|
13
|
+
* type AppRouter = {
|
|
14
|
+
* users: typeof userProcedures;
|
|
15
|
+
* posts: typeof postProcedures;
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* // 2. Wrap your app with VeloxProvider
|
|
19
|
+
* import { VeloxProvider } from '@veloxts/client/react';
|
|
20
|
+
*
|
|
21
|
+
* function App() {
|
|
22
|
+
* return (
|
|
23
|
+
* <VeloxProvider<AppRouter> config={{ baseUrl: '/api' }}>
|
|
24
|
+
* <UserList />
|
|
25
|
+
* </VeloxProvider>
|
|
26
|
+
* );
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // 3. Use hooks in components
|
|
30
|
+
* import { useQuery, useMutation, useQueryClient } from '@veloxts/client/react';
|
|
31
|
+
*
|
|
32
|
+
* function UserList() {
|
|
33
|
+
* // Query - data is fully typed!
|
|
34
|
+
* const { data, isLoading } = useQuery('users', 'listUsers', {});
|
|
35
|
+
*
|
|
36
|
+
* // Mutation with cache invalidation
|
|
37
|
+
* const queryClient = useQueryClient();
|
|
38
|
+
* const { mutate: createUser } = useMutation('users', 'createUser', {
|
|
39
|
+
* onSuccess: () => {
|
|
40
|
+
* queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
41
|
+
* },
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <ul>
|
|
48
|
+
* {data?.data.map(user => (
|
|
49
|
+
* <li key={user.id}>{user.name}</li>
|
|
50
|
+
* ))}
|
|
51
|
+
* </ul>
|
|
52
|
+
* );
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @module @veloxts/client/react
|
|
57
|
+
*/
|
|
58
|
+
export type { VeloxContextValue, VeloxProviderProps } from './provider.js';
|
|
59
|
+
export { useVeloxContext, VeloxProvider } from './provider.js';
|
|
60
|
+
export { useMutation, useQuery, useQueryClient } from './hooks.js';
|
|
61
|
+
export { buildQueryKey, getQueryData, invalidateNamespace, invalidateProcedure, invalidateQuery, setQueryData, } from './utils.js';
|
|
62
|
+
export type { ClientConfig, ClientFromRouter, GetProcedure, GetProceduresFromCollection, InferProcedureInput, InferProcedureOutput, ProcedureCollection, VeloxQueryKey, VeloxUseMutationOptions, VeloxUseQueryOptions, } from './types.js';
|
|
63
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAMH,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM/D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMnE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,YAAY,GACb,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,2BAA2B,EAC3B,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @veloxts/client/react - React hooks for VeloxTS
|
|
3
|
+
*
|
|
4
|
+
* Type-safe React Query integration for VeloxTS procedures.
|
|
5
|
+
* Provides hooks that automatically infer types from your backend
|
|
6
|
+
* procedure definitions without any code generation.
|
|
7
|
+
*
|
|
8
|
+
* @example Quick Start
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // 1. Define your router type (imports backend procedure types)
|
|
11
|
+
* import type { userProcedures, postProcedures } from '../server/procedures';
|
|
12
|
+
*
|
|
13
|
+
* type AppRouter = {
|
|
14
|
+
* users: typeof userProcedures;
|
|
15
|
+
* posts: typeof postProcedures;
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* // 2. Wrap your app with VeloxProvider
|
|
19
|
+
* import { VeloxProvider } from '@veloxts/client/react';
|
|
20
|
+
*
|
|
21
|
+
* function App() {
|
|
22
|
+
* return (
|
|
23
|
+
* <VeloxProvider<AppRouter> config={{ baseUrl: '/api' }}>
|
|
24
|
+
* <UserList />
|
|
25
|
+
* </VeloxProvider>
|
|
26
|
+
* );
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // 3. Use hooks in components
|
|
30
|
+
* import { useQuery, useMutation, useQueryClient } from '@veloxts/client/react';
|
|
31
|
+
*
|
|
32
|
+
* function UserList() {
|
|
33
|
+
* // Query - data is fully typed!
|
|
34
|
+
* const { data, isLoading } = useQuery('users', 'listUsers', {});
|
|
35
|
+
*
|
|
36
|
+
* // Mutation with cache invalidation
|
|
37
|
+
* const queryClient = useQueryClient();
|
|
38
|
+
* const { mutate: createUser } = useMutation('users', 'createUser', {
|
|
39
|
+
* onSuccess: () => {
|
|
40
|
+
* queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
41
|
+
* },
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <ul>
|
|
48
|
+
* {data?.data.map(user => (
|
|
49
|
+
* <li key={user.id}>{user.name}</li>
|
|
50
|
+
* ))}
|
|
51
|
+
* </ul>
|
|
52
|
+
* );
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @module @veloxts/client/react
|
|
57
|
+
*/
|
|
58
|
+
export { useVeloxContext, VeloxProvider } from './provider.js';
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// Hooks
|
|
61
|
+
// ============================================================================
|
|
62
|
+
export { useMutation, useQuery, useQueryClient } from './hooks.js';
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Utilities
|
|
65
|
+
// ============================================================================
|
|
66
|
+
export { buildQueryKey, getQueryData, invalidateNamespace, invalidateProcedure, invalidateQuery, setQueryData, } from './utils.js';
|
|
67
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAOH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE/D,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEnE,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,YAAY,GACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VeloxProvider - React context provider for VeloxTS client
|
|
3
|
+
*
|
|
4
|
+
* Wraps your React application to provide access to the VeloxTS client
|
|
5
|
+
* and React Query's QueryClient.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/provider
|
|
8
|
+
*/
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
|
+
import type { VeloxContextValue, VeloxProviderProps } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Provider component that sets up VeloxTS client and React Query
|
|
13
|
+
*
|
|
14
|
+
* This provider:
|
|
15
|
+
* - Creates a memoized VeloxTS client instance from the provided config
|
|
16
|
+
* - Sets up React Query's QueryClientProvider
|
|
17
|
+
* - Makes the client available to hooks via React context
|
|
18
|
+
*
|
|
19
|
+
* @template TRouter - The router type defining your procedure collections
|
|
20
|
+
*
|
|
21
|
+
* @example Basic usage
|
|
22
|
+
* ```tsx
|
|
23
|
+
* import { VeloxProvider } from '@veloxts/client/react';
|
|
24
|
+
* import type { userProcedures, postProcedures } from './server/procedures';
|
|
25
|
+
*
|
|
26
|
+
* type AppRouter = {
|
|
27
|
+
* users: typeof userProcedures;
|
|
28
|
+
* posts: typeof postProcedures;
|
|
29
|
+
* };
|
|
30
|
+
*
|
|
31
|
+
* function App() {
|
|
32
|
+
* return (
|
|
33
|
+
* <VeloxProvider<AppRouter> config={{ baseUrl: '/api' }}>
|
|
34
|
+
* <YourApp />
|
|
35
|
+
* </VeloxProvider>
|
|
36
|
+
* );
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example With custom QueryClient
|
|
41
|
+
* ```tsx
|
|
42
|
+
* import { QueryClient } from '@tanstack/react-query';
|
|
43
|
+
*
|
|
44
|
+
* const queryClient = new QueryClient({
|
|
45
|
+
* defaultOptions: {
|
|
46
|
+
* queries: { staleTime: 60_000 },
|
|
47
|
+
* },
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* function App() {
|
|
51
|
+
* return (
|
|
52
|
+
* <VeloxProvider<AppRouter>
|
|
53
|
+
* config={{ baseUrl: '/api' }}
|
|
54
|
+
* queryClient={queryClient}
|
|
55
|
+
* >
|
|
56
|
+
* <YourApp />
|
|
57
|
+
* </VeloxProvider>
|
|
58
|
+
* );
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example With custom headers
|
|
63
|
+
* ```tsx
|
|
64
|
+
* function App() {
|
|
65
|
+
* const token = useAuthToken();
|
|
66
|
+
*
|
|
67
|
+
* const config = useMemo(() => ({
|
|
68
|
+
* baseUrl: '/api',
|
|
69
|
+
* headers: {
|
|
70
|
+
* Authorization: `Bearer ${token}`,
|
|
71
|
+
* },
|
|
72
|
+
* }), [token]);
|
|
73
|
+
*
|
|
74
|
+
* return (
|
|
75
|
+
* <VeloxProvider<AppRouter> config={config}>
|
|
76
|
+
* <YourApp />
|
|
77
|
+
* </VeloxProvider>
|
|
78
|
+
* );
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function VeloxProvider<TRouter>({ children, config, queryClient: providedQueryClient, }: VeloxProviderProps<TRouter>): ReactNode;
|
|
83
|
+
/**
|
|
84
|
+
* Hook to access VeloxTS client from context
|
|
85
|
+
*
|
|
86
|
+
* This is primarily used internally by useQuery and useMutation hooks,
|
|
87
|
+
* but can also be used directly for advanced use cases.
|
|
88
|
+
*
|
|
89
|
+
* @template TRouter - The router type for type-safe client access
|
|
90
|
+
* @returns The context value containing the typed client
|
|
91
|
+
* @throws Error if used outside of VeloxProvider
|
|
92
|
+
*
|
|
93
|
+
* @example Direct client access (advanced)
|
|
94
|
+
* ```tsx
|
|
95
|
+
* function MyComponent() {
|
|
96
|
+
* const { client } = useVeloxContext<AppRouter>();
|
|
97
|
+
*
|
|
98
|
+
* // Direct client access for edge cases
|
|
99
|
+
* const handleClick = async () => {
|
|
100
|
+
* const user = await client.users.getUser({ id: '123' });
|
|
101
|
+
* console.log(user);
|
|
102
|
+
* };
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare function useVeloxContext<TRouter>(): VeloxContextValue<TRouter>;
|
|
107
|
+
export type { VeloxProviderProps, VeloxContextValue };
|
|
108
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAiB,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAC;AAG3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAwCxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,EACrC,QAAQ,EACR,MAAM,EACN,WAAW,EAAE,mBAAmB,GACjC,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAAG,SAAS,CAoBzC;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,eAAe,CAAC,OAAO,KAAK,iBAAiB,CAAC,OAAO,CAAC,CAWrE;AAMD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC"}
|