qortex-react 0.3.2 → 0.3.4

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/index.d.ts CHANGED
@@ -99,4 +99,148 @@ declare function useQuerySelect<F extends Fetcher>(key: QueryKey, opts: QueryOpt
99
99
  }): QueryState<InferFetcherResult<F>>;
100
100
  declare function useQuerySelect<T = any>(key: QueryKey, opts?: QueryOptions<T>): QueryState<T>;
101
101
 
102
- export { useQuery, useQueryData, useQuerySelect };
102
+ /** Internal: Generic mutation function type for inference */
103
+ type MutationFn = (...args: any[]) => Promise<any>;
104
+ /** Internal: Infers the return data type from a mutation function */
105
+ type InferData<Fn extends MutationFn> = Awaited<ReturnType<Fn>>;
106
+ /** Internal: Infers the arguments tuple type from a mutation function */
107
+ type InferArgs<Fn extends MutationFn> = Parameters<Fn>;
108
+ /** Internal: Options type for inferred overload (without mutationFn) */
109
+ type OptionsInferred<Fn extends MutationFn, Err = Error> = {
110
+ onSuccess?: (data: InferData<Fn>, args: InferArgs<Fn>) => void;
111
+ onError?: (error: Err, args: InferArgs<Fn>) => void;
112
+ onSettled?: (data: InferData<Fn> | undefined, error: Err | undefined, args: InferArgs<Fn>) => void;
113
+ queryKey?: QueryKey;
114
+ };
115
+ /** Internal: Result type for inferred overload */
116
+ type ResultInferred<Fn extends MutationFn, Err> = {
117
+ isPending: boolean;
118
+ error: Err | undefined;
119
+ data: InferData<Fn> | undefined;
120
+ mutate: (...args: InferArgs<Fn>) => void;
121
+ mutateAsync: (...args: InferArgs<Fn>) => Promise<InferData<Fn>>;
122
+ reset: () => void;
123
+ };
124
+ /**
125
+ * Optional configuration for the useMutate hook.
126
+ * Pass as the second argument after the mutation function.
127
+ *
128
+ * @template Data - The type of data returned by the mutation
129
+ * @template Err - The type of error that can be thrown (defaults to Error)
130
+ * @template Args - The tuple type of arguments passed to the mutation (defaults to [])
131
+ *
132
+ * @example
133
+ * ```tsx
134
+ * const options: UseMutateOptions<Todo, Error, [CreateInput]> = {
135
+ * onSuccess: (data) => console.log(data.id),
136
+ * queryKey: ['todos'],
137
+ * };
138
+ * ```
139
+ */
140
+ type UseMutateOptions<Data = any, Err = Error, Args extends any[] = []> = {
141
+ /**
142
+ * Callback fired when the mutation succeeds.
143
+ * @param data - The data returned from the mutation
144
+ * @param args - The arguments that were passed to the mutation
145
+ */
146
+ onSuccess?: (data: Data, args: Args) => void;
147
+ /**
148
+ * Callback fired when the mutation fails.
149
+ * @param error - The error thrown by the mutation
150
+ * @param args - The arguments that were passed to the mutation
151
+ */
152
+ onError?: (error: Err, args: Args) => void;
153
+ /**
154
+ * Callback fired when the mutation completes (success or error).
155
+ * @param data - The data returned from the mutation (undefined if error)
156
+ * @param error - The error thrown by the mutation (undefined if success)
157
+ * @param args - The arguments that were passed to the mutation
158
+ */
159
+ onSettled?: (data: Data | undefined, error: Err | undefined, args: Args) => void;
160
+ /**
161
+ * Optional query key to invalidate after successful mutation.
162
+ * If provided, the query will be refetched after mutation completes.
163
+ */
164
+ queryKey?: QueryKey;
165
+ };
166
+ /**
167
+ * Return type for the useMutate hook.
168
+ *
169
+ * @template Data - The type of data returned by the mutation
170
+ * @template Err - The type of error that can be thrown
171
+ * @template Args - The tuple type of arguments passed to the mutation
172
+ *
173
+ * @example
174
+ * ```tsx
175
+ * const result: UseMutateResult<Todo, Error, [CreateInput]> = useMutate(createTodo);
176
+ * result.mutate({ title: 'New Todo' });
177
+ * ```
178
+ */
179
+ type UseMutateResult<Data, Err, Args extends any[]> = {
180
+ /** Whether the mutation is currently in progress */
181
+ isPending: boolean;
182
+ /** The error thrown by the last mutation attempt, or undefined */
183
+ error: Err | undefined;
184
+ /** The data returned by the last successful mutation, or undefined */
185
+ data: Data | undefined;
186
+ /** Function to trigger the mutation */
187
+ mutate: (...args: Args) => void;
188
+ /** Function to trigger the mutation and return a promise */
189
+ mutateAsync: (...args: Args) => Promise<Data>;
190
+ /** Resets the mutation state to its initial values */
191
+ reset: () => void;
192
+ };
193
+ /**
194
+ * A hook for handling asynchronous mutations with loading, error, and success states.
195
+ *
196
+ * @param mutationFn - The async function that performs the mutation (required)
197
+ * @param options - Optional configuration (callbacks, queryKey to invalidate)
198
+ *
199
+ * Supports two usage patterns:
200
+ * 1. **Inferred types**: Let TypeScript infer types from mutationFn (recommended)
201
+ * 2. **Explicit generics**: Specify Data, Error, and Args types manually
202
+ *
203
+ * @example
204
+ * ```tsx
205
+ * // Simple usage - just pass the mutation function
206
+ * const { mutate, isPending } = useMutate(api.createTodo);
207
+ * mutate({ title: 'New Todo' });
208
+ *
209
+ * // With options - callbacks and query invalidation
210
+ * const { mutate, data } = useMutate(
211
+ * async (newTodo: { title: string }) => {
212
+ * const res = await fetch('/api/todos', {
213
+ * method: 'POST',
214
+ * body: JSON.stringify(newTodo),
215
+ * });
216
+ * return res.json() as Promise<{ id: string; title: string }>;
217
+ * },
218
+ * {
219
+ * onSuccess: (data, [todo]) => console.log('Created:', data.id, todo.title),
220
+ * onError: (error) => console.error('Failed:', error),
221
+ * queryKey: ['todos'], // Invalidate todos query after mutation
222
+ * }
223
+ * );
224
+ * mutate({ title: 'New Todo' });
225
+ *
226
+ * // Multiple arguments - all types inferred
227
+ * const { mutate: updateTodo } = useMutate(
228
+ * async (id: string, title: string, completed: boolean) => {
229
+ * return await api.updateTodo(id, { title, completed });
230
+ * },
231
+ * { onSuccess: (data, [id, title]) => console.log(`Updated ${id}: ${title}`) }
232
+ * );
233
+ * updateTodo('123', 'Updated Title', true);
234
+ *
235
+ * // Explicit generics - when you need to override inferred types
236
+ * type Todo = { id: string; title: string };
237
+ * const { mutate } = useMutate<Todo, Error, [{ title: string }]>(
238
+ * async (input) => api.createTodo(input),
239
+ * { onSuccess: (data) => console.log(data.id) }
240
+ * );
241
+ * ```
242
+ */
243
+ declare function useMutate<Fn extends MutationFn, Err = Error>(mutationFn: Fn, options?: OptionsInferred<Fn, Err>): ResultInferred<Fn, Err>;
244
+ declare function useMutate<Data, Err = Error, Args extends any[] = []>(mutationFn: (...args: Args) => Promise<Data>, options?: UseMutateOptions<Data, Err, Args>): UseMutateResult<Data, Err, Args>;
245
+
246
+ export { UseMutateOptions, UseMutateResult, useMutate, useQuery, useQueryData, useQuerySelect };
package/index.js CHANGED
@@ -3,11 +3,12 @@
3
3
  var qortexCore = require('qortex-core');
4
4
  var react = require('react');
5
5
 
6
- function P(e,t){let r=qortexCore.serializeKey(e),u=react.useCallback(()=>qortexCore.queryManager.getQueryState(e,t),[r]),n=react.useCallback(o=>qortexCore.queryManager.subscribeQuery(e,o,t),[r]);return react.useSyncExternalStore(n,u)}function L(e,t){let r=qortexCore.serializeKey(e),u=react.useCallback(()=>qortexCore.queryManager.getQueryData(e,t),[r]),n=react.useCallback(o=>qortexCore.queryManager.subscribeQuery(e,o,t),[r]);return react.useSyncExternalStore(n,u)}function $(e,t){let r=qortexCore.serializeKey(e),u=react.useRef(),n=react.useRef(new Set),a=react.useCallback(y=>qortexCore.queryManager.subscribeQuery(e,s=>{let x=u.current,i=n.current;if(i.size===0){u.current=s,y();return}let Q=!1;for(let f of i)if(x?.[f]!==s[f]){Q=!0;break}Q&&(u.current=s,y());},t),[r]),o=react.useCallback(()=>qortexCore.queryManager.getQueryState(e,t),[r]),c=react.useSyncExternalStore(a,o);return react.useMemo(()=>new Proxy(c,{get(y,s){return n.current.add(s),y[s]}}),[c])}
6
+ function B(e,r){let t=qortexCore.serializeKey(e),n=react.useCallback(()=>qortexCore.queryManager.getQueryState(e,r),[t]),s=react.useCallback(o=>qortexCore.queryManager.subscribeQuery(e,o,r),[t]);return react.useSyncExternalStore(s,n)}function X(e,r){let t=qortexCore.serializeKey(e),n=react.useCallback(()=>qortexCore.queryManager.getQueryData(e,r),[t]),s=react.useCallback(o=>qortexCore.queryManager.subscribeQuery(e,o,r),[t]);return react.useSyncExternalStore(s,n)}function se(e,r){let t=qortexCore.serializeKey(e),n=react.useRef(),s=react.useRef(new Set),a=react.useCallback(y=>qortexCore.queryManager.subscribeQuery(e,u=>{let Q=n.current,f=s.current;if(f.size===0){n.current=u,y();return}let p=!1;for(let g of f)if(Q?.[g]!==u[g]){p=!0;break}p&&(n.current=u,y());},r),[t]),o=react.useCallback(()=>qortexCore.queryManager.getQueryState(e,r),[t]),i=react.useSyncExternalStore(a,o);return react.useMemo(()=>new Proxy(i,{get(y,u){return s.current.add(u),y[u]}}),[i])}function ye(e,r={}){let{onSuccess:t,onError:n,onSettled:s,queryKey:a}=r,[o,i]=react.useState(!1),[m,y]=react.useState(void 0),[u,Q]=react.useState(void 0),f=()=>{i(!1),y(void 0),Q(void 0);},p=async(...d)=>{f(),i(!0);try{let c=await e(...d);return Q(c),i(!1),t?.(c,d),s?.(c,void 0,d),a&&qortexCore.invalidateQuery(a),c}catch(c){let F=c;throw y(F),i(!1),n?.(F,d),s?.(void 0,F,d),a&&qortexCore.invalidateQuery(a),F}};return {isPending:o,error:m,data:u,mutate:(...d)=>{p(...d).catch(()=>{});},mutateAsync:p,reset:f}}
7
7
 
8
- exports.useQuery = P;
9
- exports.useQueryData = L;
10
- exports.useQuerySelect = $;
8
+ exports.useMutate = ye;
9
+ exports.useQuery = B;
10
+ exports.useQueryData = X;
11
+ exports.useQuerySelect = se;
11
12
  Object.keys(qortexCore).forEach(function (k) {
12
13
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
13
14
  enumerable: true,
package/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { serializeKey, queryManager } from 'qortex-core';
1
+ import { serializeKey, queryManager, invalidateQuery } from 'qortex-core';
2
2
  export * from 'qortex-core';
3
- import { useCallback, useSyncExternalStore, useRef, useMemo } from 'react';
3
+ import { useCallback, useSyncExternalStore, useRef, useMemo, useState } from 'react';
4
4
 
5
- function P(e,t){let r=serializeKey(e),u=useCallback(()=>queryManager.getQueryState(e,t),[r]),n=useCallback(o=>queryManager.subscribeQuery(e,o,t),[r]);return useSyncExternalStore(n,u)}function L(e,t){let r=serializeKey(e),u=useCallback(()=>queryManager.getQueryData(e,t),[r]),n=useCallback(o=>queryManager.subscribeQuery(e,o,t),[r]);return useSyncExternalStore(n,u)}function $(e,t){let r=serializeKey(e),u=useRef(),n=useRef(new Set),a=useCallback(y=>queryManager.subscribeQuery(e,s=>{let x=u.current,i=n.current;if(i.size===0){u.current=s,y();return}let Q=!1;for(let f of i)if(x?.[f]!==s[f]){Q=!0;break}Q&&(u.current=s,y());},t),[r]),o=useCallback(()=>queryManager.getQueryState(e,t),[r]),c=useSyncExternalStore(a,o);return useMemo(()=>new Proxy(c,{get(y,s){return n.current.add(s),y[s]}}),[c])}
5
+ function B(e,r){let t=serializeKey(e),n=useCallback(()=>queryManager.getQueryState(e,r),[t]),s=useCallback(o=>queryManager.subscribeQuery(e,o,r),[t]);return useSyncExternalStore(s,n)}function X(e,r){let t=serializeKey(e),n=useCallback(()=>queryManager.getQueryData(e,r),[t]),s=useCallback(o=>queryManager.subscribeQuery(e,o,r),[t]);return useSyncExternalStore(s,n)}function se(e,r){let t=serializeKey(e),n=useRef(),s=useRef(new Set),a=useCallback(y=>queryManager.subscribeQuery(e,u=>{let Q=n.current,f=s.current;if(f.size===0){n.current=u,y();return}let p=!1;for(let g of f)if(Q?.[g]!==u[g]){p=!0;break}p&&(n.current=u,y());},r),[t]),o=useCallback(()=>queryManager.getQueryState(e,r),[t]),i=useSyncExternalStore(a,o);return useMemo(()=>new Proxy(i,{get(y,u){return s.current.add(u),y[u]}}),[i])}function ye(e,r={}){let{onSuccess:t,onError:n,onSettled:s,queryKey:a}=r,[o,i]=useState(!1),[m,y]=useState(void 0),[u,Q]=useState(void 0),f=()=>{i(!1),y(void 0),Q(void 0);},p=async(...d)=>{f(),i(!0);try{let c=await e(...d);return Q(c),i(!1),t?.(c,d),s?.(c,void 0,d),a&&invalidateQuery(a),c}catch(c){let F=c;throw y(F),i(!1),n?.(F,d),s?.(void 0,F,d),a&&invalidateQuery(a),F}};return {isPending:o,error:m,data:u,mutate:(...d)=>{p(...d).catch(()=>{});},mutateAsync:p,reset:f}}
6
6
 
7
- export { P as useQuery, L as useQueryData, $ as useQuerySelect };
7
+ export { ye as useMutate, B as useQuery, X as useQueryData, se as useQuerySelect };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qortex-react",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "React hook bridge for qortex runtime",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -50,7 +50,7 @@
50
50
  "author": "Darshan Naik",
51
51
  "license": "LGPL-3.0",
52
52
  "dependencies": {
53
- "qortex-core": "0.3.2"
53
+ "qortex-core": "0.3.4"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "react": ">=18"