···27272828### Changed
29293030-- Import cleanup across all crates
3130- Dependency updates (upgraded various crypto and serialization dependencies)
3231- Documentation improvements throughout
3232+- Made handle parsing a bit more permissive for a common case ('handle.invalid' when someone has a messed up handle), added a method to confirm syntactic validity (the correct way to confirm validity is resolve_handle() from IdentityResolver, and comparing to the DID document).
33333434## [0.7.0] - 2025-10-19
3535
+3-1
README.md
···1616 - repository CAR file read/write support
1717 - CAR file write order compatible with streaming mode from the [sync iteration proposal](https://github.com/bluesky-social/proposals/blob/main/0006-sync-iteration/README.md#streaming-car-processing)
1818 - Big rewrite of all the errors in the crate, improvements to context and overall structure
1919+ - Made handle parsing a bit more permissive for a common case ('handle.invalid' when someone has a messed up handle), added a method to confirm syntactic validity (the correct way to confirm validity is resolve_handle() from the IdentityResolver trait, then fetching and comparing to the DID document).
19202021> [!WARNING]
2122> A lot of the streaming code is still pretty experimental. The examples work, though.\
2222-The modules are also less well-documented, and don't have code examples. There are also a lot of utility functions for conveniently working with the streams and transforming them which are lacking. Use [`n0-future`](https://docs.rs/n0-future/latest/n0_future/index.html) to work with them, that is what Jacquard uses internally as much as possible. I would also note the same for the repository crate until I've had more third parties test it.
2323+The modules are also less well-documented, and don't have code examples. There are also a lot of utility functions for conveniently working with the streams and transforming them which are lacking. Use [`n0-future`](https://docs.rs/n0-future/latest/n0_future/index.html) to work with them, that is what Jacquard uses internally as much as possible.\
2424+>I would also note the same for the repository crate until I've had more third parties test it.
23252426### Changelog
2527
+1-1
crates/jacquard-common/src/types.rs
···4747pub const DISALLOWED_TLDS: &[&str] = &[
4848 ".local",
4949 ".arpa",
5050- ".invalid",
5050+ ".invalid", // NOTE: if someone has a screwed up handle, this is what's returned
5151 ".localhost",
5252 ".internal",
5353 ".example",
+15-1
crates/jacquard-common/src/types/handle.rs
···5858 SmolStr::new_static("invalid"),
5959 ))
6060 } else if ends_with(stripped, DISALLOWED_TLDS) {
6161- Err(AtStrError::disallowed("handle", stripped, DISALLOWED_TLDS))
6161+ // speicifically pass this through as it is returned in instances where someone
6262+ // has screwed up their handle, and it's awkward to fail so early
6363+ if handle == "handle.invalid" {
6464+ Ok(Self(CowStr::Borrowed(stripped)))
6565+ } else {
6666+ Err(AtStrError::disallowed("handle", stripped, DISALLOWED_TLDS))
6767+ }
6268 } else {
6369 Ok(Self(CowStr::Borrowed(stripped)))
6470 }
7171+ }
7272+7373+ /// confirm that this is a (syntactically) valid handle (as we pass-through
7474+ /// "handle.invalid" during construction)
7575+ pub fn is_valid(&self) -> bool {
7676+ self.0.len() <= 253
7777+ && HANDLE_REGEX.is_match(&self.0)
7878+ && !ends_with(&self.0, DISALLOWED_TLDS)
6579 }
66806781 /// Fallible constructor, validates, takes ownership