npm package: @mycuppa/data
Description: Data fetching and state management for Cuppa framework
Author: Cuppa Platform Team
Latest version: 0.0.0

# @mycuppa/data

Data fetching and state management library for the Cuppa framework.

## Features

- **QueryClient** - Central cache manager for queries
- **useQuery** - React hook for data fetching with automatic caching
- **useMutation** - React hook for mutations (create, update, delete operations)
- **Automatic caching** - Queries are cached automatically
- **Cache invalidation** - Manually invalidate queries to refetch data
- **Retry logic** - Automatic retry with exponential backoff
- **Request deduplication** - Multiple requests for the same data are deduplicated
- **Stale-while-revalidate** - Serve cached data while fetching fresh data in the background
- **Optimistic updates** - Support for optimistic updates in mutations

## Installation

```bash
pnpm add @mycuppa/data
```

## Usage

### Setup

First, create a QueryClient and set it globally:

```typescript
import { createQueryClient, setQueryClient } from '@mycuppa/data'

const queryClient = createQueryClient()
setQueryClient(queryClient)
```

### useQuery

Fetch and cache data with the `useQuery` hook:

```typescript
import { useQuery } from '@mycuppa/data'

function UserProfile({ userId }: { userId: number }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: async () => {
      const response = await fetch(`/api/users/${userId}`)
      return response.json()
    },
    staleTime: 5000, // Cache for 5 seconds
  })

  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>

  return <div>Welcome, {data.name}!</div>
}
```

### useMutation

Perform mutations with the `useMutation` hook:

```typescript
import { useMutation } from '@mycuppa/data'

function CreateUserForm() {
  const { mutate, isLoading, error } = useMutation({
    mutationFn: async (newUser: { name: string; email: string }) => {
      const response = await fetch('/api/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newUser),
      })
      return response.json()
    },
    onSuccess: (data) => {
      console.log('User created:', data)
      // Invalidate and refetch user list
      queryClient.invalidateQueries(['users'])
    },
  })

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        mutate({ name: 'John', email: 'john@example.com' })
      }}
    >
      <button type="submit" disabled={isLoading}>
        Create User
      </button>
      {error && <div>Error: {error.message}</div>}
    </form>
  )
}
```

### Cache Invalidation

Invalidate queries to trigger refetch:

```typescript
// Invalidate specific query
queryClient.invalidateQueries(['user', 1])

// Invalidate all queries
queryClient.invalidateQueries()
```

### Optimistic Updates

Perform optimistic updates with mutations:

```typescript
const { mutate } = useMutation({
  mutationFn: updateUser,
  onMutate: async (newUser) => {
    // Cancel any outgoing refetches
    await queryClient.cancelQueries(['user', newUser.id])

    // Snapshot the previous value
    const previousUser = queryClient.getQueryData(['user', newUser.id])

    // Optimistically update to the new value
    queryClient.setQueryData(['user', newUser.id], newUser)

    // Return context with the previous value
    return { previousUser }
  },
  onError: (err, newUser, context) => {
    // Rollback on error
    queryClient.setQueryData(['user', newUser.id], context.previousUser)
  },
  onSettled: (newUser) => {
    // Refetch after error or success
    queryClient.invalidateQueries(['user', newUser.id])
  },
})
```

## API

### QueryClient

The `QueryClient` manages query cache and fetching logic.

#### Methods

- `fetchQuery(options)` - Fetch a query
- `getQueryData(queryKey)` - Get cached query data
- `setQueryData(queryKey, data)` - Set query data manually
- `invalidateQueries(queryKey?)` - Invalidate queries
- `removeQueries(queryKey?)` - Remove queries from cache
- `clear()` - Clear all cache

### useQuery

React hook for data fetching.

#### Options

- `queryKey` - Unique key for the query (string or array)
- `queryFn` - Function that fetches the data
- `staleTime` - Time in ms before cached data is considered stale (default: 0)
- `cacheTime` - Time in ms before inactive cache is garbage collected (default: 5 minutes)
- `retry` - Number of retry attempts on failure (default: 3)
- `retryDelay` - Delay in ms before first retry (default: 1000)
- `refetchOnWindowFocus` - Refetch when window regains focus (default: true)
- `refetchOnMount` - Refetch when component mounts (default: true)
- `enabled` - Enable/disable the query (default: true)
- `onSuccess` - Callback when query succeeds
- `onError` - Callback when query fails

#### Returns

- `data` - The data returned by the query
- `error` - The error if the query failed
- `isLoading` - Whether the query is loading (first fetch)
- `isFetching` - Whether the query is fetching (includes refetch)
- `isSuccess` - Whether the query succeeded
- `isError` - Whether the query failed
- `isIdle` - Whether the query is idle (not enabled)
- `status` - Current status of the query
- `refetch` - Function to manually refetch

### useMutation

React hook for mutations.

#### Options

- `mutationFn` - Function that performs the mutation
- `onMutate` - Callback before mutation starts (supports optimistic updates)
- `onSuccess` - Callback when mutation succeeds
- `onError` - Callback when mutation fails
- `onSettled` - Callback when mutation completes (success or error)
- `retry` - Number of retry attempts on failure (default: 0)
- `retryDelay` - Delay in ms before first retry (default: 1000)

#### Returns

- `data` - The data returned by the mutation
- `error` - The error if the mutation failed
- `isLoading` - Whether the mutation is loading
- `isSuccess` - Whether the mutation succeeded
- `isError` - Whether the mutation failed
- `isIdle` - Whether the mutation is idle
- `status` - Current status of the mutation
- `mutate` - Function to trigger the mutation
- `mutateAsync` - Async function to trigger the mutation
- `reset` - Function to reset the mutation state

## License

MIT