forecite 0.1.3

Official Rust SDK for the Forecite API — scored news feed (REST), Verdict scoring, and realtime WebSocket streaming.
Documentation
# forecite (Rust SDK)

[![crates.io](https://img.shields.io/crates/v/forecite.svg)](https://crates.io/crates/forecite)
[![docs.rs](https://img.shields.io/docsrs/forecite)](https://docs.rs/forecite)
[![license: MIT](https://img.shields.io/crates/l/forecite.svg)](./LICENSE)

Official Rust SDK for the [Forecite](https://forecite.dev) API — the scored news
feed (REST), the Verdict scoring engine, and the realtime WebSocket stream.
Async, built on `reqwest` (rustls) + `tokio-tungstenite`.

## Install

```bash
cargo add forecite
# plus an async runtime if you don't have one:
cargo add tokio --features macros,rt-multi-thread
```

## Quick start

```rust
use forecite::{Forecite, FeedsQuery, Artifact};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let forecite = Forecite::new("fc_live_your_key");
    // or: Forecite::builder("fc_live_…").base_url("http://localhost:3000/api").build()

    // REST — list scored feeds
    let feeds = forecite
        .feeds_list(&FeedsQuery { symbol: Some("TSLA".into()), limit: Some(20), ..Default::default() })
        .await?;
    println!("{} feeds, next_cursor={:?}", feeds.data.len(), feeds.next_cursor);

    // Score an artifact (Pro+)
    let verdict = forecite
        .score(&Artifact {
            kind: "news".into(),
            title: "Acme beats earnings".into(),
            body: "Acme reported Q2 revenue of …".into(),
            tags: None, related_symbols: None, published_at: None,
        }, None)
        .await?;
    println!("{:?}", verdict.actionability);

    Ok(())
}
```

## Realtime stream

```rust
use forecite::{Forecite, StreamFilters, StreamEvent};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let forecite = Forecite::new("fc_live_your_key");
    let filters = StreamFilters { symbols: Some(vec!["TSLA".into(), "AAPL".into()]), ..Default::default() };

    let mut stream = forecite.stream(&filters, 10).await?;
    while let Some(event) = stream.next().await? {
        match event {
            StreamEvent::Welcome { tier, .. } => println!("connected: {tier}"),
            StreamEvent::Feed { snapshot, data, .. } =>
                println!("[{}] {:?}", if snapshot { "snap" } else { "live" }, data.title),
            StreamEvent::QuotaExceeded { message, .. } => eprintln!("{message}"),
            _ => {}
        }
    }
    Ok(())
}
```

## API surface

| Group | Methods |
|---|---|
| Feeds | `feeds_list`, `feeds_get` |
| Scoring | `score` |
| Account | `me`, `usage` |
| Reference | `providers_list/get`, `sources_list/get`, `symbols_list/get`, `tags_list/get` |
| Webhooks | `webhooks_list/create/get/update/delete` |
| Realtime | `stream``ForeciteStream::next` |

All methods are `async` and return `Result<_, ForeciteError>`. Defaults:
`https://api.forecite.dev` / `wss://ws.forecite.dev` (override via the builder).