1use crate::error::Error;
21use crate::types::*;
22
23pub const DEFAULT_API_URL: &str = "https://api.openagentid.org";
28
29pub struct RegistryClient {
31 base_url: String,
32 http: reqwest::Client,
33}
34
35impl RegistryClient {
36 pub fn new(base_url: Option<&str>) -> Self {
41 Self {
42 base_url: base_url
43 .unwrap_or(DEFAULT_API_URL)
44 .trim_end_matches('/')
45 .to_string(),
46 http: reqwest::Client::new(),
47 }
48 }
49
50 pub async fn challenge(&self, wallet_address: &str) -> Result<Challenge, Error> {
58 let url = format!("{}/v1/auth/challenge", self.base_url);
59 let resp = self
60 .http
61 .post(&url)
62 .json(&serde_json::json!({ "wallet_address": wallet_address }))
63 .send()
64 .await
65 .map_err(|e| Error::Api(format!("challenge request failed: {e}")))?;
66 Self::parse_response(resp).await
67 }
68
69 pub async fn wallet_auth(&self, req: &WalletAuthRequest) -> Result<WalletAuthResponse, Error> {
73 let url = format!("{}/v1/auth/wallet", self.base_url);
74 let resp = self
75 .http
76 .post(&url)
77 .json(req)
78 .send()
79 .await
80 .map_err(|e| Error::Api(format!("wallet auth request failed: {e}")))?;
81 Self::parse_response(resp).await
82 }
83
84 pub async fn register(
92 &self,
93 token: &str,
94 req: &RegistrationRequest,
95 ) -> Result<RegistrationResponse, Error> {
96 let url = format!("{}/v1/agents", self.base_url);
97 let resp = self
98 .http
99 .post(&url)
100 .bearer_auth(token)
101 .json(req)
102 .send()
103 .await
104 .map_err(|e| Error::Api(format!("register request failed: {e}")))?;
105 Self::parse_response(resp).await
106 }
107
108 pub async fn lookup(&self, did: &str) -> Result<AgentInfo, Error> {
112 let url = format!("{}/v1/agents/{}", self.base_url, did);
113 let resp = self
114 .http
115 .get(&url)
116 .send()
117 .await
118 .map_err(|e| Error::Api(format!("lookup request failed: {e}")))?;
119 Self::parse_response(resp).await
120 }
121
122 pub async fn list_my_agents(
126 &self,
127 token: &str,
128 cursor: Option<&str>,
129 limit: Option<u32>,
130 ) -> Result<ListAgentsResponse, Error> {
131 let mut url = format!("{}/v1/agents", self.base_url);
132 let mut has_param = false;
133 if let Some(c) = cursor {
134 url.push_str(&format!("?cursor={c}"));
135 has_param = true;
136 }
137 if let Some(l) = limit {
138 url.push_str(&format!("{}limit={l}", if has_param { "&" } else { "?" }));
139 }
140 let resp = self
141 .http
142 .get(&url)
143 .bearer_auth(token)
144 .send()
145 .await
146 .map_err(|e| Error::Api(format!("list request failed: {e}")))?;
147 Self::parse_response(resp).await
148 }
149
150 pub async fn update_agent(
154 &self,
155 token: &str,
156 did: &str,
157 req: &UpdateAgentRequest,
158 ) -> Result<AgentInfo, Error> {
159 let url = format!("{}/v1/agents/{}", self.base_url, did);
160 let resp = self
161 .http
162 .patch(&url)
163 .bearer_auth(token)
164 .json(req)
165 .send()
166 .await
167 .map_err(|e| Error::Api(format!("update agent request failed: {e}")))?;
168 Self::parse_response(resp).await
169 }
170
171 pub async fn revoke(&self, token: &str, did: &str) -> Result<(), Error> {
175 let url = format!("{}/v1/agents/{}", self.base_url, did);
176 let resp = self
177 .http
178 .delete(&url)
179 .bearer_auth(token)
180 .send()
181 .await
182 .map_err(|e| Error::Api(format!("revoke request failed: {e}")))?;
183 if !resp.status().is_success() {
184 let status = resp.status();
185 let body = resp.text().await.unwrap_or_default();
186 return Err(Error::Api(format!("revoke failed ({status}): {body}")));
187 }
188 Ok(())
189 }
190
191 pub async fn rotate_key(
195 &self,
196 token: &str,
197 did: &str,
198 req: &RotateKeyRequest,
199 ) -> Result<(), Error> {
200 let url = format!("{}/v1/agents/{}/key", self.base_url, did);
201 let resp = self
202 .http
203 .put(&url)
204 .bearer_auth(token)
205 .json(req)
206 .send()
207 .await
208 .map_err(|e| Error::Api(format!("rotate key request failed: {e}")))?;
209 if !resp.status().is_success() {
210 let status = resp.status();
211 let body = resp.text().await.unwrap_or_default();
212 return Err(Error::Api(format!(
213 "rotate key failed ({status}): {body}"
214 )));
215 }
216 Ok(())
217 }
218
219 pub async fn get_credit(&self, did: &str) -> Result<CreditInfo, Error> {
227 let url = format!("{}/v1/credit/{}", self.base_url, did);
228 let resp = self
229 .http
230 .get(&url)
231 .send()
232 .await
233 .map_err(|e| Error::Api(format!("credit lookup request failed: {e}")))?;
234 Self::parse_response(resp).await
235 }
236
237 pub async fn verify(&self, req: &VerifyRequest) -> Result<VerifyResponse, Error> {
245 let url = format!("{}/v1/verify", self.base_url);
246 let resp = self
247 .http
248 .post(&url)
249 .json(req)
250 .send()
251 .await
252 .map_err(|e| Error::Api(format!("verify request failed: {e}")))?;
253 Self::parse_response(resp).await
254 }
255
256 pub async fn deploy_wallet(&self, token: &str, did: &str) -> Result<(), Error> {
264 let url = format!("{}/v1/agents/{}/deploy-wallet", self.base_url, did);
265 let resp = self
266 .http
267 .post(&url)
268 .bearer_auth(token)
269 .send()
270 .await
271 .map_err(|e| Error::Api(format!("deploy wallet request failed: {e}")))?;
272 if !resp.status().is_success() {
273 let status = resp.status();
274 let body = resp.text().await.unwrap_or_default();
275 return Err(Error::Api(format!(
276 "deploy wallet failed ({status}): {body}"
277 )));
278 }
279 Ok(())
280 }
281
282 async fn parse_response<T: serde::de::DeserializeOwned>(
288 resp: reqwest::Response,
289 ) -> Result<T, Error> {
290 if !resp.status().is_success() {
291 let status = resp.status();
292 let body = resp.text().await.unwrap_or_default();
293 return Err(Error::Api(format!("{status}: {body}")));
294 }
295 resp.json::<T>()
296 .await
297 .map_err(|e| Error::Api(format!("failed to parse response: {e}")))
298 }
299}