bitwarden_access_connector/api/models.rs
1//! Domain types produced by the [`super`] API wrapper; the wire DTOs come from
2//! `bitwarden_api_api::models`.
3
4use uuid::Uuid;
5
6use crate::{auth::session::SessionLost, error::Retry};
7
8/// A claimable rotation job returned by the poll endpoint.
9#[derive(Debug, Clone)]
10pub(crate) struct JobRef {
11 pub(crate) id: Uuid,
12}
13
14/// Errors returned by the [`super::AccessConnectorClient`] wrapper. They never include response
15/// bodies, which can contain sensitive data.
16#[derive(Debug, thiserror::Error)]
17pub(crate) enum ApiError {
18 /// The connector's session was terminally lost (revoked or closed).
19 #[error("session lost: {0:?}")]
20 SessionLost(SessionLost),
21
22 /// The server returned 409. A claim maps it to `Ok(None)` instead.
23 #[error("rejected (HTTP {status})")]
24 Rejected {
25 /// The HTTP status, typically 409.
26 status: u16,
27 },
28
29 /// A 404 on an attempt-scoped route: the server does not know the attempt, so it should be
30 /// abandoned unreported.
31 #[error("attempt not found (404)")]
32 UnknownAttempt,
33
34 /// A 404 on a connector or job route: the server does not consider this connector eligible.
35 #[error("access connector not eligible (404 on connector route)")]
36 NotEligible,
37
38 /// A transport error, 429, 5xx, a 401 that survived the refresh retry, or any other unexpected
39 /// status. The message is a bounded status or error kind, never body content.
40 #[error("transient error: {0}")]
41 Transient(String),
42
43 /// The response could not be decoded or lacked a required field.
44 #[error("protocol error: {0}")]
45 Protocol(String),
46}
47
48impl ApiError {
49 /// Only a transient error is worth retrying.
50 pub(crate) fn retry_class(&self) -> Retry {
51 match self {
52 ApiError::Transient(_) => Retry::Transient,
53 _ => Retry::Permanent,
54 }
55 }
56}