Rename the crate from invoiceninjars to invoiceninja-sdk
The package name has never matched the repository it lives in (gitea.awkawb.cloud/awkawb/invoiceninja-sdk, mirrored to github.com/awkawb1/invoiceninja-sdk) — both pointed at `invoiceninja-sdk` while `Cargo.toml` declared `invoiceninjars`. Lines everything up on the name the repo has always used. Cargo derives the crate's Rust identifier from the package name by lowercasing hyphens to underscores, so every `use invoiceninjars::...` becomes `use invoiceninja_sdk::...` — in doctests across `src/`, the four examples, all four integration test files, and `README.md`. `Cargo.lock`'s own self-entry picked up the new name on the next `cargo check`, which is also when the rename gets its real check: every doctest and every test file has to resolve the new path to compile at all, not just the ones a grep happens to catch. `flake.nix`'s `pname` and description follow, so `nix build` produces `invoiceninja-sdk-0.1.0.drv` rather than a name that no longer matches anything. `GOALS.md`'s two mentions — the hypothetical CLI's name and the `cargo install` example — follow too, for the same reason. Verified clean on both the dev toolchain and the 1.88 MSRV shell: full test suite (209 tests), clippy, fmt, and `nix build`/`nix flake check`. Not yet published to crates.io (checked: the name 404s there), so this lands before the old name was ever claimed — no one's `Cargo.toml` breaks today, but it's recorded as a Changed entry since `GOALS.md` asks for breaking changes to be legible in the changelog rather than discovered at compile time, and the crate is reachable as a git dependency regardless of crates.io status. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Changed
|
### 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
|
- `statics`, `search`, and `health_check` return concrete types instead of
|
||||||
being generic over `T: DeserializeOwned`.
|
being generic over `T: DeserializeOwned`.
|
||||||
- `send_email` now unwraps the `data` envelope, so `T` is the entity
|
- `send_email` now unwraps the `data` envelope, so `T` is the entity
|
||||||
|
|||||||
Generated
+1
-1
@@ -528,7 +528,7 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "invoiceninjars"
|
name = "invoiceninja-sdk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "invoiceninjars"
|
name = "invoiceninja-sdk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
# Set by the dependency graph rather than by this crate's own code: reqwest
|
# Set by the dependency graph rather than by this crate's own code: reqwest
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ Invoice Ninja account to contribute.
|
|||||||
ask "what does this endpoint actually return", which matters here because
|
ask "what does this endpoint actually return", which matters here because
|
||||||
the e-invoicing and integration methods are typed as
|
the e-invoicing and integration methods are typed as
|
||||||
`serde_json::Value` and were verified against mocks rather than a live
|
`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:
|
workspace, not in this one, for three reasons:
|
||||||
|
|
||||||
- *Dependencies.* Every entry in `Cargo.toml` is there because the library
|
- *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
|
- *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
|
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
|
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.
|
`--features cli` is a smaller version of the same problem.
|
||||||
|
|
||||||
For ad-hoc probing, `examples/` already covers it and costs nothing:
|
For ad-hoc probing, `examples/` already covers it and costs nothing:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# invoiceninjars
|
# invoiceninja-sdk
|
||||||
|
|
||||||
An async Rust client for the [Invoice Ninja](https://www.invoiceninja.com/) v5 API.
|
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
|
## Usage
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use invoiceninjars::{InvoiceNinjaClient, models::ListParams};
|
use invoiceninja_sdk::{InvoiceNinjaClient, models::ListParams};
|
||||||
|
|
||||||
// Hosted app:
|
// Hosted app:
|
||||||
let client = InvoiceNinjaClient::hosted(std::env::var("IN_API_TOKEN")?)?;
|
let client = InvoiceNinjaClient::hosted(std::env::var("IN_API_TOKEN")?)?;
|
||||||
@@ -75,7 +75,7 @@ with exponential backoff. Both are configurable:
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use invoiceninjars::RetryPolicy;
|
use invoiceninja_sdk::RetryPolicy;
|
||||||
|
|
||||||
let client = InvoiceNinjaClient::hosted(token)?
|
let client = InvoiceNinjaClient::hosted(token)?
|
||||||
.with_timeout(Duration::from_secs(300))
|
.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:
|
`upload_client`, `upload_invoice`, `upload_expense`, and so on:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use invoiceninjars::FileUpload;
|
use invoiceninja_sdk::FileUpload;
|
||||||
|
|
||||||
let receipt = FileUpload::new("receipt.pdf", std::fs::read("receipt.pdf")?)
|
let receipt = FileUpload::new("receipt.pdf", std::fs::read("receipt.pdf")?)
|
||||||
.mime("application/pdf");
|
.mime("application/pdf");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use invoiceninjars::models::ListParams;
|
use invoiceninja_sdk::models::ListParams;
|
||||||
use invoiceninjars::InvoiceNinjaClient;
|
use invoiceninja_sdk::InvoiceNinjaClient;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> invoiceninjars::Result<()> {
|
async fn main() -> invoiceninja_sdk::Result<()> {
|
||||||
let base_url =
|
let base_url =
|
||||||
std::env::var("IN_BASE_URL").unwrap_or_else(|_| "https://invoicing.co/api/v1".into());
|
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");
|
let token = std::env::var("IN_API_TOKEN").expect("set IN_API_TOKEN");
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
use invoiceninjars::{Error, InvoiceNinjaClient};
|
use invoiceninja_sdk::{Error, InvoiceNinjaClient};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde_json::{json, Value};
|
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.
|
/// Runs one creation, reporting the outcome and returning the new id.
|
||||||
async fn step<T>(name: &str, call: impl Future<Output = invoiceninjars::Result<T>>) -> Option<T> {
|
async fn step<T>(name: &str, call: impl Future<Output = invoiceninja_sdk::Result<T>>) -> Option<T> {
|
||||||
match call.await {
|
match call.await {
|
||||||
Ok(created) => {
|
Ok(created) => {
|
||||||
println!(" created {name}");
|
println!(" created {name}");
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ use std::fmt::Display;
|
|||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use invoiceninjars::models::{
|
use invoiceninja_sdk::models::{
|
||||||
Client, ListParams, Location, PurchaseOrder, RecurringInvoice, Vendor, Webhook,
|
Client, ListParams, Location, PurchaseOrder, RecurringInvoice, Vendor, Webhook,
|
||||||
};
|
};
|
||||||
use invoiceninjars::{Error, FileUpload, InvoiceNinjaClient};
|
use invoiceninja_sdk::{Error, FileUpload, InvoiceNinjaClient};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
|||||||
@@ -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 = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
# the "no credentials needed" property in CLAUDE.md) — just not as
|
# the "no credentials needed" property in CLAUDE.md) — just not as
|
||||||
# a source of an installable artifact.
|
# a source of an installable artifact.
|
||||||
packages.default = rustPlatform.buildRustPackage {
|
packages.default = rustPlatform.buildRustPackage {
|
||||||
pname = "invoiceninjars";
|
pname = "invoiceninja-sdk";
|
||||||
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
|
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
|
||||||
src = self;
|
src = self;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
|
|||||||
+4
-4
@@ -219,8 +219,8 @@ impl InvoiceNinjaClient {
|
|||||||
/// It used to be refused locally with a misleading `InvalidToken`.
|
/// It used to be refused locally with a misleading `InvalidToken`.
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # fn main() -> invoiceninjars::Result<()> {
|
/// # fn main() -> invoiceninja_sdk::Result<()> {
|
||||||
/// use invoiceninjars::InvoiceNinjaClient;
|
/// use invoiceninja_sdk::InvoiceNinjaClient;
|
||||||
///
|
///
|
||||||
/// let client = InvoiceNinjaClient::hosted(std::env::var("IN_API_TOKEN").unwrap())?
|
/// let client = InvoiceNinjaClient::hosted(std::env::var("IN_API_TOKEN").unwrap())?
|
||||||
/// .with_api_password(std::env::var("IN_API_PASSWORD").unwrap())?;
|
/// .with_api_password(std::env::var("IN_API_PASSWORD").unwrap())?;
|
||||||
@@ -1367,8 +1367,8 @@ impl InvoiceNinjaClient {
|
|||||||
/// for — [`Invoice`], [`Quote`], [`Credit`], or [`PurchaseOrder`]:
|
/// for — [`Invoice`], [`Quote`], [`Credit`], or [`PurchaseOrder`]:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # async fn run(client: &invoiceninjars::InvoiceNinjaClient) -> invoiceninjars::Result<()> {
|
/// # async fn run(client: &invoiceninja_sdk::InvoiceNinjaClient) -> invoiceninja_sdk::Result<()> {
|
||||||
/// use invoiceninjars::models::Invoice;
|
/// use invoiceninja_sdk::models::Invoice;
|
||||||
/// use serde_json::json;
|
/// use serde_json::json;
|
||||||
///
|
///
|
||||||
/// let invoice: Invoice = client
|
/// let invoice: Invoice = client
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
//! An async Rust client for the [Invoice Ninja](https://www.invoiceninja.com/) v5 API.
|
//! An async Rust client for the [Invoice Ninja](https://www.invoiceninja.com/) v5 API.
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```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(
|
//! let client = InvoiceNinjaClient::new(
|
||||||
//! "https://invoicing.co/api/v1",
|
//! "https://invoicing.co/api/v1",
|
||||||
//! std::env::var("IN_API_TOKEN").unwrap(),
|
//! std::env::var("IN_API_TOKEN").unwrap(),
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ impl ListParams {
|
|||||||
/// not cover.
|
/// not cover.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use invoiceninjars::models::ListParams;
|
/// use invoiceninja_sdk::models::ListParams;
|
||||||
///
|
///
|
||||||
/// let params = ListParams::new()
|
/// let params = ListParams::new()
|
||||||
/// .per_page(100)
|
/// .per_page(100)
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ use crate::error::{Error, Result};
|
|||||||
/// question in `GOALS.md`.
|
/// question in `GOALS.md`.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use invoiceninjars::FileUpload;
|
/// use invoiceninja_sdk::FileUpload;
|
||||||
///
|
///
|
||||||
/// let file = FileUpload::new("receipt.pdf", b"%PDF-1.4 ...".to_vec())
|
/// let file = FileUpload::new("receipt.pdf", b"%PDF-1.4 ...".to_vec())
|
||||||
/// .mime("application/pdf");
|
/// .mime("application/pdf");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use invoiceninjars::{models::ListParams, Error, InvoiceNinjaClient};
|
use invoiceninja_sdk::{models::ListParams, Error, InvoiceNinjaClient};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use wiremock::matchers::{header, method, path, query_param};
|
use wiremock::matchers::{header, method, path, query_param};
|
||||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
use wiremock::{Mock, MockServer, ResponseTemplate};
|
||||||
@@ -547,7 +547,7 @@ async fn ping_accepts_an_empty_success_body() {
|
|||||||
|
|
||||||
// --- retry and backoff --------------------------------------------------
|
// --- retry and backoff --------------------------------------------------
|
||||||
|
|
||||||
use invoiceninjars::RetryPolicy;
|
use invoiceninja_sdk::RetryPolicy;
|
||||||
|
|
||||||
/// Fast policy so the tests do not actually sleep for seconds.
|
/// Fast policy so the tests do not actually sleep for seconds.
|
||||||
fn quick_retry() -> RetryPolicy {
|
fn quick_retry() -> RetryPolicy {
|
||||||
@@ -751,7 +751,7 @@ async fn retried_requests_keep_their_body_and_headers() {
|
|||||||
.mount(&server)
|
.mount(&server)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let body = invoiceninjars::models::Client {
|
let body = invoiceninja_sdk::models::Client {
|
||||||
name: "Acme".into(),
|
name: "Acme".into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@@ -965,7 +965,7 @@ async fn send_email_unwraps_the_data_envelope() {
|
|||||||
.mount(&server)
|
.mount(&server)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let invoice: invoiceninjars::models::Invoice = client(&server)
|
let invoice: invoiceninja_sdk::models::Invoice = client(&server)
|
||||||
.send_email(&json!({ "entity": "invoice", "entity_id": "inv1" }))
|
.send_email(&json!({ "entity": "invoice", "entity_id": "inv1" }))
|
||||||
.await
|
.await
|
||||||
.expect("should return the refreshed entity");
|
.expect("should return the refreshed entity");
|
||||||
@@ -1179,7 +1179,7 @@ async fn no_budget_means_only_max_retries_bounds_the_call() {
|
|||||||
|
|
||||||
// --- document uploads ---------------------------------------------------
|
// --- document uploads ---------------------------------------------------
|
||||||
|
|
||||||
use invoiceninjars::FileUpload;
|
use invoiceninja_sdk::FileUpload;
|
||||||
|
|
||||||
fn pdf(name: &str) -> FileUpload {
|
fn pdf(name: &str) -> FileUpload {
|
||||||
FileUpload::new(name, b"%PDF-1.4 fake".to_vec()).mime("application/pdf")
|
FileUpload::new(name, b"%PDF-1.4 fake".to_vec()).mime("application/pdf")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
//! A wrong *type* is deliberately not covered: that is meant to be a hard
|
//! A wrong *type* is deliberately not covered: that is meant to be a hard
|
||||||
//! error, so it is not something to absorb.
|
//! error, so it is not something to absorb.
|
||||||
|
|
||||||
use invoiceninjars::models::*;
|
use invoiceninja_sdk::models::*;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use invoiceninjars::models::{
|
use invoiceninja_sdk::models::{
|
||||||
BankIntegration, BankTransaction, BankTransactionRule, BulkRequest, Client, ClientGatewayToken,
|
BankIntegration, BankTransaction, BankTransactionRule, BulkRequest, Client, ClientGatewayToken,
|
||||||
Company, CompanyGateway, CompanyToken, Credit, Design, Document, Expense, ExpenseCategory,
|
Company, CompanyGateway, CompanyToken, Credit, Design, Document, Expense, ExpenseCategory,
|
||||||
GroupSetting, HealthCheck, Invoice, ListParams, ListResponse, Location, PaymentTerm, Project,
|
GroupSetting, HealthCheck, Invoice, ListParams, ListResponse, Location, PaymentTerm, Project,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use std::collections::BTreeMap;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use invoiceninjars::models::*;
|
use invoiceninja_sdk::models::*;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user