npm package: @flightdev/cms
Description: Unified CMS adapters for Flight Framework - use any headless CMS
Author: Flight Contributors
Latest version: 0.2.1

# @flightdev/cms

Unified CMS adapters for Flight Framework. One API for Strapi, Contentful, Sanity, and more.

## Philosophy

**Flight doesn't impose** - you choose your CMS. All adapters are optional, swap providers without changing your code.

## Features

- **Adapter pattern** - Same API for any CMS
- **Zero lock-in** - Switch CMS providers without code changes
- **React hooks** - useCMSQuery, useCMSOne, mutations
- **Vue composables** - Reactive queries with auto-refetch
- **Full CRUD** - Read, create, update, delete
- **i18n support** - Locale-aware queries
- **Preview mode** - Draft content for editors

## Installation

```bash
npm install @flightdev/cms
```

## Quick Start

```typescript
import { createCMS } from '@flightdev/cms';
import { strapi } from '@flightdev/cms/strapi';

const cms = createCMS(strapi({
    url: process.env.STRAPI_URL,
    token: process.env.STRAPI_TOKEN,
}));

// Query posts
const { data: posts, meta } = await cms.findMany('posts', {
    limit: 10,
    sort: { publishedAt: 'desc' },
    populate: ['author', 'cover'],
});

// Get single post
const post = await cms.findOne('posts', {
    where: { slug: 'hello-world' },
});
```

## Adapters

### Strapi

```typescript
import { strapi } from '@flightdev/cms/strapi';

const adapter = strapi({
    url: 'http://localhost:1337',
    token: 'your-api-token',
    preview: true, // Enable draft mode
});
```

### Contentful

```typescript
import { contentful } from '@flightdev/cms/contentful';

const adapter = contentful({
    spaceId: 'your-space-id',
    accessToken: 'your-access-token',
    environment: 'master',
    preview: true,
    previewToken: 'preview-token',
});
```

### Sanity

```typescript
import { sanity } from '@flightdev/cms/sanity';

const adapter = sanity({
    projectId: 'your-project-id',
    dataset: 'production',
    token: 'your-token', // Optional for public datasets
    useCdn: true,
});
```

## React Integration

```tsx
import { CMSProvider, useCMSQuery, useCMSOne } from '@flightdev/cms/react';

// App
function App() {
    return (
        <CMSProvider cms={cms}>
            <PostList />
        </CMSProvider>
    );
}

// Query many
function PostList() {
    const { data: posts, loading, meta, refetch } = useCMSQuery('posts', {
        limit: 10,
        populate: ['author'],
    });
    
    if (loading) return <Skeleton />;
    
    return (
        <>
            {posts.map(post => <PostCard key={post.id} post={post} />)}
            <p>Total: {meta?.total}</p>
        </>
    );
}

// Query one
function PostPage({ slug }) {
    const { data: post, loading, error } = useCMSOne('posts', {
        where: { slug },
    });
    
    if (loading) return <Skeleton />;
    if (!post) return <NotFound />;
    
    return <Post post={post} />;
}
```

## Vue Integration

```vue
<script setup>
import { provideCMS, useCMSQuery } from '@flightdev/cms/vue';

// Provide CMS in root component
provideCMS(cms);

// Query posts
const { data: posts, loading, meta } = useCMSQuery('posts', {
    limit: 10,
    sort: { publishedAt: 'desc' },
});
</script>

<template>
    <div v-if="loading">Loading...</div>
    <PostGrid v-else :posts="posts" />
</template>
```

## API Reference

### Query Options

```typescript
interface FindManyOptions {
    where?: Record<string, unknown>;   // Filter conditions
    populate?: string[];               // Relations to include
    limit?: number;                    // Max results
    offset?: number;                   // Skip results
    page?: number;                     // Page number
    pageSize?: number;                 // Items per page
    sort?: Record<string, 'asc' | 'desc'>; // Sort order
    fields?: string[];                 // Select fields
    locale?: string;                   // Content locale
    preview?: boolean;                 // Draft mode
}
```

### CMS Methods

| Method | Description |
|--------|-------------|
| `findOne(collection, options)` | Get single entity |
| `findMany(collection, options)` | Get multiple with pagination |
| `findById(collection, id, options)` | Get by ID |
| `create(collection, data)` | Create entity |
| `update(collection, id, data)` | Update entity |
| `delete(collection, id)` | Delete entity |

## License

MIT