+3
-6
crates/jacquard-common/src/types/cid.rs
+3
-6
crates/jacquard-common/src/types/cid.rs
···
1
-
use crate::{CowStr, IntoStatic};
1
+
use crate::{CowStr, IntoStatic, cowstr::ToCowStr};
2
2
pub use cid::Cid as IpldCid;
3
3
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
4
4
use smol_str::ToSmolStr;
···
379
379
where
380
380
E: serde::de::Error,
381
381
{
382
-
if let Ok(cid) = IpldCid::try_from(v.as_bytes()) {
383
-
Ok(CidLink(Cid::ipld(cid)))
384
-
} else {
385
-
Err(E::custom("invalid CID string"))
386
-
}
382
+
// TODO: currently overly permissive, should fix
383
+
Ok(CidLink::cow_str(v.to_cowstr()).into_static())
387
384
}
388
385
389
386
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+248
crates/jacquard/src/client.rs
+248
crates/jacquard/src/client.rs
···
47
47
use jacquard_common::types::string::AtUri;
48
48
#[cfg(feature = "api")]
49
49
use jacquard_common::types::uri::RecordUri;
50
+
#[cfg(not(target_arch = "wasm32"))]
51
+
use jacquard_common::xrpc::XrpcResponse;
50
52
use jacquard_common::xrpc::{
51
53
CallOptions, Response, XrpcClient, XrpcError, XrpcExt, XrpcRequest, XrpcResp,
52
54
};
···
58
60
use jacquard_identity::resolver::{
59
61
DidDocResponse, IdentityError, IdentityResolver, ResolverOptions,
60
62
};
63
+
use jacquard_identity::{JacquardResolver, slingshot_resolver_default};
61
64
use jacquard_oauth::authstore::ClientAuthStore;
62
65
use jacquard_oauth::client::OAuthSession;
63
66
use jacquard_oauth::dpop::DpopExt;
···
66
69
#[cfg(feature = "api")]
67
70
use std::marker::Send;
68
71
use std::option::Option;
72
+
use std::sync::Arc;
69
73
pub use token::FileAuthStore;
74
+
use tokio::sync::RwLock;
75
+
use url::Url;
70
76
71
77
/// Identifies the active authentication mode for an agent/session.
72
78
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
···
142
148
impl Default for BasicClient {
143
149
fn default() -> Self {
144
150
Self::unauthenticated()
151
+
}
152
+
}
153
+
pub struct UnauthenticatedSession<T> {
154
+
resolver: Arc<T>,
155
+
endpoint: Arc<RwLock<Option<Url>>>,
156
+
options: Arc<RwLock<CallOptions<'static>>>,
157
+
}
158
+
159
+
impl Default for UnauthenticatedSession<JacquardResolver> {
160
+
fn default() -> Self {
161
+
Self::new_public()
162
+
}
163
+
}
164
+
165
+
impl UnauthenticatedSession<JacquardResolver> {
166
+
pub fn new_public() -> Self {
167
+
let resolver = Arc::new(JacquardResolver::default());
168
+
let endpoint = Arc::new(RwLock::new(None));
169
+
let options = Arc::new(RwLock::new(CallOptions::default()));
170
+
Self {
171
+
resolver,
172
+
endpoint,
173
+
options,
174
+
}
175
+
}
176
+
177
+
pub fn new_slingshot() -> Self {
178
+
let resolver = Arc::new(slingshot_resolver_default());
179
+
let endpoint = Arc::new(RwLock::new(None));
180
+
let options = Arc::new(RwLock::new(CallOptions::default()));
181
+
Self {
182
+
resolver,
183
+
endpoint,
184
+
options,
185
+
}
186
+
}
187
+
}
188
+
189
+
impl<T: HttpClient + Sync> HttpClient for UnauthenticatedSession<T> {
190
+
type Error = T::Error;
191
+
192
+
#[cfg(not(target_arch = "wasm32"))]
193
+
fn send_http(
194
+
&self,
195
+
request: http::Request<Vec<u8>>,
196
+
) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, T::Error>> + Send {
197
+
self.resolver.send_http(request)
198
+
}
199
+
200
+
#[cfg(target_arch = "wasm32")]
201
+
fn send_http(
202
+
&self,
203
+
request: http::Request<Vec<u8>>,
204
+
) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, T::Error>> {
205
+
self.resolver.send_http(request)
206
+
}
207
+
}
208
+
209
+
impl<T: HttpClient> XrpcClient for UnauthenticatedSession<T>
210
+
where
211
+
T: Sync + Send,
212
+
{
213
+
#[doc = " Get the base URI for the client."]
214
+
fn base_uri(&self) -> impl Future<Output = Url> + Send {
215
+
async move {
216
+
self.endpoint.read().await.clone().unwrap_or(
217
+
Url::parse("https://public.bsky.app").expect("public appview should be valid url"),
218
+
)
219
+
}
220
+
}
221
+
222
+
#[doc = " Send an XRPC request and parse the response"]
223
+
#[cfg(not(target_arch = "wasm32"))]
224
+
fn send<R>(&self, request: R) -> impl Future<Output = XrpcResult<XrpcResponse<R>>> + Send
225
+
where
226
+
R: XrpcRequest + Send + Sync,
227
+
<R as XrpcRequest>::Response: Send + Sync,
228
+
Self: Sync,
229
+
{
230
+
async move {
231
+
let opts = self.options.read().await.clone();
232
+
self.send_with_opts(request, opts).await
233
+
}
234
+
}
235
+
236
+
#[doc = " Send an XRPC request and parse the response"]
237
+
#[cfg(not(target_arch = "wasm32"))]
238
+
fn send_with_opts<R>(
239
+
&self,
240
+
request: R,
241
+
opts: CallOptions<'_>,
242
+
) -> impl Future<Output = XrpcResult<XrpcResponse<R>>> + Send
243
+
where
244
+
R: XrpcRequest + Send + Sync,
245
+
<R as XrpcRequest>::Response: Send + Sync,
246
+
Self: Sync,
247
+
{
248
+
async move {
249
+
let base_uri = self.base_uri().await;
250
+
self.resolver
251
+
.xrpc(base_uri.clone())
252
+
.with_options(opts.clone())
253
+
.send(&request)
254
+
.await
255
+
}
256
+
}
257
+
258
+
#[doc = " Send an XRPC request and parse the response"]
259
+
#[cfg(target_arch = "wasm32")]
260
+
fn send<R>(&self, request: R) -> impl Future<Output = XrpcResult<XrpcResponse<R>>>
261
+
where
262
+
R: XrpcRequest + Send + Sync,
263
+
<R as XrpcRequest>::Response: Send + Sync,
264
+
{
265
+
async move {
266
+
let opts = self.options.read().await.clone();
267
+
self.send_with_opts(request, opts).await
268
+
}
269
+
}
270
+
271
+
#[doc = " Send an XRPC request and parse the response"]
272
+
#[cfg(target_arch = "wasm32")]
273
+
fn send_with_opts<R>(
274
+
&self,
275
+
request: R,
276
+
opts: CallOptions<'_>,
277
+
) -> impl Future<Output = XrpcResult<XrpcResponse<R>>>
278
+
where
279
+
R: XrpcRequest + Send + Sync,
280
+
<R as XrpcRequest>::Response: Send + Sync,
281
+
{
282
+
async move {
283
+
let base_uri = self.base_uri().await;
284
+
self.resolver
285
+
.xrpc(base_uri.clone())
286
+
.with_options(opts.clone())
287
+
.send(&request)
288
+
.await
289
+
}
290
+
}
291
+
292
+
#[doc = " Set the base URI for the client."]
293
+
fn set_base_uri(&self, url: Url) -> impl Future<Output = ()> + Send {
294
+
async move {
295
+
let mut guard = self.endpoint.write().await;
296
+
*guard = Some(url);
297
+
}
298
+
}
299
+
300
+
#[doc = " Get the call options for the client."]
301
+
fn opts(&self) -> impl Future<Output = CallOptions<'_>> + Send {
302
+
async move { self.options.read().await.clone() }
303
+
}
304
+
305
+
#[doc = " Set the call options for the client."]
306
+
fn set_opts(&self, opts: CallOptions<'_>) -> impl Future<Output = ()> + Send {
307
+
async move {
308
+
*self.options.write().await = opts.into_static();
309
+
}
310
+
}
311
+
}
312
+
313
+
impl<T: IdentityResolver + HttpClient> AgentSession for UnauthenticatedSession<T>
314
+
where
315
+
T: Sync + Send,
316
+
{
317
+
fn session_kind(&self) -> AgentKind {
318
+
AgentKind::AppPassword
319
+
}
320
+
321
+
fn session_info(
322
+
&self,
323
+
) -> impl Future<Output = Option<(Did<'static>, Option<CowStr<'static>>)>> {
324
+
async { None } // no session
325
+
}
326
+
327
+
fn endpoint(&self) -> impl Future<Output = Url> {
328
+
async { self.base_uri().await }
329
+
}
330
+
331
+
#[doc = " Override per-session call options."]
332
+
fn set_options<'a>(&'a self, opts: CallOptions<'a>) -> impl Future<Output = ()> + Send {
333
+
async move {
334
+
*self.options.write().await = opts.into_static();
335
+
}
336
+
}
337
+
338
+
#[doc = " Refresh the session and return a fresh AuthorizationToken."]
339
+
fn refresh(&self) -> impl Future<Output = ClientResult<AuthorizationToken<'static>>> + Send {
340
+
async {
341
+
Err(ClientError::auth(
342
+
jacquard_common::error::AuthError::NotAuthenticated,
343
+
))
344
+
}
345
+
}
346
+
}
347
+
348
+
impl<T: IdentityResolver + Sync> IdentityResolver for UnauthenticatedSession<T> {
349
+
#[doc = " Access options for validation decisions in default methods"]
350
+
fn options(&self) -> &ResolverOptions {
351
+
self.resolver.options()
352
+
}
353
+
354
+
#[doc = " Resolve handle"]
355
+
#[cfg(not(target_arch = "wasm32"))]
356
+
fn resolve_handle(
357
+
&self,
358
+
handle: &Handle<'_>,
359
+
) -> impl Future<Output = std::result::Result<Did<'static>, IdentityError>> + Send
360
+
where
361
+
Self: Sync,
362
+
{
363
+
self.resolver.resolve_handle(handle)
364
+
}
365
+
366
+
#[doc = " Resolve DID document"]
367
+
#[cfg(not(target_arch = "wasm32"))]
368
+
fn resolve_did_doc(
369
+
&self,
370
+
did: &Did<'_>,
371
+
) -> impl Future<Output = std::result::Result<DidDocResponse, IdentityError>> + Send
372
+
where
373
+
Self: Sync,
374
+
{
375
+
self.resolver.resolve_did_doc(did)
376
+
}
377
+
#[doc = " Resolve handle"]
378
+
#[cfg(target_arch = "wasm32")]
379
+
fn resolve_handle(
380
+
&self,
381
+
handle: &Handle<'_>,
382
+
) -> impl Future<Output = std::result::Result<Did<'static>, IdentityError>> {
383
+
self.resolver.resolve_handle(handle)
384
+
}
385
+
386
+
#[doc = " Resolve DID document"]
387
+
#[cfg(target_arch = "wasm32")]
388
+
fn resolve_did_doc(
389
+
&self,
390
+
did: &Did<'_>,
391
+
) -> impl Future<Output = std::result::Result<DidDocResponse, IdentityError>> {
392
+
self.resolver.resolve_did_doc(did)
145
393
}
146
394
}
147
395