···1919- `Cow<'a, str>` now supported by borrow-or-share pattern traits
20202121**OAuth permission sets, refactored scopes** (`jacquard-oauth`, `jacquard`, `jacquard-lexicon`)
2222-- Added `Scopes<S>` validated container for space-separated OAuth scope strings, replacing `Vec<Scope<S>>`. Stores a single string buffer with pre-computed byte-range indices, yielding zero-copy `Scope<&str>` views.
2222+- Added ergonomic `Scope` constructors for common atproto, account, identity, transition, repo, RPC, and permission-set scopes.
2323+- Added `Scopes::from_scopes()` and `ScopesBuilder` so callers can construct typed scopes programmatically while reusing the same validation, normalization, reduction, and indexing path as string parsing.
2424+- Added endpoint-aware `Scope::rpc_request::<R: XrpcRequest>()` and collection-aware repo helpers such as `Scope::repo_create_record::<C: Collection>()`.
2525+- Added `AuthorizeOptions` helpers for setting scopes from a string or typed scope values; builders can be passed through existing `with_scopes()` after `ScopesBuilder::build()`.
2326- Added `IncludeScope<S>` scope variant referencing permission set NSIDs with optional `?aud=<did>` audience.
2424-- Added permission set lexicon types (`LexPermissionSet`, `LexPermission`, `LexPermissionResource`) in jacquard-lexicon.
2525-- Added `expand_permission_set()` and `resolve_permission_set()` for converting permission set lexicons into concrete scopes.
2626-- Added `scope-check` feature to jacquard-oauth and jacquard, enabling client-side scope validation and eager resolution of `include:` scopes at session creation.
2727+- Updated OAuth examples and inline docs to demonstrate typed scope builders and link to the atproto OAuth scope docs and interactive scope-string builder.
27282829**Bootstrap XRPC types** (`jacquard-common`)
2930- Added `DidService<S>` validated type for DID audiences with optional service-id fragments (e.g., `did:web:example.com#bsky_appview`).
···146147- `DpopDataSource` trait methods return `Option<&str>` (was `Option<CowStr<'_>>`)
147148- DPoP proof building uses `&str` for zero-copy JWT construction
148149- `build_dpop_proof` takes `&str` parameters, returns `SmolStr`
150150+151151+**OAuth permission sets, refactored scopes** (`jacquard-oauth`, `jacquard`, `jacquard-lexicon`)
152152+- Added `Scopes<S>` validated container for space-separated OAuth scope strings, replacing `Vec<Scope<S>>`. Stores a single string buffer with pre-computed byte-range indices, yielding zero-copy `Scope<&str>` views.
153153+- Added `IncludeScope<S>` scope variant referencing permission set NSIDs with optional `?aud=<did>` audience.
154154+- Added permission set lexicon types (`LexPermissionSet`, `LexPermission`, `LexPermissionResource`) in jacquard-lexicon.
155155+- Added `expand_permission_set()` and `resolve_permission_set()` for converting permission set lexicons into concrete scopes.
156156+- Added `scope-check` feature to jacquard-oauth and jacquard, enabling client-side scope validation and eager resolution of `include:` scopes at session creation.
149157150158**Identity resolution** (`jacquard-identity`)
151159- `IdentityResolver::resolve_handle<S: BosStr + Sync>(&self, handle: &Handle<S>)`: generic over handle backing type
+8-6
crates/jacquard-lexicon/src/lexicon.rs
···66 CowStr,
77 deps::smol_str::SmolStr,
88 into_static::IntoStatic,
99- types::blob::MimeType,
1010- types::did::Did,
1111- types::nsid::Nsid,
1212- types::scope_primitives::{AccountAction, RepoAction},
99+ types::{
1010+ blob::MimeType,
1111+ nsid::Nsid,
1212+ scope_primitives::{AccountAction, RepoAction},
1313+ string::DidService,
1414+ },
1315};
1416use serde::{Deserialize, Serialize};
1517use serde_repr::{Deserialize_repr, Serialize_repr};
···455457 /// Lexicon method NSIDs this permission applies to.
456458 #[serde(borrow)]
457459 lxm: Vec<Nsid<CowStr<'s>>>,
458458- /// Audience DID for inter-service auth.
460460+ /// Audience DID with optional service fragment for inter-service auth.
459461 #[serde(borrow, default)]
460460- aud: Option<Did<CowStr<'s>>>,
462462+ aud: Option<DidService<CowStr<'s>>>,
461463 /// If true, inherits audience from the include scope's aud parameter.
462464 #[serde(default, rename = "inheritAud")]
463465 inherit_aud: Option<bool>,
+47
crates/jacquard-oauth/src/atproto.rs
···210210 self
211211 }
212212213213+ /// Set the OAuth scopes for this client.
214214+ pub fn with_scopes(mut self, scopes: Scopes<S>) -> Self {
215215+ self.scopes = scopes;
216216+ self
217217+ }
218218+219219+ /// Set the uri where the client's keys are hosted.
220220+ pub fn with_jwks_uri(mut self, jwks_uri: Uri<String>) -> Self {
221221+ self.jwks_uri = Some(jwks_uri);
222222+ self
223223+ }
224224+225225+ /// Set the human-readable display name for this client.
226226+ pub fn with_client_name(mut self, client_name: S) -> Self {
227227+ self.client_name = Some(client_name);
228228+ self
229229+ }
230230+213231 /// Create a default loopback client metadata with the `atproto` and `transition:generic` scopes.
214232 ///
215233 /// This is a convenience constructor for local development and CLI tools. The resulting
···223241 .expect("valid scopes")
224242 .convert();
225243 Self::new_localhost(None, Some(scopes))
244244+ }
245245+246246+ /// Create hosted client metadata with optional custom scopes.
247247+ ///
248248+ /// When `scopes` is `None`, the `atproto` scope is used.
249249+ /// Use the builder functions to set fields like the jwks_uri or client name, etc.
250250+ pub fn new(
251251+ redirect_uris: Vec<Uri<String>>,
252252+ client_id: Uri<String>,
253253+ scopes: Option<Scopes<S>>,
254254+ ) -> AtprotoClientMetadata<S>
255255+ where
256256+ S: From<SmolStr> + AsRef<str>,
257257+ {
258258+ let default_scopes: Scopes<S> = Scopes::new(SmolStr::new_static("atproto"))
259259+ .expect("valid scopes")
260260+ .convert();
261261+ AtprotoClientMetadata {
262262+ client_id: client_id.clone(),
263263+ client_uri: Some(client_id),
264264+ redirect_uris: redirect_uris,
265265+ grant_types: vec![GrantType::AuthorizationCode, GrantType::RefreshToken],
266266+ scopes: scopes.unwrap_or(default_scopes),
267267+ jwks_uri: None,
268268+ client_name: None,
269269+ logo_uri: None,
270270+ tos_uri: None,
271271+ privacy_policy_uri: None,
272272+ }
226273 }
227274228275 /// Create loopback client metadata with optional custom redirect URIs and scopes.