kagi_sdk/lib.rs
1//! Rust SDK for Kagi with explicit protocol surfaces.
2//!
3//! ## Overview
4//!
5//! `kagi-sdk` models Kagi access as two distinct surfaces:
6//!
7//! 1. **Official API surface**
8//! - Auth header: `Authorization: Bot <token>`
9//! - Route families: `/api/v0/*` and `/api/v1/*` (in-scope subset)
10//! - Response shape: JSON envelopes
11//!
12//! 2. **Session web surface**
13//! - Cookie header: `Cookie: kagi_session=<token>`
14//! - Routes: `/html/search`, `/mother/summary_labs`, `/mother/summary_labs/`
15//! - Response shape:
16//! - `search(...)`: HTML parsing
17//! - `summarize(...)`: JSON parsing
18//! - `summarize_stream(...)`: framed stream parsing (advanced)
19//!
20//! The SDK enforces auth/surface compatibility at runtime before request execution,
21//! returning explicit errors for unsupported combinations.
22//!
23//! ## Quickstart: official API (bot token)
24//!
25//! ```no_run
26//! use kagi_sdk::{BotToken, KagiClient};
27//! use kagi_sdk::official_api::models::SearchRequest;
28//!
29//! # async fn run() -> Result<(), kagi_sdk::KagiError> {
30//! let token = BotToken::new(std::env::var("KAGI_API_KEY").expect("set KAGI_API_KEY"))?;
31//! let client = KagiClient::with_bot_token(token)?;
32//! let api = client.official_api()?;
33//!
34//! let response = api.search(SearchRequest::new("rust error handling")?).await?;
35//! println!("{:#?}", response.data);
36//! # Ok(())
37//! # }
38//! # fn main() {}
39//! ```
40//!
41//! ## Quickstart: session web (session token)
42//!
43//! ```no_run
44//! use kagi_sdk::{KagiClient, SessionToken};
45//! use kagi_sdk::session_web::models::{SearchRequest, SummarizeRequest};
46//!
47//! # async fn run() -> Result<(), kagi_sdk::KagiError> {
48//! let token =
49//! SessionToken::new(std::env::var("KAGI_SESSION_TOKEN").expect("set KAGI_SESSION_TOKEN"))?;
50//! let client = KagiClient::with_session_token(token)?;
51//! let web = client.session_web()?;
52//!
53//! let search = web.search(SearchRequest::new("kagi rust sdk")?).await?;
54//! let summary = web
55//! .summarize(SummarizeRequest::from_url("https://example.com")?)
56//! .await?;
57//! println!("{} {}", search.results.len(), summary.markdown.len());
58//! # Ok(())
59//! # }
60//! # fn main() {}
61//! ```
62//!
63//! ## Builder configuration example
64//!
65//! ```no_run
66//! use std::time::Duration;
67//! use kagi_sdk::{BotToken, ClientConfig, KagiClient};
68//!
69//! # fn run() -> Result<(), kagi_sdk::KagiError> {
70//! let config = ClientConfig::default()
71//! .with_timeout(Duration::from_secs(15))
72//! .with_user_agent("my-app/0.1.0");
73//!
74//! let _client = KagiClient::builder()
75//! .config(config)
76//! .bot_token(BotToken::new("your-token")?)
77//! .build()?;
78//! # Ok(())
79//! # }
80//! # fn main() {}
81//! ```
82//!
83//! ## Error handling
84//!
85//! Most fallible operations return [`KagiError`]. Prefer `?` propagation and map errors at your
86//! application boundary.
87//!
88//! ## Module overview
89//!
90//! | Module | Purpose |
91//! |---|---|
92//! | [`auth`] | Credential types and header/cookie application |
93//! | [`client`] | `KagiClient` construction and surface entrypoints |
94//! | [`config`] | Client base URL, timeout, and user-agent configuration |
95//! | [`official_api`] | Typed official API requests and envelope parsing |
96//! | [`session_web`] | Typed session-web requests for HTML search, JSON summarize, and advanced framed streaming |
97//! | [`parsing`] | Parser helpers for session HTML search, summarize JSON, and framed streaming |
98//! | [`routing`] | Endpoint metadata (surface, version, parser shape) |
99//! | [`error`] | Central typed error model |
100//!
101//! ## Safety
102//!
103//! This crate forbids `unsafe` Rust (`#![forbid(unsafe_code)]`).
104//!
105#![forbid(unsafe_code)]
106
107mod boundary;
108mod transport;
109
110pub mod auth;
111pub mod client;
112pub mod config;
113pub mod error;
114pub mod official_api;
115pub mod parsing;
116pub mod routing;
117pub mod session_web;
118
119pub use auth::{BotToken, CredentialKind, Credentials, SessionToken};
120pub use boundary::{HttpUrl, NonBlankString, NonEmptyString};
121pub use client::{KagiClient, KagiClientBuilder};
122pub use config::ClientConfig;
123pub use error::KagiError;