npm package: @pressflow/sdk
Description: TypeScript SDK for the Pressflow public API
Latest version: 0.1.0

# @pressflow/sdk

TypeScript SDK for the [Pressflow](https://pressflow.io) public API. Fetch articles, categories, and tags from your Pressflow blog with full type safety.

## Installation

```bash
npm install @pressflow/sdk
```

## Quick Start

```typescript
import { PressflowClient } from "@pressflow/sdk"

const client = new PressflowClient({ baseUrl: "https://api.pressflow.io", apiKey: "pk_..." })
const { articles } = await client.listArticles({ limit: 10 })
const article = await client.getArticle("my-first-post")
```

## API Reference

### `new PressflowClient(config)`

Creates a new Pressflow client instance.

| Parameter | Type     | Required | Default | Description                          |
| --------- | -------- | -------- | ------- | ------------------------------------ |
| `baseUrl` | `string` | Yes      | -       | Pressflow API base URL               |
| `apiKey`  | `string` | Yes      | -       | Your public API key (starts with `pk_`) |
| `timeout` | `number` | No       | `10000` | Request timeout in milliseconds      |

### `listArticles(params?)`

Returns a paginated list of articles.

```typescript
const response = await client.listArticles({ limit: 20, status: "published" })
console.log(response.articles)
console.log(response.pagination.next_cursor) // pass to next call for pagination
```

**Parameters:**

| Parameter     | Type                                         | Default | Description                   |
| ------------- | -------------------------------------------- | ------- | ----------------------------- |
| `cursor`      | `string`                                     | -       | Pagination cursor             |
| `limit`       | `number`                                     | `20`    | Results per page (1-100)      |
| `status`      | `"draft" \| "published" \| "archived"`       | -       | Filter by article status      |
| `category_id` | `string`                                     | -       | Filter by category ID         |
| `sort`        | `"created_at" \| "published_at" \| "title"` | -       | Sort field                    |
| `order`       | `"asc" \| "desc"`                            | -       | Sort direction                |

**Returns:** `ArticleListResponse`

### `getArticle(slug)`

Returns a single article by its URL slug.

```typescript
const article = await client.getArticle("getting-started-with-pressflow")
```

| Parameter | Type     | Required | Description        |
| --------- | -------- | -------- | ------------------ |
| `slug`    | `string` | Yes      | The article's slug |

**Returns:** `Article`

### `listCategories()`

Returns all categories for the blog.

```typescript
const categories = await client.listCategories()
```

**Returns:** `Category[]`

### `listTags()`

Returns all tags for the blog.

```typescript
const tags = await client.listTags()
```

**Returns:** `Tag[]`

## Types

### `Article`

```typescript
interface Article {
  id: string
  title: string
  slug: string
  content: string
  content_plain: string
  excerpt: string | null
  featured_image_url: string | null
  status: "draft" | "published" | "archived"
  meta_title: string | null
  meta_description: string | null
  og_image_url: string | null
  canonical_url: string | null
  category_id: string | null
  tags: Tag[]
  author: ArticleAuthor
  published_at: string | null
  created_at: string
  updated_at: string
}
```

### `ArticleAuthor`

```typescript
interface ArticleAuthor {
  id: string
  name: string
  avatar_url: string | null
}
```

### `Category`

```typescript
interface Category {
  id: string
  name: string
  slug: string
  description: string | null
  parent_id: string | null
  created_at: string
  updated_at: string
}
```

### `Tag`

```typescript
interface Tag {
  id: string
  name: string
  slug: string
  created_at: string
  updated_at: string
}
```

### `ArticleListResponse`

```typescript
interface ArticleListResponse {
  articles: Article[]
  pagination: {
    next_cursor: string | null
    limit: number
  }
}
```

### `PressflowError`

```typescript
class PressflowError extends Error {
  code: string    // e.g. "NOT_FOUND", "UNAUTHORIZED"
  message: string
  status: number  // HTTP status code (0 for timeouts)
}
```

## Error Handling

All API methods throw `PressflowError` on failure.

```typescript
import { PressflowClient, PressflowError } from "@pressflow/sdk"

try {
  const article = await client.getArticle("nonexistent")
} catch (err) {
  if (err instanceof PressflowError) {
    console.error(err.code)    // "NOT_FOUND"
    console.error(err.message) // "Article not found"
    console.error(err.status)  // 404
  }
}
```

**Common error codes:**

| Code           | Status | Description                    |
| -------------- | ------ | ------------------------------ |
| `UNAUTHORIZED` | 401    | Invalid or missing API key     |
| `NOT_FOUND`    | 404    | Resource does not exist        |
| `RATE_LIMITED`  | 429    | Too many requests              |
| `TIMEOUT`      | 0      | Request exceeded timeout limit |

## License

MIT