notra 0.1.1

Unofficial Rust SDK for the Notra API
Documentation
# notra

> **Unofficial** Rust SDK for the [Notra]https://usenotra.com API.

[![Crates.io](https://img.shields.io/crates/v/notra.svg)](https://crates.io/crates/notra)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
notra = "0.1"
tokio = { version = "1", features = ["full"] }
```

## Quick Start

```rust
use notra::Notra;
use notra::models::{ContentType, LookbackWindow, PostStatus};

#[tokio::main]
async fn main() -> Result<(), notra::NotraError> {
    let notra = Notra::builder()
        .bearer_auth("your-api-key")
        .build()?;

    // List all published posts
    let response = notra.content()
        .list_posts()
        .status(PostStatus::Published)
        .limit(10)
        .send()
        .await?;

    for post in &response.posts {
        println!("{} ({})", post.title, post.id);
    }

    Ok(())
}
```

## Usage

### Client Configuration

```rust
use std::time::Duration;
use notra::Notra;

let notra = Notra::builder()
    .bearer_auth("your-api-key")
    .server_url("https://api.usenotra.com")  // optional, this is the default
    .timeout(Duration::from_secs(60))        // optional, defaults to 30s
    .build()?;
```

### Posts

```rust
use notra::models::*;

// List posts with filters
let posts = notra.content()
    .list_posts()
    .status(PostStatus::Published)
    .content_type(ContentType::Changelog)
    .sort(Sort::Desc)
    .limit(20)
    .page(1)
    .send()
    .await?;

// Get a single post
let post = notra.content()
    .get_post("post-id")
    .send()
    .await?;

// Update a post
let updated = notra.content()
    .update_post("post-id")
    .title("Updated Title")
    .markdown("# Hello\n\nNew content here.")
    .status(PostStatus::Published)
    .slug("updated-title")
    .send()
    .await?;

// Delete a post
notra.content()
    .delete_post("post-id")
    .send()
    .await?;
```

### Post Generation

Generate posts from your connected GitHub repositories and Linear integrations:

```rust
use notra::models::*;

// Start a generation job
let job = notra.content()
    .create_post_generation(ContentType::Changelog)
    .lookback_window(LookbackWindow::Last7Days)
    .brand_identity_id("brand-id")
    .github_integration_ids(vec!["integration-1".into()])
    .repositories(vec![
        Repository { owner: "my-org".into(), repo: "my-repo".into() },
    ])
    .data_points(DataPoints {
        commits: true,
        pull_requests: true,
        releases: true,
        linear_data: false,
    })
    .send()
    .await?;

println!("Job started: {}", job.job.id);

// Poll for completion
let status = notra.content()
    .get_post_generation(&job.job.id)
    .send()
    .await?;

println!("Status: {:?}", status.job.status);
```

### Brand Identities

```rust
use notra::models::*;

// List brand identities
let identities = notra.content()
    .list_brand_identities()
    .send()
    .await?;

// Generate a brand identity from a website
let job = notra.content()
    .create_brand_identity("https://example.com")
    .name("My Brand")
    .send()
    .await?;

// Check generation progress
let status = notra.content()
    .get_brand_identity_generation(&job.job.id)
    .send()
    .await?;

// Get a brand identity
let identity = notra.content()
    .get_brand_identity("identity-id")
    .send()
    .await?;

// Update a brand identity
let updated = notra.content()
    .update_brand_identity("identity-id")
    .name("New Name")
    .tone_profile(ToneProfile::Professional)
    .language(Language::English)
    .audience("Developers")
    .is_default(true)
    .send()
    .await?;

// Delete a brand identity
notra.content()
    .delete_brand_identity("identity-id")
    .send()
    .await?;
```

### Integrations

```rust
// List all integrations
let integrations = notra.content()
    .list_integrations()
    .send()
    .await?;

for gh in &integrations.github {
    println!("{}/{} ({})", gh.owner, gh.repo, gh.default_branch);
}

// Connect a GitHub repository
let gh = notra.content()
    .create_github_integration("my-org", "my-repo")
    .branch("main")
    .send()
    .await?;

// Disconnect an integration
notra.content()
    .delete_integration("integration-id")
    .send()
    .await?;
```

## Error Handling

All methods return `Result<T, NotraError>`. The error type covers HTTP errors, API errors, and client misconfiguration:

```rust
use notra::NotraError;

match notra.content().get_post("bad-id").send().await {
    Ok(response) => println!("Found: {}", response.post.unwrap().title),
    Err(NotraError::Api { status: 404, .. }) => println!("Post not found"),
    Err(NotraError::Api { status, message }) => {
        println!("API error ({}): {}", status, message);
    }
    Err(e) => println!("Other error: {e}"),
}
```

## API Reference

All operations are accessible through `notra.content()`:

| Method | HTTP | Description |
|--------|------|-------------|
| `list_posts()` | `GET /v1/posts` | List posts with optional filters |
| `get_post(id)` | `GET /v1/posts/{id}` | Get a single post |
| `update_post(id)` | `PATCH /v1/posts/{id}` | Update a post |
| `delete_post(id)` | `DELETE /v1/posts/{id}` | Delete a post |
| `create_post_generation(type)` | `POST /v1/posts/generate` | Start AI post generation |
| `get_post_generation(job_id)` | `GET /v1/posts/generate/{id}` | Check generation status |
| `list_brand_identities()` | `GET /v1/brand-identities` | List brand identities |
| `get_brand_identity(id)` | `GET /v1/brand-identities/{id}` | Get a brand identity |
| `create_brand_identity(url)` | `POST /v1/brand-identities/generate` | Generate brand identity from website |
| `get_brand_identity_generation(job_id)` | `GET /v1/brand-identities/generate/{id}` | Check generation status |
| `update_brand_identity(id)` | `PATCH /v1/brand-identities/{id}` | Update a brand identity |
| `delete_brand_identity(id)` | `DELETE /v1/brand-identities/{id}` | Delete a brand identity |
| `list_integrations()` | `GET /v1/integrations` | List connected integrations |
| `create_github_integration(owner, repo)` | `POST /v1/integrations/github` | Connect a GitHub repo |
| `delete_integration(id)` | `DELETE /v1/integrations/{id}` | Disconnect an integration |

## Disclaimer

This is an **unofficial**, community-maintained SDK and is not affiliated with or endorsed by Notra. Use at your own discretion.

## License

MIT