+1
Cargo.lock
+1
Cargo.lock
+177
-14
crates/jacquard-common/src/types/xrpc.rs
+177
-14
crates/jacquard-common/src/types/xrpc.rs
···························
+12
crates/jacquard-identity/src/resolver.rs
+12
crates/jacquard-identity/src/resolver.rs
···+#[diagnostic(code(jacquard_identity::unsupported_did_method), help("supported DID methods: did:web, did:plc"))]+#[diagnostic(code(jacquard_identity::invalid_well_known), help("expected first non-empty line to be a DID"))]+#[diagnostic(code(jacquard_identity::http), help("check network connectivity and TLS configuration"))]+#[diagnostic(code(jacquard_identity::http_status), help("verify well-known paths or PDS XRPC endpoints"))]+#[diagnostic(code(jacquard_identity::xrpc), help("enable PDS fallback or public resolver if needed"))]+#[diagnostic(code(jacquard_identity::invalid_doc), help("validate keys and services; ensure AtprotoPersonalDataServer service exists"))]+#[diagnostic(code(jacquard_identity::doc_id_mismatch), help("document id differs from requested DID; do not trust this document"))]
+1
crates/jacquard-oauth/Cargo.toml
+1
crates/jacquard-oauth/Cargo.toml
+77
-26
crates/jacquard-oauth/src/atproto.rs
+77
-26
crates/jacquard-oauth/src/atproto.rs
············-"http://localhost?redirect_uri=http%3A%2F%2F127.0.0.1%2Fcallback&redirect_uri=http%3A%2F%2F%5B%3A%3A1%5D%2Fcallback&scope=account%3Aemail+atproto+transition%3Ageneric"+"http://localhost?redirect_uri=http%3A%2F%2Flocalhost%2Fcallback&redirect_uri=http%3A%2F%2Flocalhost%2Fcallback&scope=account%3Aemail+atproto+transition%3Ageneric"······
+26
-22
crates/jacquard-oauth/src/client.rs
+26
-22
crates/jacquard-oauth/src/client.rs
·········+return Err(CallbackError::IssuerMismatch { expected: metadata.issuer.to_string(), got: iss.to_string() }.into());···+self.data.read().await.token_set.refresh_token.as_ref().map(|t| AuthorizationToken::Dpop(t.clone()))·········
+50
-39
crates/jacquard-oauth/src/error.rs
+50
-39
crates/jacquard-oauth/src/error.rs
···
+207
-17
crates/jacquard-oauth/src/request.rs
+207
-17
crates/jacquard-oauth/src/request.rs
···+#[diagnostic(code(jacquard_oauth::request::no_endpoint), help("server does not advertise this endpoint"))]+#[diagnostic(code(jacquard_oauth::request::http_status), help("see server response for details"))]+#[diagnostic(code(jacquard_oauth::request::http_status_body), help("server returned error JSON; inspect fields like `error`, `error_description`"))]···························
+129
-17
crates/jacquard-oauth/src/resolver.rs
+129
-17
crates/jacquard-oauth/src/resolver.rs
···+#[diagnostic(code(jacquard_oauth::resolver::not_found), help("check the base URL or identifier"))]+#[diagnostic(code(jacquard_oauth::resolver::at_identifier), help("ensure a valid handle or DID was provided"))]+#[diagnostic(code(jacquard_oauth::resolver::did), help("ensure DID is correctly formed (did:plc or did:web)"))]+#[diagnostic(code(jacquard_oauth::resolver::did_document), help("verify the DID document structure and service entries"))]+#[diagnostic(code(jacquard_oauth::resolver::protected_resource_metadata), help("PDS must advertise an authorization server in its protected resource metadata"))]+#[diagnostic(code(jacquard_oauth::resolver::authorization_server_metadata), help("issuer must match and include the PDS resource"))]+#[diagnostic(code(jacquard_oauth::resolver::unsupported_did_method), help("supported DID methods: did:web, did:plc"))]+#[diagnostic(code(jacquard_oauth::resolver::http_status), help("check well-known paths and server configuration"))]···············+*client.next.lock().await = Some(HttpResponse::builder().status(StatusCode::NOT_FOUND).body(Vec::new()).unwrap());+*client.next.lock().await = Some(HttpResponse::builder().status(StatusCode::OK).body(b"{not json}".to_vec()).unwrap());
+6
-3
crates/jacquard-oauth/src/session.rs
+6
-3
crates/jacquard-oauth/src/session.rs
······
+7
-3
crates/jacquard/src/client.rs
+7
-3
crates/jacquard/src/client.rs
···············
+41
-4
crates/jacquard/src/client/credential_session.rs
+41
-4
crates/jacquard/src/client/credential_session.rs
························
+95
-25
crates/jacquard/src/client/token.rs
+95
-25
crates/jacquard/src/client/token.rs
···-// Base URL of the "resource server" (eg, PDS). Should include scheme, hostname, port; no path or auth info.-// Base URL of the "auth server" (eg, PDS or entryway). Should include scheme, hostname, port; no path or auth info.···-// The random identifier generated by the client for the auth request flow. Can be used as "primary key" for storing and retrieving this information.-// If the flow started with an account identifier (DID or handle), it should be persisted, to verify against the initial token response.············
+4
-4
crates/jacquard/src/lib.rs
+4
-4
crates/jacquard/src/lib.rs
············
+147
crates/jacquard/tests/agent.rs
+147
crates/jacquard/tests/agent.rs
···+// Queue a refresh response and call agent.refresh(); Authorization header must use refresh token
+261
crates/jacquard/tests/credential_session.rs
+261
crates/jacquard/tests/credential_session.rs
···+// Queue responses in order: createSession 200 → getSession 401 → refreshSession 200 → getSession 200
+374
crates/jacquard/tests/oauth_auto_refresh.rs
+374
crates/jacquard/tests/oauth_auto_refresh.rs
···+) -> std::result::Result<jacquard::identity::resolver::DidDocResponse, jacquard::identity::resolver::IdentityError> {+) -> Result<OAuthAuthorizationServerMetadata<'static>, jacquard_oauth::resolver::ResolverError> {+) -> Result<OAuthAuthorizationServerMetadata<'static>, jacquard_oauth::resolver::ResolverError> {+md.pushed_authorization_request_endpoint = Some(jacquard::CowStr::from("https://issuer/par"));+assert!(log[0].headers().get(http::header::AUTHORIZATION).unwrap().to_str().unwrap().starts_with("DPoP "));+// Queue responses: initial 401 with JSON body; token refresh 400(use_dpop_nonce); token refresh 200; retry getSession 200
+293
crates/jacquard/tests/oauth_flow.rs
+293
crates/jacquard/tests/oauth_flow.rs
···
+125
crates/jacquard/tests/restore_pds_cache.rs
+125
crates/jacquard/tests/restore_pds_cache.rs
···