diff --git a/CHANGELOG.md b/CHANGELOG.md index a32bdfd..73fb957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,6 +112,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **The crate is renamed from `invoiceninjars` to `invoiceninja-sdk`**, to + match the repository it has always lived in + (`gitea.awkawb.cloud/awkawb/invoiceninja-sdk`). Depend on it as + `invoiceninja-sdk` in `Cargo.toml`, and import it as `invoiceninja_sdk` + (Cargo lowercases a package name's hyphens to underscores for the crate + identifier) — every `use invoiceninjars::...` becomes + `use invoiceninja_sdk::...`. Not yet published to crates.io, so this + lands before the name was ever claimed there. - `statics`, `search`, and `health_check` return concrete types instead of being generic over `T: DeserializeOwned`. - `send_email` now unwraps the `data` envelope, so `T` is the entity diff --git a/Cargo.lock b/Cargo.lock index 85398e6..9dd101a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -528,7 +528,7 @@ dependencies = [ ] [[package]] -name = "invoiceninjars" +name = "invoiceninja-sdk" version = "0.1.0" dependencies = [ "percent-encoding", diff --git a/Cargo.toml b/Cargo.toml index 0ff9fe1..fc3f714 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "invoiceninjars" +name = "invoiceninja-sdk" version = "0.1.0" edition = "2021" # Set by the dependency graph rather than by this crate's own code: reqwest diff --git a/GOALS.md b/GOALS.md index 3ee51e9..bd58565 100644 --- a/GOALS.md +++ b/GOALS.md @@ -90,7 +90,7 @@ Invoice Ninja account to contribute. ask "what does this endpoint actually return", which matters here because the e-invoicing and integration methods are typed as `serde_json::Value` and were verified against mocks rather than a live - service. It belongs in a sibling crate (`invoiceninjars-cli`) in a + service. It belongs in a sibling crate (`invoiceninja-sdk-cli`) in a workspace, not in this one, for three reasons: - *Dependencies.* Every entry in `Cargo.toml` is there because the library @@ -106,7 +106,7 @@ Invoice Ninja account to contribute. - *Versioning.* Pre-1.0 this crate tells callers to pin an exact version and expect breaking changes in minor releases. A CLI's flags are a compatibility surface too, and one version number would force the two to - move in lockstep. `cargo install invoiceninjars` silently needing + move in lockstep. `cargo install invoiceninja-sdk` silently needing `--features cli` is a smaller version of the same problem. For ad-hoc probing, `examples/` already covers it and costs nothing: diff --git a/README.md b/README.md index eb6754b..7fa908f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# invoiceninjars +# invoiceninja-sdk An async Rust client for the [Invoice Ninja](https://www.invoiceninja.com/) v5 API. @@ -33,7 +33,7 @@ nix develop .#msrv --command cargo test ## Usage ```rust -use invoiceninjars::{InvoiceNinjaClient, models::ListParams}; +use invoiceninja_sdk::{InvoiceNinjaClient, models::ListParams}; // Hosted app: let client = InvoiceNinjaClient::hosted(std::env::var("IN_API_TOKEN")?)?; @@ -75,7 +75,7 @@ with exponential backoff. Both are configurable: ```rust use std::time::Duration; -use invoiceninjars::RetryPolicy; +use invoiceninja_sdk::RetryPolicy; let client = InvoiceNinjaClient::hosted(token)? .with_timeout(Duration::from_secs(300)) @@ -164,7 +164,7 @@ only way the API creates one. Sixteen resources support it, as `upload_client`, `upload_invoice`, `upload_expense`, and so on: ```rust -use invoiceninjars::FileUpload; +use invoiceninja_sdk::FileUpload; let receipt = FileUpload::new("receipt.pdf", std::fs::read("receipt.pdf")?) .mime("application/pdf"); diff --git a/examples/list_clients.rs b/examples/list_clients.rs index e1aa925..d01d16e 100644 --- a/examples/list_clients.rs +++ b/examples/list_clients.rs @@ -1,8 +1,8 @@ -use invoiceninjars::models::ListParams; -use invoiceninjars::InvoiceNinjaClient; +use invoiceninja_sdk::models::ListParams; +use invoiceninja_sdk::InvoiceNinjaClient; #[tokio::main] -async fn main() -> invoiceninjars::Result<()> { +async fn main() -> invoiceninja_sdk::Result<()> { let base_url = std::env::var("IN_BASE_URL").unwrap_or_else(|_| "https://invoicing.co/api/v1".into()); let token = std::env::var("IN_API_TOKEN").expect("set IN_API_TOKEN"); diff --git a/examples/seed_sample_data.rs b/examples/seed_sample_data.rs index e2dc698..e947822 100644 --- a/examples/seed_sample_data.rs +++ b/examples/seed_sample_data.rs @@ -18,7 +18,7 @@ use std::future::Future; use std::process::ExitCode; -use invoiceninjars::{Error, InvoiceNinjaClient}; +use invoiceninja_sdk::{Error, InvoiceNinjaClient}; use serde::de::DeserializeOwned; use serde_json::{json, Value}; @@ -34,7 +34,7 @@ fn describe(error: &Error) -> String { } /// Runs one creation, reporting the outcome and returning the new id. -async fn step(name: &str, call: impl Future>) -> Option { +async fn step(name: &str, call: impl Future>) -> Option { match call.await { Ok(created) => { println!(" created {name}"); diff --git a/examples/smoke_test.rs b/examples/smoke_test.rs index 3b97ccc..eae647c 100644 --- a/examples/smoke_test.rs +++ b/examples/smoke_test.rs @@ -37,10 +37,10 @@ use std::fmt::Display; use std::process::ExitCode; use std::time::{SystemTime, UNIX_EPOCH}; -use invoiceninjars::models::{ +use invoiceninja_sdk::models::{ Client, ListParams, Location, PurchaseOrder, RecurringInvoice, Vendor, Webhook, }; -use invoiceninjars::{Error, FileUpload, InvoiceNinjaClient}; +use invoiceninja_sdk::{Error, FileUpload, InvoiceNinjaClient}; use serde::Serialize; use serde_json::{json, Value}; diff --git a/flake.nix b/flake.nix index e2fd783..5af88ef 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "invoiceninjars: a Rust client for the Invoice Ninja v5 API"; + description = "invoiceninja-sdk: a Rust client for the Invoice Ninja v5 API"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; @@ -69,7 +69,7 @@ # the "no credentials needed" property in CLAUDE.md) — just not as # a source of an installable artifact. packages.default = rustPlatform.buildRustPackage { - pname = "invoiceninjars"; + pname = "invoiceninja-sdk"; version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version; src = self; cargoLock.lockFile = ./Cargo.lock; diff --git a/src/client.rs b/src/client.rs index 940c7f3..0e49f70 100644 --- a/src/client.rs +++ b/src/client.rs @@ -219,8 +219,8 @@ impl InvoiceNinjaClient { /// It used to be refused locally with a misleading `InvalidToken`. /// /// ```no_run - /// # fn main() -> invoiceninjars::Result<()> { - /// use invoiceninjars::InvoiceNinjaClient; + /// # fn main() -> invoiceninja_sdk::Result<()> { + /// use invoiceninja_sdk::InvoiceNinjaClient; /// /// let client = InvoiceNinjaClient::hosted(std::env::var("IN_API_TOKEN").unwrap())? /// .with_api_password(std::env::var("IN_API_PASSWORD").unwrap())?; @@ -1367,8 +1367,8 @@ impl InvoiceNinjaClient { /// for — [`Invoice`], [`Quote`], [`Credit`], or [`PurchaseOrder`]: /// /// ```no_run - /// # async fn run(client: &invoiceninjars::InvoiceNinjaClient) -> invoiceninjars::Result<()> { - /// use invoiceninjars::models::Invoice; + /// # async fn run(client: &invoiceninja_sdk::InvoiceNinjaClient) -> invoiceninja_sdk::Result<()> { + /// use invoiceninja_sdk::models::Invoice; /// use serde_json::json; /// /// let invoice: Invoice = client diff --git a/src/lib.rs b/src/lib.rs index b3c64a6..b2291ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ //! An async Rust client for the [Invoice Ninja](https://www.invoiceninja.com/) v5 API. //! //! ```no_run -//! use invoiceninjars::{InvoiceNinjaClient, models::ListParams}; +//! use invoiceninja_sdk::{InvoiceNinjaClient, models::ListParams}; //! -//! # async fn run() -> invoiceninjars::Result<()> { +//! # async fn run() -> invoiceninja_sdk::Result<()> { //! let client = InvoiceNinjaClient::new( //! "https://invoicing.co/api/v1", //! std::env::var("IN_API_TOKEN").unwrap(), diff --git a/src/models/common.rs b/src/models/common.rs index 4545e12..7f07744 100644 --- a/src/models/common.rs +++ b/src/models/common.rs @@ -104,7 +104,7 @@ impl ListParams { /// not cover. /// /// ``` - /// use invoiceninjars::models::ListParams; + /// use invoiceninja_sdk::models::ListParams; /// /// let params = ListParams::new() /// .per_page(100) diff --git a/src/upload.rs b/src/upload.rs index 8becba6..38fe429 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -11,7 +11,7 @@ use crate::error::{Error, Result}; /// question in `GOALS.md`. /// /// ``` -/// use invoiceninjars::FileUpload; +/// use invoiceninja_sdk::FileUpload; /// /// let file = FileUpload::new("receipt.pdf", b"%PDF-1.4 ...".to_vec()) /// .mime("application/pdf"); diff --git a/tests/client_requests.rs b/tests/client_requests.rs index 13217b5..58ac66c 100644 --- a/tests/client_requests.rs +++ b/tests/client_requests.rs @@ -8,7 +8,7 @@ use std::time::Duration; -use invoiceninjars::{models::ListParams, Error, InvoiceNinjaClient}; +use invoiceninja_sdk::{models::ListParams, Error, InvoiceNinjaClient}; use serde_json::json; use wiremock::matchers::{header, method, path, query_param}; use wiremock::{Mock, MockServer, ResponseTemplate}; @@ -547,7 +547,7 @@ async fn ping_accepts_an_empty_success_body() { // --- retry and backoff -------------------------------------------------- -use invoiceninjars::RetryPolicy; +use invoiceninja_sdk::RetryPolicy; /// Fast policy so the tests do not actually sleep for seconds. fn quick_retry() -> RetryPolicy { @@ -751,7 +751,7 @@ async fn retried_requests_keep_their_body_and_headers() { .mount(&server) .await; - let body = invoiceninjars::models::Client { + let body = invoiceninja_sdk::models::Client { name: "Acme".into(), ..Default::default() }; @@ -965,7 +965,7 @@ async fn send_email_unwraps_the_data_envelope() { .mount(&server) .await; - let invoice: invoiceninjars::models::Invoice = client(&server) + let invoice: invoiceninja_sdk::models::Invoice = client(&server) .send_email(&json!({ "entity": "invoice", "entity_id": "inv1" })) .await .expect("should return the refreshed entity"); @@ -1179,7 +1179,7 @@ async fn no_budget_means_only_max_retries_bounds_the_call() { // --- document uploads --------------------------------------------------- -use invoiceninjars::FileUpload; +use invoiceninja_sdk::FileUpload; fn pdf(name: &str) -> FileUpload { FileUpload::new(name, b"%PDF-1.4 fake".to_vec()).mime("application/pdf") diff --git a/tests/decode_tolerance.rs b/tests/decode_tolerance.rs index b343bc3..942cb80 100644 --- a/tests/decode_tolerance.rs +++ b/tests/decode_tolerance.rs @@ -11,7 +11,7 @@ //! A wrong *type* is deliberately not covered: that is meant to be a hard //! error, so it is not something to absorb. -use invoiceninjars::models::*; +use invoiceninja_sdk::models::*; use serde::{de::DeserializeOwned, Serialize}; use serde_json::Value; diff --git a/tests/model_roundtrip.rs b/tests/model_roundtrip.rs index 40e343f..a3636a8 100644 --- a/tests/model_roundtrip.rs +++ b/tests/model_roundtrip.rs @@ -1,4 +1,4 @@ -use invoiceninjars::models::{ +use invoiceninja_sdk::models::{ BankIntegration, BankTransaction, BankTransactionRule, BulkRequest, Client, ClientGatewayToken, Company, CompanyGateway, CompanyToken, Credit, Design, Document, Expense, ExpenseCategory, GroupSetting, HealthCheck, Invoice, ListParams, ListResponse, Location, PaymentTerm, Project, diff --git a/tests/real_shapes.rs b/tests/real_shapes.rs index b024382..4b77a20 100644 --- a/tests/real_shapes.rs +++ b/tests/real_shapes.rs @@ -15,7 +15,7 @@ use std::collections::BTreeMap; use std::fs; use std::path::{Path, PathBuf}; -use invoiceninjars::models::*; +use invoiceninja_sdk::models::*; use serde::{de::DeserializeOwned, Serialize}; use serde_json::Value;