# Changelog

All notable changes to the `cnb` crate are documented here. The format is
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.0] — 2026-04-30

### Summary

**Full rewrite based on the latest CNB OpenAPI specification.**
The 0.2.0 release re-generates every resource module from the upstream
`https://api.cnb.cool/swagger.json` (179 paths / 241 operations / 271 DTOs)
and replaces the hand-rolled runtime with a typed, production-grade core.

This is a **breaking** release: every public API has changed shape. There is
no compatibility shim — please follow the migration guide below.

### Highlights

- 🔐 **Bearer-token authentication** via `ApiClient::builder().token(...)`
  with automatic fall-back to the `CNB_TOKEN` environment variable.
- 🧱 **Typed request bodies & responses**: all 271 DTOs from the spec are
  re-generated as `serde` structs. `serde_json::Value` survives only for
  endpoints whose schema the upstream spec doesn't pin.
- 🧰 **Builder-based query parameters**: long sequences of `Option<...>` are
  gone. Each operation with query params now exposes a `XxxQuery` builder.
- 💥 **Structured error type**:
  ```rust
  ApiError::Http { status, body, code, message, request_id }
  ```
  preserves the raw response body, parses common envelope fields, and
  surfaces `X-Request-Id` for support triage.
- 🔁 **Retries with back-off**: exponential back-off + jitter, only on
  idempotent verbs (GET/HEAD/PUT/DELETE/OPTIONS) and only for retryable
  errors (5xx, 408, 429, transport failures). Honours `Retry-After`.
- 🏷️ **Correct media type**: every request advertises
  `Accept: application/vnd.cnb.api+json` automatically.
- 🧪 **`wiremock`-based integration tests** covering auth, error envelopes,
  retries, `Retry-After`, default headers and resource happy-paths.
- 📊 **Optional `tracing` feature** emits structured spans per call (no
  bearer tokens are ever logged).
- 📈 **Optional `stream` feature** with a generic `paginate(...)` helper for
  CNB's `page` / `page_size` endpoints.
- 🚦 **Per-resource feature flags**: opt out of the resource modules you
  don't use to slash compile time. `default-features = false` strips the SDK
  to the bare minimum.
- 🛠️ **In-tree code generator** (`codegen/cnb-codegen`, not published)
  consumes the spec and writes `src/models/data.rs` plus 28 resource modules.

### Added

- `cnb::ApiClient::builder()` returning a [`ClientBuilder`] with
  `token`, `no_token`, `base_url`, `timeout`, `retry`, `user_agent`,
  `default_header`.
- `cnb::ApiError::Http { status, body, code, message, request_id }`,
  `ApiError::EnvVar`, plus `ApiError::status()` and `ApiError::is_retryable()`.
- `cnb::RetryConfig` with `max_attempts` / `base_delay` / `max_delay`.
- `cnb::pagination::paginate(...)` (under the `stream` feature).
- `cnb::http::HttpInner` for advanced users.
- New resource modules: `members`, `registries`, `rank`, `search`, `charge`,
  `repo_code_issue`.
- Generated query-parameter builder structs (`<OperationId>Query`) per resource.
- 7 runnable examples under `examples/`.
- 5 `wiremock` integration tests under `tests/`.
- GitHub Actions workflow (`.github/workflows/ci.yml`) and CNB-native CI
  (`.cnb.yml`).
- `rust-toolchain.toml` with `stable` and an MSRV declaration of `1.75`.
- Per-resource Cargo features (`activities`, `ai`, …, `workspace`) and
  TLS-backend toggles (`rustls-tls` default, `native-tls` opt-in).

### Changed (BREAKING)

- **Method names** now follow the OpenAPI `operationId` (snake-cased) rather
  than `<verb>_<path>`. This produces stable, readable names but renames
  every public method. See the migration guide below for the most common
  changes.
- **Method signatures**: query parameters are bundled into a `XxxQuery`
  builder instead of being trailing `Option<...>`. The builder is passed by
  reference (`&query`).
- **Request bodies** are passed by reference to a typed DTO
  (`&models::CreateRepoReq`) instead of `serde_json::Value`.
- **Response types** are typed (`models::Repos4User`,
  `Vec<models::Branch>`, …) wherever the spec provides a schema.
- **Construction**: `ApiClient::new("https://api.cnb.cool".to_string())`
  is replaced by `ApiClient::new()?` (uses default base URL + `CNB_TOKEN`)
  or `ApiClient::builder().build()?`.
- **Error model**: `ApiError::HttpError(u16)` is replaced by the much
  richer `ApiError::Http { ... }` struct variant.
- **Dependency upgrades**: `reqwest 0.11 → 0.12`,
  `anyhow → thiserror`. The transitive dependency tree is now smaller and
  TLS is `rustls` by default.
- `tokio` features were trimmed from `full` to `time` only (binaries that
  used `cnb` indirectly to pull in tokio's macros / runtime should add the
  features they need themselves).
- The `with_auth(...)` placeholder methods on every resource client have
  been removed — auth is configured at the `ClientBuilder` level.

### Removed

- `collaborators.rs`, `contributors.rs`, `repo_contributor.rs` orphan
  modules (re-generated automatically when the spec lists them).
- `anyhow` dependency.
- Per-method `with_auth(token)` placeholders.

### Migration guide (0.1.x → 0.2.0)

1. **Construct the client through the builder.**

   ```rust
   // 0.1.x
   let client = cnb::ApiClient::new("https://api.cnb.cool".to_string());

   // 0.2.0
   let client = cnb::ApiClient::new()?;                  // CNB_TOKEN env
   // or
   let client = cnb::ApiClient::builder()
       .token("ghp_xxx")
       .build()?;
   ```

2. **Rename methods to the new operationId-based scheme.** Common examples
   (full mapping is left to the rustdoc / IDE auto-complete — every method
   shows the original `METHOD path` in its doc comment):

   | 0.1.x                                   | 0.2.0                                          |
   | --------------------------------------- | ---------------------------------------------- |
   | `users().get_users_username(name)`      | `users().get_user_info_by_name(name, &q)`      |
   | `repositories().get_repo("o/r")`        | `repositories().get_by_id("o/r")`              |
   | `repositories().get_users_username_repos(...)` | `repositories().get_repos(&q)` (with builder) |
   | `issues().get_repo_issues(...)`         | `issues().list_issues(repo, &q)`               |
   | `issues().post_repo_issues(repo, body)` | `issues().create_issue(repo, &body)`           |
   | `git().get_repo_git_branches(...)`      | `git().list_branches(repo, &q)`                |
   | `releases().get_repo_releases_latest(r)`| `releases().get_latest_release(r)`             |
   | `pulls().get_repo_pulls_number_files(...)` | (renamed; see rustdoc)                      |

3. **Replace inline `Option<i64>` query params with the builder.**

   ```rust
   // 0.1.x
   let repos = client.repositories()
       .get_users_username_repos(
           "octocat".into(),
           None, None, None, None, None,
           Some(1), Some(20), None, None,
       ).await?;

   // 0.2.0
   use cnb::repositories::GetReposQuery;
   let q = GetReposQuery::new().page(1i64).page_size(20i64);
   let repos = client.repositories().get_repos(&q).await?;
   ```

4. **Pass typed DTOs instead of `serde_json::json!(...)` for request bodies.**

   ```rust
   // 0.1.x
   client.issues().post_repo_issues(
       repo, serde_json::json!({ "title": "Bug", "body": "..." })
   ).await?;

   // 0.2.0
   use cnb::models::PostIssueForm;
   let body = PostIssueForm {
       title: Some("Bug".into()),
       body: Some("...".into()),
       ..Default::default()
   };
   client.issues().create_issue(repo, &body).await?;
   ```

5. **Match on the new error variant.**

   ```rust
   // 0.1.x
   Err(cnb::ApiError::HttpError(404)) => { ... }

   // 0.2.0
   Err(cnb::ApiError::Http { status: 404, request_id, .. }) => { ... }
   ```

6. **If you compiled with `default-features = true` and want to keep the
   slimmest dependency set**, you can now opt into `default-features = false`
   and pick only the resource features you need (`features = ["rustls-tls",
   "issues", "repositories"]`).

---

## [0.1.2] — earlier

The pre-rewrite generator emitted untyped, value-only methods. See git
history for details.
