1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, SdkError>;
4
5#[derive(Debug, Error)]
6pub enum SdkError {
7 #[error("invalid agent id: {0}")]
8 InvalidAgentId(String),
9
10 #[error("agent id must start with did:agent:")]
11 InvalidAgentIdPrefix,
12
13 #[error("invalid public key length: expected 32 bytes, got {0}")]
14 InvalidPublicKeyLength(usize),
15
16 #[error("canonical JSON error: {0}")]
17 CanonicalJson(String),
18
19 #[error("JSON error: {0}")]
20 Json(#[from] serde_json::Error),
21
22 #[error("base64url decode error: {0}")]
23 Base64(#[from] base64::DecodeError),
24
25 #[error("Ed25519 error: {0}")]
26 Ed25519(#[from] ed25519_dalek::SignatureError),
27
28 #[error("random generation error: {0}")]
29 Random(String),
30
31 #[error("invalid signature length: expected 64 bytes, got {0}")]
32 InvalidSignatureLength(usize),
33
34 #[error("invalid event hash: expected {expected}, got {actual}")]
35 InvalidEventHash { expected: String, actual: String },
36
37 #[error("invalid event hash length: expected 32 bytes, got {0}")]
38 InvalidEventHashLength(usize),
39
40 #[error("invalid event protocol: expected {expected}, got {actual}")]
41 InvalidEventProtocol { expected: String, actual: String },
42
43 #[error("invalid event type: expected {expected}, got {actual}")]
44 InvalidEventType { expected: String, actual: String },
45
46 #[error("invalid actor: {0}")]
47 InvalidActor(String),
48
49 #[error("timestamp is outside the allowed live-write window")]
50 TimestampOutOfWindow,
51
52 #[error("invalid nonce: {0}")]
53 InvalidNonce(String),
54
55 #[error("nonce must be greater than accepted max nonce {max_nonce}")]
56 NonceNotGreater { max_nonce: u64 },
57
58 #[error("event requires a room_id")]
59 MissingRoomId,
60
61 #[error("room id mismatch: expected {expected}, got {actual}")]
62 RoomIdMismatch { expected: String, actual: String },
63
64 #[error("permission denied")]
65 PermissionDenied,
66
67 #[error("invalid payload: {0}")]
68 InvalidPayload(String),
69
70 #[error("event type is not defined in the room: {0}")]
71 TypeNotDefined(String),
72
73 #[error("event type is disabled in the room: {0}")]
74 TypeDisabled(String),
75
76 #[error("payload does not satisfy the type schema: {0}")]
77 PayloadSchemaViolation(String),
78
79 #[error("type pack cannot be resolved or fails verification: {0}")]
80 PackUnavailable(String),
81
82 #[error("invalid JWT: {0}")]
83 InvalidJwt(String),
84
85 #[error("invalid JWT claim: {0}")]
86 InvalidJwtClaim(&'static str),
87
88 #[error("{code}: {message}")]
90 Protocol { code: &'static str, message: String },
91
92 #[error("{code}: {message}")]
94 ProtocolWithData {
95 code: &'static str,
96 message: String,
97 data: serde_json::Value,
98 },
99
100 #[error("paginated read did not complete within {0} pages")]
102 PageLimitExceeded(usize),
103
104 #[error("HTTP {status}: {body}")]
108 HttpStatus {
109 status: u16,
110 code: Option<String>,
111 data: Option<serde_json::Value>,
112 max_seen_nonce: Option<String>,
113 body: String,
114 },
115
116 #[cfg(feature = "http-client")]
117 #[error("HTTP client error: {0}")]
118 Http(#[from] reqwest::Error),
119}
120
121impl SdkError {
122 pub fn protocol(code: &'static str, message: impl Into<String>) -> Self {
124 Self::Protocol {
125 code,
126 message: message.into(),
127 }
128 }
129
130 pub fn protocol_with_data(
131 code: &'static str,
132 message: impl Into<String>,
133 data: serde_json::Value,
134 ) -> Self {
135 Self::ProtocolWithData {
136 code,
137 message: message.into(),
138 data,
139 }
140 }
141
142 pub fn data(&self) -> Option<&serde_json::Value> {
143 match self {
144 Self::ProtocolWithData { data, .. } => Some(data),
145 Self::HttpStatus { data, .. } => data.as_ref(),
146 _ => None,
147 }
148 }
149
150 pub fn code(&self) -> Option<&str> {
152 match self {
153 Self::Protocol { code, .. } | Self::ProtocolWithData { code, .. } => Some(code),
154 Self::HttpStatus { code, .. } => code.as_deref(),
155 Self::InvalidSignatureLength(_) | Self::Ed25519(_) => Some("invalid_signature"),
156 Self::InvalidEventHash { .. } | Self::InvalidEventHashLength(_) => {
157 Some("invalid_event_hash")
158 }
159 Self::TimestampOutOfWindow => Some("timestamp_out_of_window"),
160 Self::NonceNotGreater { .. } => Some("nonce_not_greater"),
161 Self::PermissionDenied => Some("permission_denied"),
162 Self::TypeNotDefined(_) => Some("type_not_defined"),
163 Self::TypeDisabled(_) => Some("type_disabled"),
164 Self::PayloadSchemaViolation(_) => Some("payload_schema_violation"),
165 Self::PackUnavailable(_) => Some("pack_unavailable"),
166 Self::InvalidJwt(_) | Self::InvalidJwtClaim(_) => Some("invalid_token"),
167 Self::InvalidActor(_) => Some("invalid_actor"),
168 _ => None,
169 }
170 }
171}