Skip to main content

Client

Struct Client 

Source
pub struct Client { /* private fields */ }
Expand description

A client for the account endpoints.

Every call takes the token it acts with; the client holds none. It is cheap to clone (the connection pool is shared).

use ccwire_oauth::{Client, Secret};

let client = Client::new()?;
let token = Secret::new(std::env::var("ACCESS_TOKEN").unwrap_or_default());
let usage = client.usage(&token).await?;
if let Some(w) = usage.five_hour {
    println!("5h: {:?}% (resets {:?})", w.utilization, w.resets_at);
}

Implementations§

Source§

impl Client

Source

pub fn new() -> Result<Self, Error>

A client with the defaults.

§Errors

See ClientBuilder::build.

Source

pub fn builder() -> ClientBuilder

A ClientBuilder with the defaults.

Source

pub async fn usage(&self, token: &Secret) -> Result<Usage, Error>

GET /api/oauth/usage: the 5-hour and 7-day windows and extra usage.

§Errors

Error; a token without the profile scope is Error::Forbidden.

Source

pub async fn profile(&self, token: &Secret) -> Result<Profile, Error>

GET /api/oauth/profile: the account and its organization.

§Errors

Error; an inference-only token is Error::Forbidden.

Source

pub async fn validate(&self, token: &Secret) -> Result<(), Error>

POST /api/oauth/validate: whether the token is good, without reading anything. Ok(()) if it is.

The endpoint accepts tokens with user:profile (a subscription login) and refuses inference-only ones.

§Errors

Error::Unauthorized for a bad, expired or revoked token, Error::Forbidden for one without an accepted scope; Error otherwise.

Source

pub async fn roles(&self, token: &Secret) -> Result<Roles, Error>

GET /api/oauth/claude_cli/roles: the user’s roles in the token’s organization.

§Errors

Error.

Source

pub async fn prepaid_credits( &self, token: &Secret, org: &str, ) -> Result<PrepaidCredits, Error>

GET /api/oauth/organizations/{org}/prepaid/credits: the prepaid credit balance. org is Organization::uuid.

§Errors

Error::Config for an empty, . or .. org; Error.

Source

pub async fn overage_spend_limit( &self, token: &Secret, org: &str, ) -> Result<OverageSpendLimit, Error>

GET /api/oauth/organizations/{org}/overage_spend_limit: the extra usage limit and what’s spent against it. Read-only: this crate never changes it.

§Errors

Error::Config for an empty, . or .. org; Error.

Source

pub async fn refresh(&self, req: &RefreshRequest) -> Result<TokenSet, Error>

Posts a refresh-token grant to the token endpoint and returns the new tokens.

A plain call: it stores nothing and takes no lock. The posted refresh token is spent once the server answers, so the caller stores the result with a compare-and-swap (see TokenSet).

The response is read leniently: as long as it carries the tokens, they come back, whatever the other fields hold (a missing or odd expires_in is None).

§Don’t cancel it

Once the request is sent, the server may already have spent the posted refresh token. Dropping this future then (a select! that picks another branch, a tokio::time::timeout shorter than the client’s own, an aborted task) throws away the new tokens, and the login is lost: the old refresh token is dead and the new one was never stored. Await it to the end; the client’s own timeout (ClientBuilder::timeout) bounds it. If the caller itself may be cancelled, use Client::refresh_and_store, which runs the refresh and the store in a task of their own.

§Errors

Error::Unauthorized with code invalid_grant for a revoked or already-rotated refresh token (a new login is needed); Error::Decode only for a body without the tokens; Error otherwise.

Source

pub fn refresh_and_store<F, Fut, R>( &self, req: RefreshRequest, store: F, ) -> impl Future<Output = Result<R, Error>> + Send + 'static
where F: FnOnce(TokenSet) -> Fut + Send + 'static, Fut: Future<Output = R> + Send + 'static, R: Send + 'static,

Client::refresh, then store with the new tokens, both in a task of their own (tokio::spawn): once this is called they run to the end even if the returned future is dropped, so a cancelled caller can’t lose a rotated login.

store runs only on success, and gets the TokenSet; do the compare-and-swap there. The returned future gives store’s output. The task starts when this is called, not when the future is first polled.

use ccwire_oauth::{RefreshRequest, Secret};

let req = RefreshRequest::new(Secret::new("stored-refresh-token"));
let access = client
    .refresh_and_store(req, |tokens| async move {
        // Compare-and-swap tokens.refresh_token into the store here.
        tokens.access_token
    })
    .await?;
§Errors

As Client::refresh; Error::Cancelled if the task was cancelled (its runtime shut down).

§Panics

Outside a tokio runtime. A panic in store resumes in the caller.

Trait Implementations§

Source§

impl Clone for Client

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Client

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Client

§

impl !UnwindSafe for Client

§

impl Forget for Client

§

impl Freeze for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl UnsafeUnpin for Client

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more