Files
invoiceninja-sdk/Cargo.toml
T
awkawbandClaude Opus 5 ad9553516e Pin the Rust toolchain and declare an MSRV of 1.88
The dev shell tracked `stable.latest` and CI used `@stable`, so nothing
pinned a version and nothing declared a floor. A consumer on an older
toolchain hit a confusing error deep in a dependency rather than cargo
saying the version was too old, and a new stable release could turn a
lint into an unrelated red build.

- `rust-version = "1.88"` in Cargo.toml. The floor comes from the
  dependency graph, not this crate's code: reqwest pulls in url -> idna
  -> idna_adapter -> icu_*, and the icu crates require 1.88. Verified by
  running the full suite against 1.88, not inferred.
- flake.nix pins the dev toolchain to 1.99.1 and adds an `msrv` devShell,
  so the floor can be rechecked with
  `nix develop .#msrv --command cargo test`.
- CI pins the main job to the same 1.99.1 and adds a job building on
  1.88. Lint and format stay on the pinned toolchain only, since their
  output varies by release.

Note the tradeoff: with CI pinned, a future stable that breaks the build
will not be noticed until the pin moves. Worth adding a non-blocking
`stable` job if that matters.

CLAUDE.md records the three places that must agree when either version
moves, and how to recheck the floor after a dependency bump.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-23 18:46:32 -04:00

33 lines
1.3 KiB
TOML

[package]
name = "invoiceninjars"
version = "0.1.0"
edition = "2021"
# Set by the dependency graph rather than by this crate's own code: reqwest
# pulls in url -> idna -> idna_adapter -> icu_*, and the icu crates require
# 1.88. Verified by running the test suite against it; see the `msrv`
# devShell in flake.nix.
rust-version = "1.88"
description = "An async Rust client for the Invoice Ninja v5 API"
license = "MIT"
repository = "https://github.com/bryant/invoiceninjars"
[dependencies]
reqwest = { version = "0.12", default-features = false, features = ["json", "native-tls"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
# Already in the tree via reqwest's `url`; used to escape ids before they are
# interpolated into request paths.
percent-encoding = "2"
# Already in the tree as reqwest's runtime; only `time` is needed, for the
# sleep between retries.
tokio = { version = "1", features = ["time"] }
[dev-dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
# Used to assert that ListParams urlencodes the way reqwest will send it.
serde_urlencoded = "0.7"
# Loopback HTTP server for exercising the request plumbing (pagination, path
# escaping, headers, error mapping) without reaching the network.
wiremock = "0.6"