@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,162 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* VeloxProvider - React context provider for VeloxTS client
|
|
4
|
+
*
|
|
5
|
+
* Wraps your React application to provide access to the VeloxTS client
|
|
6
|
+
* and React Query's QueryClient.
|
|
7
|
+
*
|
|
8
|
+
* @module @veloxts/client/react/provider
|
|
9
|
+
*/
|
|
10
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
11
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
12
|
+
import { createClient } from '../client.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Context
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Internal context for VeloxTS client
|
|
18
|
+
*
|
|
19
|
+
* Typed as `unknown` at creation time since the router type
|
|
20
|
+
* is provided by the consumer via generic parameter.
|
|
21
|
+
*/
|
|
22
|
+
const VeloxContext = createContext(null);
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Default QueryClient
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Creates a default QueryClient with sensible defaults for VeloxTS
|
|
28
|
+
*/
|
|
29
|
+
function createDefaultQueryClient() {
|
|
30
|
+
return new QueryClient({
|
|
31
|
+
defaultOptions: {
|
|
32
|
+
queries: {
|
|
33
|
+
staleTime: 30_000, // 30 seconds
|
|
34
|
+
retry: 1,
|
|
35
|
+
refetchOnWindowFocus: false,
|
|
36
|
+
},
|
|
37
|
+
mutations: {
|
|
38
|
+
retry: 0,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Provider Component
|
|
45
|
+
// ============================================================================
|
|
46
|
+
/**
|
|
47
|
+
* Provider component that sets up VeloxTS client and React Query
|
|
48
|
+
*
|
|
49
|
+
* This provider:
|
|
50
|
+
* - Creates a memoized VeloxTS client instance from the provided config
|
|
51
|
+
* - Sets up React Query's QueryClientProvider
|
|
52
|
+
* - Makes the client available to hooks via React context
|
|
53
|
+
*
|
|
54
|
+
* @template TRouter - The router type defining your procedure collections
|
|
55
|
+
*
|
|
56
|
+
* @example Basic usage
|
|
57
|
+
* ```tsx
|
|
58
|
+
* import { VeloxProvider } from '@veloxts/client/react';
|
|
59
|
+
* import type { userProcedures, postProcedures } from './server/procedures';
|
|
60
|
+
*
|
|
61
|
+
* type AppRouter = {
|
|
62
|
+
* users: typeof userProcedures;
|
|
63
|
+
* posts: typeof postProcedures;
|
|
64
|
+
* };
|
|
65
|
+
*
|
|
66
|
+
* function App() {
|
|
67
|
+
* return (
|
|
68
|
+
* <VeloxProvider<AppRouter> config={{ baseUrl: '/api' }}>
|
|
69
|
+
* <YourApp />
|
|
70
|
+
* </VeloxProvider>
|
|
71
|
+
* );
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @example With custom QueryClient
|
|
76
|
+
* ```tsx
|
|
77
|
+
* import { QueryClient } from '@tanstack/react-query';
|
|
78
|
+
*
|
|
79
|
+
* const queryClient = new QueryClient({
|
|
80
|
+
* defaultOptions: {
|
|
81
|
+
* queries: { staleTime: 60_000 },
|
|
82
|
+
* },
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* function App() {
|
|
86
|
+
* return (
|
|
87
|
+
* <VeloxProvider<AppRouter>
|
|
88
|
+
* config={{ baseUrl: '/api' }}
|
|
89
|
+
* queryClient={queryClient}
|
|
90
|
+
* >
|
|
91
|
+
* <YourApp />
|
|
92
|
+
* </VeloxProvider>
|
|
93
|
+
* );
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example With custom headers
|
|
98
|
+
* ```tsx
|
|
99
|
+
* function App() {
|
|
100
|
+
* const token = useAuthToken();
|
|
101
|
+
*
|
|
102
|
+
* const config = useMemo(() => ({
|
|
103
|
+
* baseUrl: '/api',
|
|
104
|
+
* headers: {
|
|
105
|
+
* Authorization: `Bearer ${token}`,
|
|
106
|
+
* },
|
|
107
|
+
* }), [token]);
|
|
108
|
+
*
|
|
109
|
+
* return (
|
|
110
|
+
* <VeloxProvider<AppRouter> config={config}>
|
|
111
|
+
* <YourApp />
|
|
112
|
+
* </VeloxProvider>
|
|
113
|
+
* );
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export function VeloxProvider({ children, config, queryClient: providedQueryClient, }) {
|
|
118
|
+
// Create client instance, memoized based on config reference
|
|
119
|
+
// Users should memoize their config object if they need to prevent re-renders
|
|
120
|
+
const client = useMemo(() => createClient(config), [config]);
|
|
121
|
+
// Use provided QueryClient or create default
|
|
122
|
+
// Only create once to avoid query state loss
|
|
123
|
+
const queryClient = useMemo(() => providedQueryClient ?? createDefaultQueryClient(), [providedQueryClient]);
|
|
124
|
+
// Memoize context value to prevent unnecessary re-renders
|
|
125
|
+
const contextValue = useMemo(() => ({ client }), [client]);
|
|
126
|
+
return (_jsx(VeloxContext.Provider, { value: contextValue, children: _jsx(QueryClientProvider, { client: queryClient, children: children }) }));
|
|
127
|
+
}
|
|
128
|
+
// ============================================================================
|
|
129
|
+
// Context Hook
|
|
130
|
+
// ============================================================================
|
|
131
|
+
/**
|
|
132
|
+
* Hook to access VeloxTS client from context
|
|
133
|
+
*
|
|
134
|
+
* This is primarily used internally by useQuery and useMutation hooks,
|
|
135
|
+
* but can also be used directly for advanced use cases.
|
|
136
|
+
*
|
|
137
|
+
* @template TRouter - The router type for type-safe client access
|
|
138
|
+
* @returns The context value containing the typed client
|
|
139
|
+
* @throws Error if used outside of VeloxProvider
|
|
140
|
+
*
|
|
141
|
+
* @example Direct client access (advanced)
|
|
142
|
+
* ```tsx
|
|
143
|
+
* function MyComponent() {
|
|
144
|
+
* const { client } = useVeloxContext<AppRouter>();
|
|
145
|
+
*
|
|
146
|
+
* // Direct client access for edge cases
|
|
147
|
+
* const handleClick = async () => {
|
|
148
|
+
* const user = await client.users.getUser({ id: '123' });
|
|
149
|
+
* console.log(user);
|
|
150
|
+
* };
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export function useVeloxContext() {
|
|
155
|
+
const context = useContext(VeloxContext);
|
|
156
|
+
if (!context) {
|
|
157
|
+
throw new Error('useVeloxContext must be used within a VeloxProvider. ' +
|
|
158
|
+
'Wrap your component tree with <VeloxProvider config={{...}}>.');
|
|
159
|
+
}
|
|
160
|
+
return context;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":";AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAkB,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,YAAY,GAAG,aAAa,CAAoC,IAAI,CAAC,CAAC;AAE5E,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;GAEG;AACH,SAAS,wBAAwB;IAC/B,OAAO,IAAI,WAAW,CAAC;QACrB,cAAc,EAAE;YACd,OAAO,EAAE;gBACP,SAAS,EAAE,MAAM,EAAE,aAAa;gBAChC,KAAK,EAAE,CAAC;gBACR,oBAAoB,EAAE,KAAK;aAC5B;YACD,SAAS,EAAE;gBACT,KAAK,EAAE,CAAC;aACT;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,MAAM,UAAU,aAAa,CAAU,EACrC,QAAQ,EACR,MAAM,EACN,WAAW,EAAE,mBAAmB,GACJ;IAC5B,6DAA6D;IAC7D,8EAA8E;IAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAU,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEtE,6CAA6C;IAC7C,6CAA6C;IAC7C,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC,mBAAmB,IAAI,wBAAwB,EAAE,EACvD,CAAC,mBAAmB,CAAC,CACtB,CAAC;IAEF,0DAA0D;IAC1D,MAAM,YAAY,GAAG,OAAO,CAA6B,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvF,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,YAA0C,YACtE,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YAAG,QAAQ,GAAuB,GACpD,CACzB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAEzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,uDAAuD;YACrD,+DAA+D,CAClE,CAAC;IACJ,CAAC;IAED,OAAO,OAAqC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for React hooks integration
|
|
3
|
+
*
|
|
4
|
+
* Provides type utilities for building type-safe React Query hooks
|
|
5
|
+
* that work with VeloxTS procedure definitions.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/types
|
|
8
|
+
*/
|
|
9
|
+
import type { UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
|
|
10
|
+
import type { ClientConfig, ClientFromRouter, InferProcedureInput, InferProcedureOutput, ProcedureCollection } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Extracts a specific procedure from the router type
|
|
13
|
+
*
|
|
14
|
+
* Enables type inference for procedure input/output in hooks.
|
|
15
|
+
*
|
|
16
|
+
* @template TRouter - The router type (collection of procedure collections)
|
|
17
|
+
* @template TNamespace - The namespace key (e.g., 'users', 'posts')
|
|
18
|
+
* @template TProcedureName - The procedure name (e.g., 'getUser', 'listUsers')
|
|
19
|
+
*/
|
|
20
|
+
export type GetProcedure<TRouter, TNamespace extends keyof TRouter, TProcedureName extends keyof GetProceduresFromCollection<TRouter[TNamespace]>> = TRouter[TNamespace] extends ProcedureCollection<infer TProcedures> ? TProcedureName extends keyof TProcedures ? TProcedures[TProcedureName] : never : never;
|
|
21
|
+
/**
|
|
22
|
+
* Extracts the procedures record from a collection
|
|
23
|
+
*
|
|
24
|
+
* @template TCollection - The procedure collection type
|
|
25
|
+
*/
|
|
26
|
+
export type GetProceduresFromCollection<TCollection> = TCollection extends ProcedureCollection ? TCollection['procedures'] : never;
|
|
27
|
+
/**
|
|
28
|
+
* Options for useQuery hook
|
|
29
|
+
*
|
|
30
|
+
* Omits queryKey and queryFn since those are provided automatically
|
|
31
|
+
* based on the procedure namespace, name, and input.
|
|
32
|
+
*
|
|
33
|
+
* @template TData - The expected response data type
|
|
34
|
+
* @template TError - The error type (defaults to Error)
|
|
35
|
+
*/
|
|
36
|
+
export type VeloxUseQueryOptions<TData, TError = Error> = Omit<UseQueryOptions<TData, TError>, 'queryKey' | 'queryFn'>;
|
|
37
|
+
/**
|
|
38
|
+
* Options for useMutation hook
|
|
39
|
+
*
|
|
40
|
+
* Omits mutationFn since that's provided automatically
|
|
41
|
+
* based on the procedure namespace and name.
|
|
42
|
+
*
|
|
43
|
+
* @template TData - The expected response data type
|
|
44
|
+
* @template TInput - The mutation input type
|
|
45
|
+
* @template TError - The error type (defaults to Error)
|
|
46
|
+
* @template TContext - The mutation context type
|
|
47
|
+
*/
|
|
48
|
+
export type VeloxUseMutationOptions<TData, TInput, TError = Error, TContext = unknown> = Omit<UseMutationOptions<TData, TError, TInput, TContext>, 'mutationFn'>;
|
|
49
|
+
/**
|
|
50
|
+
* Query key structure for VeloxTS
|
|
51
|
+
*
|
|
52
|
+
* Format: [namespace, procedureName, input?]
|
|
53
|
+
*
|
|
54
|
+
* This structure enables:
|
|
55
|
+
* - Invalidating all queries for a namespace: `['users']`
|
|
56
|
+
* - Invalidating a specific procedure: `['users', 'getUser']`
|
|
57
|
+
* - Invalidating a specific query: `['users', 'getUser', { id: '123' }]`
|
|
58
|
+
*/
|
|
59
|
+
export type VeloxQueryKey = readonly [string, string] | readonly [string, string, Record<string, unknown>];
|
|
60
|
+
/**
|
|
61
|
+
* Context value provided by VeloxProvider
|
|
62
|
+
*
|
|
63
|
+
* @template TRouter - The router type for type-safe client access
|
|
64
|
+
*/
|
|
65
|
+
export interface VeloxContextValue<TRouter> {
|
|
66
|
+
/** The typed client instance */
|
|
67
|
+
readonly client: ClientFromRouter<TRouter>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Props for VeloxProvider component
|
|
71
|
+
*
|
|
72
|
+
* @template _TRouter - The router type for type-safe client configuration (used for generic inference)
|
|
73
|
+
*/
|
|
74
|
+
export interface VeloxProviderProps<_TRouter> {
|
|
75
|
+
/** React children to render within the provider */
|
|
76
|
+
readonly children: React.ReactNode;
|
|
77
|
+
/** Client configuration (baseUrl, headers, etc.) */
|
|
78
|
+
readonly config: ClientConfig;
|
|
79
|
+
/** Optional pre-configured QueryClient instance */
|
|
80
|
+
readonly queryClient?: import('@tanstack/react-query').QueryClient;
|
|
81
|
+
}
|
|
82
|
+
export type { InferProcedureInput, InferProcedureOutput, ProcedureCollection, ClientConfig, ClientFromRouter, };
|
|
83
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/react/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEjF,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAMrB;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,CACtB,OAAO,EACP,UAAU,SAAS,MAAM,OAAO,EAChC,cAAc,SAAS,MAAM,2BAA2B,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAC3E,OAAO,CAAC,UAAU,CAAC,SAAS,mBAAmB,CAAC,MAAM,WAAW,CAAC,GAClE,cAAc,SAAS,MAAM,WAAW,GACtC,WAAW,CAAC,cAAc,CAAC,GAC3B,KAAK,GACP,KAAK,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,CAAC,WAAW,IAAI,WAAW,SAAS,mBAAmB,GAC1F,WAAW,CAAC,YAAY,CAAC,GACzB,KAAK,CAAC;AAMV;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,IAAI,CAC5D,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,EAC9B,UAAU,GAAG,SAAS,CACvB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,QAAQ,GAAG,OAAO,IAAI,IAAI,CAC3F,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EACnD,YAAY,CACb,CAAC;AAMF;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GACzB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAMvD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB,CAAC,QAAQ;IAC1C,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IACnC,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,mDAAmD;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,uBAAuB,EAAE,WAAW,CAAC;CACpE;AAMD,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,GACjB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for React hooks integration
|
|
3
|
+
*
|
|
4
|
+
* Provides type utilities for building type-safe React Query hooks
|
|
5
|
+
* that work with VeloxTS procedure definitions.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/types
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/react/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for React Query integration
|
|
3
|
+
*
|
|
4
|
+
* Provides query key builders and cache invalidation helpers
|
|
5
|
+
* for consistent and predictable caching behavior.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/utils
|
|
8
|
+
*/
|
|
9
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
10
|
+
import type { VeloxQueryKey } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Builds a stable query key for React Query
|
|
13
|
+
*
|
|
14
|
+
* Query keys are structured as: [namespace, procedureName, input?]
|
|
15
|
+
* This enables efficient cache invalidation by namespace or procedure.
|
|
16
|
+
*
|
|
17
|
+
* The key structure follows React Query best practices:
|
|
18
|
+
* - Keys are arrays for hierarchical invalidation
|
|
19
|
+
* - Input is serialized for stable identity
|
|
20
|
+
*
|
|
21
|
+
* @param namespace - The procedure namespace (e.g., 'users')
|
|
22
|
+
* @param procedureName - The procedure name (e.g., 'getUser')
|
|
23
|
+
* @param input - Optional input parameters
|
|
24
|
+
* @returns A stable query key array
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Query with no input
|
|
29
|
+
* buildQueryKey('health', 'check');
|
|
30
|
+
* // => ['health', 'check']
|
|
31
|
+
*
|
|
32
|
+
* // Query with object input
|
|
33
|
+
* buildQueryKey('users', 'getUser', { id: '123' });
|
|
34
|
+
* // => ['users', 'getUser', { id: '123' }]
|
|
35
|
+
*
|
|
36
|
+
* // Query with primitive input (wrapped)
|
|
37
|
+
* buildQueryKey('users', 'getCount', 10);
|
|
38
|
+
* // => ['users', 'getCount', { value: 10 }]
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildQueryKey(namespace: string, procedureName: string, input?: unknown): VeloxQueryKey;
|
|
42
|
+
/**
|
|
43
|
+
* Invalidates all queries for a namespace
|
|
44
|
+
*
|
|
45
|
+
* This is useful after mutations that may affect multiple resources
|
|
46
|
+
* within the same namespace.
|
|
47
|
+
*
|
|
48
|
+
* @param queryClient - The React Query client instance
|
|
49
|
+
* @param namespace - The namespace to invalidate (e.g., 'users')
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const queryClient = useQueryClient();
|
|
54
|
+
*
|
|
55
|
+
* // After deleting a user, invalidate all user queries
|
|
56
|
+
* await invalidateNamespace(queryClient, 'users');
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function invalidateNamespace(queryClient: QueryClient, namespace: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Invalidates all queries for a specific procedure
|
|
62
|
+
*
|
|
63
|
+
* This is useful when you want to refetch all instances of a specific
|
|
64
|
+
* query without affecting other queries in the same namespace.
|
|
65
|
+
*
|
|
66
|
+
* @param queryClient - The React Query client instance
|
|
67
|
+
* @param namespace - The procedure namespace (e.g., 'users')
|
|
68
|
+
* @param procedureName - The procedure name (e.g., 'getUser')
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const queryClient = useQueryClient();
|
|
73
|
+
*
|
|
74
|
+
* // After updating a user, invalidate all getUser queries
|
|
75
|
+
* await invalidateProcedure(queryClient, 'users', 'getUser');
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function invalidateProcedure(queryClient: QueryClient, namespace: string, procedureName: string): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Invalidates a specific query by its exact key
|
|
81
|
+
*
|
|
82
|
+
* This is useful when you know the exact input and want to invalidate
|
|
83
|
+
* only that specific cached query.
|
|
84
|
+
*
|
|
85
|
+
* @param queryClient - The React Query client instance
|
|
86
|
+
* @param namespace - The procedure namespace (e.g., 'users')
|
|
87
|
+
* @param procedureName - The procedure name (e.g., 'getUser')
|
|
88
|
+
* @param input - The exact input used in the query
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const queryClient = useQueryClient();
|
|
93
|
+
*
|
|
94
|
+
* // After updating user 123, invalidate only that specific query
|
|
95
|
+
* await invalidateQuery(queryClient, 'users', 'getUser', { id: '123' });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function invalidateQuery(queryClient: QueryClient, namespace: string, procedureName: string, input?: unknown): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Gets cached data for a specific query
|
|
101
|
+
*
|
|
102
|
+
* Useful for optimistic updates where you need the current cached value.
|
|
103
|
+
*
|
|
104
|
+
* @param queryClient - The React Query client instance
|
|
105
|
+
* @param namespace - The procedure namespace
|
|
106
|
+
* @param procedureName - The procedure name
|
|
107
|
+
* @param input - The query input
|
|
108
|
+
* @returns The cached data or undefined if not cached
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const queryClient = useQueryClient();
|
|
113
|
+
*
|
|
114
|
+
* // Get current cached user before optimistic update
|
|
115
|
+
* const previousUser = getQueryData<User>(
|
|
116
|
+
* queryClient,
|
|
117
|
+
* 'users',
|
|
118
|
+
* 'getUser',
|
|
119
|
+
* { id: '123' }
|
|
120
|
+
* );
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare function getQueryData<TData>(queryClient: QueryClient, namespace: string, procedureName: string, input?: unknown): TData | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Sets cached data for a specific query
|
|
126
|
+
*
|
|
127
|
+
* Useful for optimistic updates where you want to update the cache
|
|
128
|
+
* immediately before the mutation completes.
|
|
129
|
+
*
|
|
130
|
+
* @param queryClient - The React Query client instance
|
|
131
|
+
* @param namespace - The procedure namespace
|
|
132
|
+
* @param procedureName - The procedure name
|
|
133
|
+
* @param input - The query input
|
|
134
|
+
* @param data - The data to cache
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const queryClient = useQueryClient();
|
|
139
|
+
*
|
|
140
|
+
* // Optimistically update user in cache
|
|
141
|
+
* setQueryData<User>(
|
|
142
|
+
* queryClient,
|
|
143
|
+
* 'users',
|
|
144
|
+
* 'getUser',
|
|
145
|
+
* { id: '123' },
|
|
146
|
+
* { ...previousUser, name: 'New Name' }
|
|
147
|
+
* );
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export declare function setQueryData<TData>(queryClient: QueryClient, namespace: string, procedureName: string, input: unknown, data: TData): void;
|
|
151
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/react/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,OAAO,GACd,aAAa,CAYf;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAGf;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAChC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,OAAO,GACd,KAAK,GAAG,SAAS,CAGnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAChC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,KAAK,GACV,IAAI,CAGN"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for React Query integration
|
|
3
|
+
*
|
|
4
|
+
* Provides query key builders and cache invalidation helpers
|
|
5
|
+
* for consistent and predictable caching behavior.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/client/react/utils
|
|
8
|
+
*/
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Query Key Builders
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Builds a stable query key for React Query
|
|
14
|
+
*
|
|
15
|
+
* Query keys are structured as: [namespace, procedureName, input?]
|
|
16
|
+
* This enables efficient cache invalidation by namespace or procedure.
|
|
17
|
+
*
|
|
18
|
+
* The key structure follows React Query best practices:
|
|
19
|
+
* - Keys are arrays for hierarchical invalidation
|
|
20
|
+
* - Input is serialized for stable identity
|
|
21
|
+
*
|
|
22
|
+
* @param namespace - The procedure namespace (e.g., 'users')
|
|
23
|
+
* @param procedureName - The procedure name (e.g., 'getUser')
|
|
24
|
+
* @param input - Optional input parameters
|
|
25
|
+
* @returns A stable query key array
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // Query with no input
|
|
30
|
+
* buildQueryKey('health', 'check');
|
|
31
|
+
* // => ['health', 'check']
|
|
32
|
+
*
|
|
33
|
+
* // Query with object input
|
|
34
|
+
* buildQueryKey('users', 'getUser', { id: '123' });
|
|
35
|
+
* // => ['users', 'getUser', { id: '123' }]
|
|
36
|
+
*
|
|
37
|
+
* // Query with primitive input (wrapped)
|
|
38
|
+
* buildQueryKey('users', 'getCount', 10);
|
|
39
|
+
* // => ['users', 'getCount', { value: 10 }]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function buildQueryKey(namespace, procedureName, input) {
|
|
43
|
+
if (input === undefined || input === null) {
|
|
44
|
+
return [namespace, procedureName];
|
|
45
|
+
}
|
|
46
|
+
// For objects, include directly in key for proper caching
|
|
47
|
+
if (typeof input === 'object') {
|
|
48
|
+
return [namespace, procedureName, input];
|
|
49
|
+
}
|
|
50
|
+
// For primitives, wrap in object to maintain consistent key structure
|
|
51
|
+
return [namespace, procedureName, { value: input }];
|
|
52
|
+
}
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Cache Invalidation Helpers
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Invalidates all queries for a namespace
|
|
58
|
+
*
|
|
59
|
+
* This is useful after mutations that may affect multiple resources
|
|
60
|
+
* within the same namespace.
|
|
61
|
+
*
|
|
62
|
+
* @param queryClient - The React Query client instance
|
|
63
|
+
* @param namespace - The namespace to invalidate (e.g., 'users')
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const queryClient = useQueryClient();
|
|
68
|
+
*
|
|
69
|
+
* // After deleting a user, invalidate all user queries
|
|
70
|
+
* await invalidateNamespace(queryClient, 'users');
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export async function invalidateNamespace(queryClient, namespace) {
|
|
74
|
+
await queryClient.invalidateQueries({ queryKey: [namespace] });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Invalidates all queries for a specific procedure
|
|
78
|
+
*
|
|
79
|
+
* This is useful when you want to refetch all instances of a specific
|
|
80
|
+
* query without affecting other queries in the same namespace.
|
|
81
|
+
*
|
|
82
|
+
* @param queryClient - The React Query client instance
|
|
83
|
+
* @param namespace - The procedure namespace (e.g., 'users')
|
|
84
|
+
* @param procedureName - The procedure name (e.g., 'getUser')
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const queryClient = useQueryClient();
|
|
89
|
+
*
|
|
90
|
+
* // After updating a user, invalidate all getUser queries
|
|
91
|
+
* await invalidateProcedure(queryClient, 'users', 'getUser');
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export async function invalidateProcedure(queryClient, namespace, procedureName) {
|
|
95
|
+
await queryClient.invalidateQueries({ queryKey: [namespace, procedureName] });
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Invalidates a specific query by its exact key
|
|
99
|
+
*
|
|
100
|
+
* This is useful when you know the exact input and want to invalidate
|
|
101
|
+
* only that specific cached query.
|
|
102
|
+
*
|
|
103
|
+
* @param queryClient - The React Query client instance
|
|
104
|
+
* @param namespace - The procedure namespace (e.g., 'users')
|
|
105
|
+
* @param procedureName - The procedure name (e.g., 'getUser')
|
|
106
|
+
* @param input - The exact input used in the query
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const queryClient = useQueryClient();
|
|
111
|
+
*
|
|
112
|
+
* // After updating user 123, invalidate only that specific query
|
|
113
|
+
* await invalidateQuery(queryClient, 'users', 'getUser', { id: '123' });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export async function invalidateQuery(queryClient, namespace, procedureName, input) {
|
|
117
|
+
const queryKey = buildQueryKey(namespace, procedureName, input);
|
|
118
|
+
await queryClient.invalidateQueries({ queryKey });
|
|
119
|
+
}
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Cache Data Accessors
|
|
122
|
+
// ============================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Gets cached data for a specific query
|
|
125
|
+
*
|
|
126
|
+
* Useful for optimistic updates where you need the current cached value.
|
|
127
|
+
*
|
|
128
|
+
* @param queryClient - The React Query client instance
|
|
129
|
+
* @param namespace - The procedure namespace
|
|
130
|
+
* @param procedureName - The procedure name
|
|
131
|
+
* @param input - The query input
|
|
132
|
+
* @returns The cached data or undefined if not cached
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* const queryClient = useQueryClient();
|
|
137
|
+
*
|
|
138
|
+
* // Get current cached user before optimistic update
|
|
139
|
+
* const previousUser = getQueryData<User>(
|
|
140
|
+
* queryClient,
|
|
141
|
+
* 'users',
|
|
142
|
+
* 'getUser',
|
|
143
|
+
* { id: '123' }
|
|
144
|
+
* );
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function getQueryData(queryClient, namespace, procedureName, input) {
|
|
148
|
+
const queryKey = buildQueryKey(namespace, procedureName, input);
|
|
149
|
+
return queryClient.getQueryData(queryKey);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Sets cached data for a specific query
|
|
153
|
+
*
|
|
154
|
+
* Useful for optimistic updates where you want to update the cache
|
|
155
|
+
* immediately before the mutation completes.
|
|
156
|
+
*
|
|
157
|
+
* @param queryClient - The React Query client instance
|
|
158
|
+
* @param namespace - The procedure namespace
|
|
159
|
+
* @param procedureName - The procedure name
|
|
160
|
+
* @param input - The query input
|
|
161
|
+
* @param data - The data to cache
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const queryClient = useQueryClient();
|
|
166
|
+
*
|
|
167
|
+
* // Optimistically update user in cache
|
|
168
|
+
* setQueryData<User>(
|
|
169
|
+
* queryClient,
|
|
170
|
+
* 'users',
|
|
171
|
+
* 'getUser',
|
|
172
|
+
* { id: '123' },
|
|
173
|
+
* { ...previousUser, name: 'New Name' }
|
|
174
|
+
* );
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
export function setQueryData(queryClient, namespace, procedureName, input, data) {
|
|
178
|
+
const queryKey = buildQueryKey(namespace, procedureName, input);
|
|
179
|
+
queryClient.setQueryData(queryKey, data);
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/react/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,aAAa,CAC3B,SAAiB,EACjB,aAAqB,EACrB,KAAe;IAEf,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,CAAC,SAAS,EAAE,aAAa,CAAU,CAAC;IAC7C,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,SAAS,EAAE,aAAa,EAAE,KAAgC,CAAU,CAAC;IAC/E,CAAC;IAED,sEAAsE;IACtE,OAAO,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAU,CAAC;AAC/D,CAAC;AAED,+EAA+E;AAC/E,6BAA6B;AAC7B,+EAA+E;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAwB,EACxB,SAAiB;IAEjB,MAAM,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAwB,EACxB,SAAiB,EACjB,aAAqB;IAErB,MAAM,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAwB,EACxB,SAAiB,EACjB,aAAqB,EACrB,KAAe;IAEf,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;IAChE,MAAM,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAwB,EACxB,SAAiB,EACjB,aAAqB,EACrB,KAAe;IAEf,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;IAChE,OAAO,WAAW,CAAC,YAAY,CAAQ,QAAQ,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAwB,EACxB,SAAiB,EACjB,aAAqB,EACrB,KAAc,EACd,IAAW;IAEX,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;IAChE,WAAW,CAAC,YAAY,CAAQ,QAAQ,EAAE,IAAI,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,kCAAkC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.js","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,kCAAkC,CAAC"}
|