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
|
||||
|
||||
- **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
|
||||
|
||||
Generated
+1
-1
@@ -528,7 +528,7 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "invoiceninjars"
|
||||
name = "invoiceninja-sdk"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<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 {
|
||||
Ok(created) => {
|
||||
println!(" created {name}");
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
+2
-2
@@ -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(),
|
||||
|
||||
@@ -104,7 +104,7 @@ impl ListParams {
|
||||
/// not cover.
|
||||
///
|
||||
/// ```
|
||||
/// use invoiceninjars::models::ListParams;
|
||||
/// use invoiceninja_sdk::models::ListParams;
|
||||
///
|
||||
/// let params = ListParams::new()
|
||||
/// .per_page(100)
|
||||
|
||||
+1
-1
@@ -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");
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user