Gate atproto-lexicon's resolver behind a `resolve` feature #662

Merged ngerakines.me
targeting main from lexicon-resolve-feature
Merged opened by and assigned to ngerakines.me
targeting main from lexicon-resolve-feature

Closes atproto-crates#22h3.

Validating a record against a schema pulled an HTTP client, an async runtime and a DNS resolver in behind it: reqwest was non-optional, and atproto-client and atproto-identity arrived with their defaults. Nothing in validation/ wants any of that — only resolve.rs, resolve_recursive.rs and the CLI reach the network.

resolve is spelled the way atproto-identity spells its own: on by default, implied by hickory-dns and clap, gating the two modules, the binary, the pub use reqwest re-export and the two error enums only those modules raise. atproto-identity is declared rather than inherited so its defaults can be off.

Every existing consumer is unaffected — the PDS, atpmcp and the CLI all build untouched. With --no-default-features, cargo tree shows 0 reqwest, 0 hickory-resolver.

Two things a reviewer should know #

tokio stays in the lean tree, through atproto-dasl, which validation/ needs for CIDs and whose CAR reader is async-first. That's the same edge lean_dependencies.rs already records for atproto-space. The issue's acceptance asked for no tokio; that can't hold without gating a different crate, so the two new test cases assert the edge by name instead of excusing it — gate DASL later and these tests ask to be updated.

resolve lists tokio, not dep:tokio, unlike atproto-identity. Hiding an optional dependency behind dep: removes the implicit feature of that name, and CI's release check passes -F tokio across the workspace (for atproto-attestation, which has an explicit one) — with dep:tokio, that check fails on this package rather than skipping it. There's a comment in the manifest saying so.

Verification #

cargo fmt --all; cargo clippy --workspace --all-targets -- -D warnings clean with default and --all-features; cargo test --workspace --no-fail-fast green; cargo check -p atproto-lexicon --no-default-features --all-targets passes; CI's release-feature check passes.

Not in scope #

Adding an atproto-space → atproto-lexicon dependency. This only makes it possible; the edge should wait for something atproto-space wants to validate inside the library.

Commits 0