npm package: @flightdev/data
Description: Data fetching primitives for Flight Framework - loaders, actions, forms, useFetch, and useAsyncData
Author: Flight Framework
Latest version: 0.0.7

# @flightdev/data

Data fetching primitives for Flight Framework.

## Installation

```bash
npm install @flightdev/data
```

## Loaders

Loaders run on the server before rendering a page. They fetch data that the page needs.

```tsx
// src/routes/posts/[slug].page.tsx
import { useLoaderData } from '@flightdev/data';

export async function loader({ params }: LoaderContext) {
    const post = await db.posts.findUnique({
        where: { slug: params.slug }
    });
    
    if (!post) {
        throw new Response('Not Found', { status: 404 });
    }
    
    return { post };
}

export default function PostPage() {
    const { post } = useLoaderData<typeof loader>();
    
    return (
        <article>
            <h1>{post.title}</h1>
            <div>{post.content}</div>
        </article>
    );
}
```

## Actions

Actions handle form submissions and mutations. They run on the server when a form is submitted.

```tsx
import { redirect, Form } from '@flightdev/data';

export async function action({ request }: ActionContext) {
    const formData = await request.formData();
    
    await db.posts.create({
        data: {
            title: formData.get('title') as string,
            content: formData.get('content') as string,
        }
    });
    
    return redirect('/posts');
}

export default function NewPostPage() {
    return (
        <Form method="post">
            <input name="title" placeholder="Title" required />
            <textarea name="content" placeholder="Content" />
            <button type="submit">Create Post</button>
        </Form>
    );
}
```

## useFetcher

For data fetching without navigation:

```tsx
import { useFetcher } from '@flightdev/data';

function SearchBox() {
    const fetcher = useFetcher<SearchResult[]>();
    
    return (
        <div>
            <input
                type="search"
                onChange={(e) => fetcher.load(`/api/search?q=${e.target.value}`)}
            />
            
            {fetcher.state === 'loading' && <Spinner />}
            
            {fetcher.data?.map(result => (
                <SearchResultItem key={result.id} result={result} />
            ))}
        </div>
    );
}
```

## Response Utilities

```ts
import { redirect, json, notFound, badRequest } from '@flightdev/data';

// Redirect
return redirect('/dashboard');

// JSON response
return json({ success: true });

// 404 Not Found
return notFound();

// 400 Bad Request
return badRequest({ error: 'Invalid input' });
```

## Type Safety

The `SerializeFrom` utility type extracts the return type of a loader:

```tsx
import type { SerializeFrom } from '@flightdev/data';

export async function loader() {
    return { posts: await getPosts() };
}

// Type is: { posts: Post[] }
type LoaderData = SerializeFrom<typeof loader>;
```

## SSR Integration

Loader data is automatically hydrated from SSR to client:

```tsx
// entry-server.tsx
import { hydrateLoaderData } from '@flightdev/data';

const html = `
    <html>
        <body>
            <div id="root">${content}</div>
            ${hydrateLoaderData(url, loaderData)}
        </body>
    </html>
`;
```

---

## Client-Side Data Fetching

For client-side data fetching with caching and deduplication, Flight provides `useFetch` and `useAsyncData`.

### useFetch

Simple, cached data fetching:

```tsx
// React
import { useFetch } from '@flightdev/data/react';

function Users() {
    const { data, pending, error, refresh } = useFetch<User[]>('/api/users');
    
    if (pending) return <p>Loading...</p>;
    if (error) return <p>Error: {error.message}</p>;
    
    return (
        <div>
            <button onClick={refresh}>Refresh</button>
            <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>
        </div>
    );
}
```

### Framework Adapters

Import from the adapter for your framework:

```typescript
// React
import { useFetch, useAsyncData } from '@flightdev/data/react';

// Vue
import { useFetch, useAsyncData } from '@flightdev/data/vue';

// Svelte
import { useFetch, useAsyncData } from '@flightdev/data/svelte';

// Solid
import { useFetch, useAsyncData } from '@flightdev/data/solid';
```

### useAsyncData

For custom fetching logic:

```tsx
import { useAsyncData } from '@flightdev/data/react';

function Analytics() {
    const { data, pending, execute } = useAsyncData(
        'analytics-weekly',
        async () => await analyticsAPI.getWeeklyReport()
    );
    
    return (
        <div>
            <button onClick={execute}>Refresh</button>
            {pending ? <Spinner /> : <Chart data={data} />}
        </div>
    );
}
```

### Options

```typescript
useFetch('/api/data', {
    key: 'custom-key',      // Cache key (default: url)
    immediate: true,        // Fetch on mount (default: true)
    default: [],            // Default value while loading
    cache: true,            // Enable caching (default: true)
    dedupe: true,           // Deduplicate requests (default: true)
    maxAge: 60000,          // Cache TTL in ms
    revalidateOnFocus: true // Re-fetch on window focus
});
```

### Cache Utilities

```typescript
import { invalidate, prefetch, clearCache } from '@flightdev/data';

// Invalidate specific key
invalidate('/api/users');

// Invalidate by pattern
invalidate(key => key.startsWith('/api/'));

// Prefetch data
await prefetch('/api/users');

// Clear all cache
clearCache();
```

### Features

| Feature | Description |
|---------|-------------|
| LRU Cache | O(1) operations, memory-bounded |
| Deduplication | Multiple calls share one request |
| Stale-While-Revalidate | Instant stale data, background refresh |
| SSR Hydration | Seamless server-to-client transfer |
| Framework Agnostic | React, Vue, Svelte, Solid |

## License

MIT