1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! A typed async client for the Claude account endpoints an OAuth login can
//! call: usage, profile, token validation, roles, prepaid credits and the
//! overage limit, and the refresh-token grant.
//!
//! Everything is read-only. Nothing here spends money, changes a setting
//! or mints a key; the only `POST`s are the token check
//! ([`Client::validate`]) and the refresh grant ([`Client::refresh`]).
//!
//! This crate is not affiliated with or endorsed by Anthropic. The
//! endpoints are undocumented: they are the ones Claude Code itself calls.
//! Their shapes can change without notice, so nearly every field is an
//! `Option` that reads as `None` when it is missing or of an unexpected
//! type, and each type keeps whatever else the response carried in its
//! `extra` map.
//!
//! - [`Client`]: one method per endpoint. It holds no token: each call
//! takes the one it acts with.
//! - [`Secret`]: a token. It never prints and its own buffer is zeroed on
//! drop (copies made along the way may not be: see [`Secret`]).
//! - [`Error`]: [`Error::Unauthorized`] (re-login), [`Error::Forbidden`]
//! (a good token without the scope or role),
//! [`Error::RateLimited`] (with `Retry-After`), [`Error::Http`],
//! [`Error::Decode`] (with a scrubbed body snippet), and the rest.
//!
//! # Read usage
//!
//! Add `ccwire-oauth = "0.1"` and Tokio to your application. Obtain an
//! access token through an existing Claude OAuth login; this crate does
//! not perform browser login or persist credentials.
//!
//! ```no_run
//! # async fn usage() -> Result<(), Box<dyn std::error::Error>> {
//! use ccwire_oauth::{Client, Secret};
//!
//! let token = Secret::new(std::env::var("CLAUDE_ACCESS_TOKEN")?);
//! let usage = Client::new()?.usage(&token).await?;
//! if let Some(window) = usage.five_hour {
//! println!("utilization: {:?}%", window.utilization);
//! }
//! # Ok(()) }
//! ```
//!
//! # Refresh and inspect a profile
//!
//! ```no_run
//! # async fn run() -> Result<(), ccwire_oauth::Error> {
//! use ccwire_oauth::{Client, RefreshRequest, Secret};
//!
//! let client = Client::new()?;
//! let stored = Secret::new("stored-refresh-token");
//! // Don't cancel a refresh once it's sent (see `Client::refresh`).
//! let tokens = client.refresh(&RefreshRequest::new(stored)).await?;
//! // Store tokens.refresh_token only if the stored one is still the one
//! // posted (compare-and-swap); it has been spent either way.
//! let profile = client.profile(&tokens.access_token).await?;
//! if let Some(org) = &profile.organization {
//! let limit = client.overage_spend_limit(&tokens.access_token, &org.uuid).await?;
//! println!("{:?} {:?}", limit.is_enabled, limit.used_credits);
//! }
//! # Ok(()) }
//! ```
//!
//! # License
//!
//! Licensed under the Apache License, Version 2.0 (`LICENSE`).
extern crate alloc;
pub use ;
pub use Error;
pub use Secret;
pub use ;
pub use ;
/// The README's example, compiled as a doctest.
;