import { QueryKey, UseMutationResult } from '@tanstack/react-query';
import { ApiError, RequestConfig, QueryParams } from '../types';
/**
* Mutation variables structure
*/
export interface MutationVariables
{
/** Request body */
body?: TBody;
/** Path parameters */
pathParams?: Record;
/** Query parameters */
queryParams?: QueryParams;
}
/**
* API mutation configuration
*/
export interface ApiMutationConfig {
/** HTTP method */
method: 'POST' | 'PUT' | 'PATCH' | 'DELETE';
/** Request URL (can include :param placeholders) */
url: string;
/** Additional request options */
requestOptions?: Partial;
/** Query keys to invalidate on success */
invalidateQueries?: QueryKey[];
/** Query keys to refetch on success */
refetchQueries?: QueryKey[];
/** Query key for optimistic updates */
optimisticQueryKey?: QueryKey;
/** Optimistic update function */
optimisticUpdate?: (oldData: unknown, variables: MutationVariables) => unknown;
/** On mutate callback (for custom optimistic updates) */
onMutate?: (variables: MutationVariables) => Promise | TContext;
/** On success callback */
onSuccess?: (data: TResponse, variables: MutationVariables, context: TContext | undefined) => void | Promise;
/** On error callback */
onError?: (error: ApiError, variables: MutationVariables, context: TContext | undefined) => void | Promise;
/** On settled callback */
onSettled?: (data: TResponse | undefined, error: ApiError | null, variables: MutationVariables, context: TContext | undefined) => void | Promise;
/** Retry configuration */
retry?: number | boolean;
/** Retry delay */
retryDelay?: number;
}
/**
* Return type for useApiMutation
*/
export interface UseApiMutationResult extends Omit>, never> {
/** Execute mutation with just body */
mutateWithBody: (body: TBody) => void;
/** Execute mutation async with just body */
mutateAsyncWithBody: (body: TBody) => Promise;
}
/**
* Hook for making typed API mutations
*
* @typeParam TResponse - Expected response data type
* @typeParam TBody - Request body type
* @typeParam TContext - Mutation context type (for optimistic updates)
* @param config - Mutation configuration
* @returns Mutation result with utilities
*
* @example
* ```typescript
* // Create mutation
* const createUser = useApiMutation({
* method: 'POST',
* url: '/users',
* invalidateQueries: [['users', 'list']],
* });
*
* // Execute
* createUser.mutate({ body: { name: 'John', email: 'john@example.com' } });
*
* // Or with simplified API
* createUser.mutateWithBody({ name: 'John', email: 'john@example.com' });
*
* // Update mutation with path params
* const updateUser = useApiMutation({
* method: 'PATCH',
* url: '/users/:id',
* invalidateQueries: [['users', 'list']],
* });
*
* updateUser.mutate({
* pathParams: { id: '123' },
* body: { name: 'Updated Name' },
* });
*
* // Delete mutation
* const deleteUser = useApiMutation({
* method: 'DELETE',
* url: '/users/:id',
* invalidateQueries: [['users', 'list']],
* });
*
* deleteUser.mutate({ pathParams: { id: '123' } });
* ```
*/
export declare function useApiMutation(config: ApiMutationConfig): UseApiMutationResult;
/**
* Hook for POST mutations
*
* @example
* ```typescript
* const createUser = usePost('/users', {
* invalidateQueries: [['users', 'list']],
* });
*
* createUser.mutateWithBody({ name: 'John' });
* ```
*/
export declare function usePost(url: string, options?: Omit, 'method' | 'url'>): UseApiMutationResult;
/**
* Hook for PUT mutations
*
* @example
* ```typescript
* const updateUser = usePut('/users/:id', {
* invalidateQueries: [['users', 'list']],
* });
*
* updateUser.mutate({
* pathParams: { id: '123' },
* body: { name: 'Updated' },
* });
* ```
*/
export declare function usePut(url: string, options?: Omit, 'method' | 'url'>): UseApiMutationResult;
/**
* Hook for PATCH mutations
*
* @example
* ```typescript
* const patchUser = usePatch>('/users/:id');
*
* patchUser.mutate({
* pathParams: { id: '123' },
* body: { status: 'active' },
* });
* ```
*/
export declare function usePatch(url: string, options?: Omit, 'method' | 'url'>): UseApiMutationResult;
/**
* Hook for DELETE mutations
*
* @example
* ```typescript
* const deleteUser = useDelete('/users/:id', {
* invalidateQueries: [['users', 'list']],
* });
*
* deleteUser.mutate({ pathParams: { id: '123' } });
* ```
*/
export declare function useDelete(url: string, options?: Omit, 'method' | 'url'>): UseApiMutationResult;
/**
* Create optimistic update configuration for adding item to list
*
* @example
* ```typescript
* const createUser = usePost('/users', {
* ...createOptimisticAdd(['users', 'list'], (body) => ({
* ...body,
* id: 'temp-id',
* createdAt: new Date().toISOString(),
* })),
* });
* ```
*/
export declare function createOptimisticAdd(queryKey: QueryKey, createTempItem: (body: unknown) => TItem): Pick, 'optimisticQueryKey' | 'optimisticUpdate'>;
/**
* Create optimistic update configuration for updating item in list
*
* @example
* ```typescript
* const updateUser = usePatch>('/users/:id', {
* ...createOptimisticUpdate(['users', 'list'], (item) => item.id),
* });
* ```
*/
export declare function createOptimisticUpdate>(queryKey: QueryKey, getItemId: (item: TItem) => string | number): Pick, {
previousData: TItem[] | undefined;
}>, 'optimisticQueryKey' | 'optimisticUpdate'>;
/**
* Create optimistic update configuration for removing item from list
*
* @example
* ```typescript
* const deleteUser = useDelete('/users/:id', {
* ...createOptimisticRemove(['users', 'list'], (item) => item.id),
* });
* ```
*/
export declare function createOptimisticRemove(queryKey: QueryKey, getItemId: (item: TItem) => string | number): Pick, 'optimisticQueryKey' | 'optimisticUpdate'>;
/**
* Hook for executing multiple mutations in sequence
*
* @example
* ```typescript
* const batchUpdate = useBatchMutation(
* '/users/:id',
* 'PATCH'
* );
*
* await batchUpdate.mutateAsync([
* { pathParams: { id: '1' }, body: { status: 'active' } },
* { pathParams: { id: '2' }, body: { status: 'active' } },
* ]);
* ```
*/
export declare function useBatchMutation(url: string, method: 'POST' | 'PUT' | 'PATCH' | 'DELETE', options?: Omit, 'method' | 'url'>): {
mutate: (variables: MutationVariables[]) => void;
mutateAsync: (variables: MutationVariables[]) => Promise;
isPending: boolean;
isError: boolean;
error: ApiError | null;
data: TResponse[] | undefined;
reset: () => void;
};