[workspace]
members = [".", "api-bones-tower", "api-bones-reqwest", "api-bones-progenitor", "api-bones-sdk-gen", "api-bones-test"]
resolver = "2"

[package]
name = "api-bones"
version = "4.6.0"
edition = "2024"
authors = ["Gregoire Salingue"]
license = "MIT"
description = "Opinionated REST API types: errors (RFC 9457), pagination, health checks, and more"
repository = "https://github.com/brefwiz/api-bones"
homepage = "https://github.com/brefwiz/api-bones"
documentation = "https://docs.rs/api-bones"
readme = "README.md"
keywords = ["rest", "http", "rfc9457", "api", "axum"]
categories = ["web-programming::http-server", "api-bindings", "no-std", "data-structures"]
rust-version = "1.85"

[features]
default = ["std", "serde", "uuid", "chrono", "validator"]
## Enables `std`-dependent types (`HashMap`, `std::error::Error`, etc.).
## Disabling this switches the crate to `#![no_std]` mode; pair with `alloc`
## for heap-allocated types (`String`, `Vec`, `Arc`).
std = ["alloc", "thiserror/std"]
## Enables heap-allocated types (`String`, `Vec`, `Arc`) in `no_std` contexts.
alloc = []
serde = ["dep:serde", "dep:serde_json", "uuid?/serde", "chrono?/serde", "std"]
## Enables `serde::base64_bytes` — `Vec<u8>` ↔ Base64 string serde helpers.
## Requires `alloc`.
base64 = ["alloc", "dep:base64"]
uuid = ["dep:uuid"]
chrono = ["dep:chrono", "utoipa?/chrono"]
http = ["dep:http", "alloc"]
axum = ["dep:axum", "http", "serde", "std"]
utoipa = ["dep:utoipa", "std"]
icalendar = ["dep:icalendar", "std"]
validator = ["dep:validator", "std"]
arbitrary = ["dep:arbitrary", "uuid?/arbitrary", "std"]
proptest = ["dep:proptest", "dep:proptest-derive", "std"]
fake = ["dep:fake", "dep:rand", "std", "uuid"]
schemars = ["dep:schemars", "schemars/uuid1", "schemars/chrono04", "std"]
## Enables `AuthScheme`, `AuthorizationHeader`, credential types, `Scope`, and `Permission`.
## Requires `alloc`. Enables Base64 decode for Basic auth.
auth = ["alloc", "base64", "dep:zeroize"]
## Enables HMAC-SHA256 signing for opaque cursors (`Cursor::encode_signed` / `decode_signed`).
## Requires `base64` and `alloc`.
hmac = ["base64", "alloc", "dep:hmac", "dep:sha2"]

[dependencies]
thiserror = { version = "2", default-features = false }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
uuid = { version = "1.23", features = ["v4"], optional = true }
chrono = { version = "0.4", optional = true }
arbitrary = { version = "1", features = ["derive"], optional = true }
proptest = { version = "1", optional = true }
proptest-derive = { version = "0.8", optional = true }
axum = { version = "0.8", optional = true }
http = { version = "1.0", optional = true }
utoipa = { version = "5", optional = true, features = ["uuid", "chrono"] }
icalendar = { version = "0.17", features = ["parser", "serde"], optional = true }
validator = { version = "0.20", features = ["derive"], optional = true }
fake = { version = "5", optional = true }
rand = { version = "0.10", optional = true }
schemars = { version = "1", optional = true }
base64 = { version = "0.22", default-features = false, features = ["alloc"], optional = true }
zeroize = { version = "1", features = ["derive"], optional = true }
hmac = { version = "0.13", optional = true }
sha2 = { version = "0.11", optional = true }

[lints.rust]
# Allow cfg(coverage) set by cargo-llvm-cov
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
# PLATFORM-008: Zero-Tolerance Security Linting
unsafe_code = { level = "deny", priority = -1 }
unsafe_op_in_unsafe_fn = { level = "deny", priority = -1 }
warnings = { level = "deny", priority = -1 }
unused_imports = { level = "deny", priority = -1 }
unused_variables = { level = "deny", priority = -1 }
dead_code = { level = "deny", priority = -1 }

[lints.clippy]
# PLATFORM-008: Tier 3 — pedantic linting at deny level
all = { level = "deny", priority = -1 }
pedantic = { level = "deny", priority = -1 }
nursery = { level = "warn", priority = -1 }
# Selective allow-list (justified below)
missing_errors_doc = "allow"   # serde/helper fns — noise without benefit
missing_panics_doc = "allow"   # no panic paths in public API
module_name_repetitions = "allow"    # e.g. ErrorCode, ApiError — idiomatic
missing_const_for_fn = "allow"       # nursery: not stable across MSRV, adds no safety value here
derive_partial_eq_without_eq = "allow" # nursery: serde types are rarely fully Eq-hashable
option_if_let_else = "allow"         # nursery: map_or_else is less readable in match-heavy code

[dev-dependencies]
mockito = "1.7.2"
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread", "net"] }

[[example]]
name = "query_builder"
required-features = ["serde"]

[[example]]
name = "axum_error_handling"
required-features = ["axum"]

[[example]]
name = "problem_json"
required-features = ["axum"]

[[example]]
name = "axum_extractors_and_ratelimit"
required-features = ["axum"]

[[example]]
name = "audit"
required-features = ["uuid", "chrono"]

[[example]]
name = "bulk_operations"

[[example]]
name = "error_handling"
required-features = ["uuid", "std", "serde"]

[[example]]
name = "etag"

[[example]]
name = "hateoas_links"

[[example]]
name = "health_check"

[[example]]
name = "pagination"

[[example]]
name = "query_params"

[[example]]
name = "rate_limit"

[[example]]
name = "response_envelope"
required-features = ["uuid", "serde"]

[[example]]
name = "slug"

[[example]]
name = "error_construction"
required-features = ["uuid", "std", "serde"]

[[example]]
name = "bulk_envelope"

[[example]]
name = "cursor_hmac"
required-features = ["base64"]

[[example]]
name = "auth_flow"
required-features = ["auth"]

[[example]]
name = "axum_core_extractors"
required-features = ["axum"]

[[example]]
name = "cache_control"

[[example]]
name = "etag_conditional"

[[example]]
name = "range_headers"

[[example]]
name = "trace_context"
required-features = ["uuid"]

[[example]]
name = "org_context"
required-features = ["uuid"]

[[example]]
name = "header_parser"
required-features = ["http"]
