## 0.3.19 (2026-07-26)

### Fixes

#### Support custom GraphQL root type names

Hive Router now reads `query`, `mutation`, and `subscription` root type names from the schema instead of assuming they are named `Query`, `Mutation`, and `Subscription`.

## 0.3.18 (2026-07-20)

### Fixes

#### Improve GraphQL operation validation

- **Faster validation (2-3x):** rules now share a single `OperationVisitor` pass over the operation document instead of each rule visiting it independently.
- **New `UniqueInputFieldNames` rule:** input object fields are now kept as a list rather than a map, so duplicate fields are no longer silently deduplicated before validation. A query like `{ field(input: { value: 1, value: 2 }) }` is now correctly rejected.
- **Fixed `VariablesInAllowedPosition`:** now accounts for default values on variables, field arguments, and input object fields. Nullable variables used in a non-null argument that defines a default are no longer incorrectly rejected.

## 0.3.17 (2026-06-30)

### Fixes

#### Fix: Traverse fragments linearly during cycle validation and inlining

GraphQL fragments can spread other fragments, e.g. `fragment A on T { ...B }`. When fragments form a long acyclic chain (A spreads B, B spreads C, and so on for thousands of links), we walked that chain with plain recursion. 

This change prevents the stack from being filled in such cases.

## 0.3.16 (2026-06-15)

### Features

#### Add at-least-once sampling for Usage Reporting

Hive Router now supports at-least-once sampling for Usage Reporting.

This feature is useful when you want to keep a low sampling rate, but still make sure all operations are visible in Hive at least once.

The first request for each unique key is always reported. Later requests for the same key follow the configured sampling `rate`.

Example configuration:

```yaml
telemetry:
  hive:
    usage_reporting:
      enabled: true
      sampling:
        rate: "10%" # 10% of operations will be reported
        at_least_once:
          key: # the combination of operation's name and body makes the request unique
            - operation_name
            - operation_body
          max_distinct_keys: 12000 # how many keys to track and hold in memory
```

Keys are tracked in memory, up to `max_distinct_keys` (default: `100_000`). Every key takes approximately 16 bytes of memory.

#### Apply usage-reporting excludes before sampling

Exclusion of Usage Reports is now evaluated before sampling. Excluded operations are dropped immediately and sampling is not affected.

## 0.3.15 (2026-06-13)

### Fixes

- Version bump and update `vrl` to latest

## 0.3.14 (2026-05-27)

### Fixes

#### Fix `VariablesInAllowedPosition` rejecting list-typed variables with a non-null default value

The router used to reject valid client queries that declared a list-typed variable with a non-null default value, for example:

```graphql
query Q($arg: [SomeEnum!] = SOME_VALUE) {
  field(arg: $arg)
}
```

with a `VariablesInAllowedPosition` validation error containing a malformed type:

```
Variable "$arg" of type "SomeEnum!!" used in position expecting type "[SomeEnum!]".
```

The rule used to compute the variable's effective type incorrectly when the variable was list-typed and had a non-null default value: it dropped the list wrapper and re-wrapped the inner element type in `NonNull`, producing the invalid `T!!` shape. Per [the spec](https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed), a non-null default value makes the variable usable in a non-null position; the variable's effective type should be `NonNull(var_type)`, not `NonNull(element_type)`. So for `[SomeEnum!]` with a non-null default, the effective type is now correctly `[SomeEnum!]!` (and the query is accepted).

## 0.3.13 (2026-05-26)

### Fixes

#### Remove dependency ntex from console-sdk

Other pkgs are released due to minor refactor and code relocation.

## 0.3.12 (2026-05-19)

### Fixes

#### Fix: pin `ntex` version to `3.7.2` to avoid regressions

This release pins `ntex` to `3.7.2` to avoid regressions, like the one reported in [#997](https://github.com/graphql-hive/router/issues/997). 

Users who builds their own router are impacted by this regression, due to the way Cargo handles unpinned dependencies.

## 0.3.11 (2026-05-17)

### Fixes

#### Implement Circuit Breaker for Subgraph Requests

This change introduces a circuit breaker mechanism for subgraph requests in the Hive Router. The circuit breaker will monitor the success and failure rates of requests to each subgraph and will prevent future requests if the failure rate exceeds a certain threshold. When the circuit breaker is opened, subsequent requests to that subgraph will fail immediately without attempting to send the request.

This implementation helps improve the resilience and stability of the Hive Router when dealing with unreliable subgraphs.

## 0.3.10 (2026-05-05)

### Features

#### Dynamic Exclusions

### Dynamic Exclusions in Hive Router

Hive Router now supports dynamic exclusions, allowing you to exclude specific requests from usage reporting based on custom logic. This feature is useful for scenarios where you want to skip telemetry for certain requests, such as health checks or specific endpoints.

The previous operation-name list format is still supported for backward compatibility.

#### Usage
```diff
- exclude: ['ExcludedOp']
+ exclude:
+   expression: '.request.operation.name == "ExcludedOp"'
```

Both of the following are valid and supported:

```yaml
## legacy format
exclude:
  - ExcludedOp

## dynamic expression format
exclude:
  expression: '.request.operation.name == "ExcludedOp"'
```

The details about expression context is documented in the [Hive Router documentation](https://the-guild.dev/graphql/hive/docs/router/configuration/expressions).

### Dynamic Exclusions in Apollo Router

As in Hive Router, Apollo Router used to support only operation name based exclusions. With the new dynamic exclusions feature, you can now specify custom logic to exclude requests from usage reporting.


## New `add_report_with_request` method in Hive Console SDK

In order to support exclusions based on request properties, a new method `add_report_with_request` has been added to the Hive Console SDK. This method allows you to include the request information in the report, which can then be used in the dynamic exclusion logic.

## 0.3.9 (2026-04-20)

### Features

#### Negative Cache and Single-Flight

Introduced single-flight resolution of documents in the SDK.

Added a negative cache to store non 2XX requests for 5s (configurable, but in SDK it's disabled by default). It's meant to not keep repeating the same requests that eventually give errors or 404s.

#### Persisted Documents

Introduces persisted documents support in Hive Router with configurable extraction and storage backends.

Supports extracting persisted document IDs from:
- `documentId` in request body (default)
- `documentId` in URL query params (default)
- Apollo-style `extensions.persistedQuery.sha256Hash` (default)
- custom `json_path` (for example `doc_id` or `extensions.anything.id`)
- custom `url_query_param` (for example `?doc_id=123`)
- custom `url_path_param` (for example `/graphql/:id`)

Order is configurable and evaluated top-to-bottom.

Supports persisted document resolution from:
- file manifests (Apollo and Relay KV styles)
- Hive CDN (via `hive-console-sdk`)

File storage includes watch mode by default (with 150ms debounce) to reload manifests after file changes.
Hive storage validates document ID syntax before generating CDN paths to avoid silent invalid-path behavior.

Adds persisted-documents metrics:

- `hive.router.persisted_documents.extract.missing_id_total`
- `hive.router.persisted_documents.storage.failures_total`

These help track migration progress and resolution failures in production

## 0.3.8 (2026-03-16)

### Fixes

- Update `regress` to `0.11.0`
- Implements `AsRef` trait for `graphql_tools::parser::query::ast::TypeCondition`

## 0.3.7 (2026-03-05)

### Features

#### Plugin System

This release introduces a Plugin System that allows users to extend the functionality of Hive Router by creating custom plugins.

```rust
use hive_router::plugins::plugin_trait::RouterPlugin;
use hive_router::async_trait;
 
struct MyPlugin;
 
##[async_trait]
impl RouterPlugin for MyPlugin {
    type Config = ();
 
    fn plugin_name() -> &'static str {
        "my_plugin"
    }
}
```

You can learn more about the plugin system in the [technical documentation](https://the-guild.dev/graphql/hive/docs/router/plugin-system) and in [Extending the Router guide](https://the-guild.dev/graphql/hive/docs/router/guides/extending-the-router).

This new feature also exposes many of the Router's internals through the [`hive-router` crate](https://crates.io/crates/hive-router).

### Fixes

#### Dependencies Updates

- Update `rustls`, `aws-lc-rs` and `aws-lc-sys` dependencies to address `PKCS7` CVE in `aws-lc` crates.
- Update `rand` to latest version.

#### Internal GraphQL Validation Cache Key

- `ConsumerSchema` and `ValidationPlan` now implement `hash` property, which is calculated based on the SDL string of the consumer schema and the validation rules when the struct is created or when a new rule is added to the validation plan.
- Validation cache key is generated by hashing the SDL string of the consumer schema, and the validation rules together with the operation itself.
- All schema AST nodes now implement `Hash` trait, which allows us to hash the entire schema AST when generating the validation cache key.

## 0.3.6 (2026-02-06)

### Features

- Operation Complexity - Limit Aliases (#746)
- Operation Complexity - Limit Aliases (#749)

## 0.3.5 (2026-01-27)

### Fixes

#### Fix release issues and conflicts

- Re-export `graphql-tools` from `hive-console-sdk` to make it easier to depend directly on the SDK instead of an external package.

#### Fixed: 4xx client errors are now properly treated as errors and trigger endpoint failover, instead of being returned as successful responses.

This ensures the CDN fallback mechanism works correctly when endpoints return client errors like 403 Forbidden or 404 Not Found.

## 0.3.4 (2026-01-22)

### Fixes

#### Refactor Parse Error Handling in `graphql-tools`

Breaking;
- `ParseError(String)` is now `ParseError(InternalError<'static>)`.
- - So that the internals of the error can be better structured and more informative, such as including line and column information.
- `ParseError`s are no longer prefixed with "query parse error: " in their Display implementation.

## 0.3.3 (2026-01-16)

### Fixes

#### Add `minify_query_document` for optimized query minification

Implements `minify_query_document` to minify parsed GraphQL operations directly, avoiding the need for an intermediate `Display` step. This new approach uses `itoa` and `ryu` for efficient integer and float formatting.

By minifying the query document representation instead of the query string, we achieve performance improvements: query minification time is reduced from 4μs to 500ns, and unnecessary allocations are eliminated.

Includes benchmarks and tests to validate the performance gains and correctness of the new implementation.

#### Update reqwest default features

In this version, we've updated the `features` used by the `reqwest` dependency. By default, this Crate is using `rustls` for TLS.

## 0.3.2 (2026-01-15)

### Fixes

- Downgrade `reqwest` to `v0.12` to avoid runtime crash from `rustls` `CryptoProvider` introduced in reqwest `v0.13`.

## 0.3.1 (2026-01-14)

### Fixes

#### Update `reqwest`, `reqwest-retry`, and `reqwest-middleware` dependencies

This change updates the `reqwest` dependency to version `0.13.0`, `reqwest-retry` to version `0.9.0`, and `reqwest-middleware` to version `0.5.0` in the Hive Console SDK and Router packages.

#### Moves hive-console-sdk to router repository

This change moves the `hive-console-sdk` package to the Hive Router repository.

## 0.3.0

### Minor Changes

- [#7379](https://github.com/graphql-hive/console/pull/7379)
  [`b134461`](https://github.com/graphql-hive/console/commit/b13446109d9663ccabef07995eb25cf9dff34f37)
  Thanks [@ardatan](https://github.com/ardatan)! - Breaking Changes to avoid future breaking
  changes;

  Switch to [Builder](https://rust-unofficial.github.io/patterns/patterns/creational/builder.html)
  pattern for `SupergraphFetcher`, `PersistedDocumentsManager` and `UsageAgent` structs.

  No more `try_new` or `try_new_async` or `try_new_sync` functions, instead use
  `SupergraphFetcherBuilder`, `PersistedDocumentsManagerBuilder` and `UsageAgentBuilder` structs to
  create instances.

  Benefits;

  - No need to provide all parameters at once when creating an instance even for default values.

  Example;

  ```rust
  // Before
  let fetcher = SupergraphFetcher::try_new_async(
          "SOME_ENDPOINT", // endpoint
           "SOME_KEY",
          "MyUserAgent/1.0".to_string(),
          Duration::from_secs(5), // connect_timeout
          Duration::from_secs(10), // request_timeout
          false, // accept_invalid_certs
          3, // retry_count
      )?;

  // After
  // No need to provide all parameters at once, can use default values
  let fetcher = SupergraphFetcherBuilder::new()
      .endpoint("SOME_ENDPOINT".to_string())
      .key("SOME_KEY".to_string())
      .build_async()?;
  ```

  - Easier to add new configuration options in the future without breaking existing code.

  Example;

  ```rust
  let fetcher = SupergraphFetcher::try_new_async(
          "SOME_ENDPOINT", // endpoint
           "SOME_KEY",
          "MyUserAgent/1.0".to_string(),
          Duration::from_secs(5), // connect_timeout
          Duration::from_secs(10), // request_timeout
          false, // accept_invalid_certs
          3, // retry_count
          circuit_breaker_config, // Breaking Change -> new parameter added
      )?;

  let fetcher = SupergraphFetcherBuilder::new()
      .endpoint("SOME_ENDPOINT".to_string())
      .key("SOME_KEY".to_string())
      .build_async()?; // No breaking change, circuit_breaker_config can be added later if needed
  ```

### Patch Changes

- [#7379](https://github.com/graphql-hive/console/pull/7379)
  [`b134461`](https://github.com/graphql-hive/console/commit/b13446109d9663ccabef07995eb25cf9dff34f37)
  Thanks [@ardatan](https://github.com/ardatan)! - Circuit Breaker Implementation and Multiple
  Endpoints Support

  Implementation of Circuit Breakers in Hive Console Rust SDK, you can learn more
  [here](https://the-guild.dev/graphql/hive/product-updates/2025-12-04-cdn-mirror-and-circuit-breaker)

  Breaking Changes:

  Now `endpoint` configuration accepts multiple endpoints as an array for `SupergraphFetcherBuilder`
  and `PersistedDocumentsManager`.

  ```diff
  SupergraphFetcherBuilder::default()
  -    .endpoint(endpoint)
  +    .add_endpoint(endpoint1)
  +    .add_endpoint(endpoint2)
  ```

  This change requires updating the configuration structure to accommodate multiple endpoints.

## 0.2.3

### Patch Changes

- [#7446](https://github.com/graphql-hive/console/pull/7446)
  [`0ac2e06`](https://github.com/graphql-hive/console/commit/0ac2e06fd6eb94c9d9817f78faf6337118f945eb)
  Thanks [@ardatan](https://github.com/ardatan)! - Fixed the stack overflow error while collecting
  schema coordinates from the recursive input object types correctly;

  Let's consider the following schema:

  ```graphql
  input RecursiveInput {
    field: String
    nested: RecursiveInput
  }
  ```

  And you have an operation that uses this input type:

  ```graphql
  query UserQuery($input: RecursiveInput!) {
    user(input: $input) {
      id
    }
  }
  ```

  When collecting schema coordinates from operations that use this input type, the previous
  implementation could enter an infinite recursion when traversing the nested `RecursiveInput` type.
  This would lead to a stack overflow error.

- [#7448](https://github.com/graphql-hive/console/pull/7448)
  [`4b796f9`](https://github.com/graphql-hive/console/commit/4b796f95bbc0fc37aac2c3a108a6165858b42b49)
  Thanks [@kamilkisiela](https://github.com/kamilkisiela)! - export `minify_query` and
  `normalize_operation` functions (mainly for Hive Router)

- [#7439](https://github.com/graphql-hive/console/pull/7439)
  [`a9905ec`](https://github.com/graphql-hive/console/commit/a9905ec7198cf1bec977a281c5021e0ef93c2c34)
  Thanks [@jdolle](https://github.com/jdolle)! - Remove the usage flag (!) from non-null, but unused
  variables to match js sdk

## 0.2.2

### Patch Changes

- [#7405](https://github.com/graphql-hive/console/pull/7405)
  [`24c0998`](https://github.com/graphql-hive/console/commit/24c099818e4dfec43feea7775e8189d0f305a10c)
  Thanks [@ardatan](https://github.com/ardatan)! - Use the JSON Schema specification of the usage
  reports directly to generate Rust structs as a source of truth instead of manually written types

## 0.2.1

### Patch Changes

- [#7364](https://github.com/graphql-hive/console/pull/7364)
  [`69e2f74`](https://github.com/graphql-hive/console/commit/69e2f74ab867ee5e97bbcfcf6a1b69bb23ccc7b2)
  Thanks [@ardatan](https://github.com/ardatan)! - Fix the bug where reports were not being sent
  correctly due to missing headers

## 0.2.0

### Minor Changes

- [#7246](https://github.com/graphql-hive/console/pull/7246)
  [`cc6cd28`](https://github.com/graphql-hive/console/commit/cc6cd28eb52d774683c088ce456812d3541d977d)
  Thanks [@ardatan](https://github.com/ardatan)! - Breaking;

  - `SupergraphFetcher` now has two different modes: async and sync. You can choose between
    `SupergraphFetcherAsyncClient` and `SupergraphFetcherSyncClient` based on your needs. See the
    examples at the bottom.
  - `SupergraphFetcher` now has a new `retry_count` parameter to specify how many times to retry
    fetching the supergraph in case of failures.
  - `PersistedDocumentsManager` new needs `user_agent` parameter to be sent to Hive Console when
    fetching persisted queries.
  - `UsageAgent::new` is now `UsageAgent::try_new` and it returns a `Result` with `Arc`, so you can
    freely clone it across threads. This change was made to handle potential errors during the
    creation of the HTTP client. Make sure to handle the `Result` when creating a `UsageAgent`.

  ```rust
  // Sync Mode
  let fetcher = SupergraphFetcher::try_new_sync(/* params */)
  .map_err(|e| anyhow!("Failed to create SupergraphFetcher: {}", e))?;

  // Use the fetcher to fetch the supergraph (Sync)
  let supergraph = fetcher
      .fetch_supergraph()
      .map_err(|e| anyhow!("Failed to fetch supergraph: {}", e))?;

  // Async Mode

  let fetcher = SupergraphFetcher::try_new_async(/* params */)
  .map_err(|e| anyhow!("Failed to create SupergraphFetcher: {}", e))?;

  // Use the fetcher to fetch the supergraph (Async)
  let supergraph = fetcher
      .fetch_supergraph()
      .await
      .map_err(|e| anyhow!("Failed to fetch supergraph: {}", e))?;
  ```

## 0.1.1

### Patch Changes

- [#7248](https://github.com/graphql-hive/console/pull/7248)
  [`d8f6e25`](https://github.com/graphql-hive/console/commit/d8f6e252ee3cd22948eb0d64b9d25c9b04dba47c)
  Thanks [@n1ru4l](https://github.com/n1ru4l)! - Support project and personal access tokens (`hvp1/`
  and `hvu1/`).

## 0.1.0

### Minor Changes

- [#7196](https://github.com/graphql-hive/console/pull/7196)
  [`7878736`](https://github.com/graphql-hive/console/commit/7878736643578ab23d95412b893c091e32691e60)
  Thanks [@ardatan](https://github.com/ardatan)! - Breaking;

  - `UsageAgent` now accepts `Duration` for `connect_timeout` and `request_timeout` instead of
    `u64`.
  - `SupergraphFetcher` now accepts `Duration` for `connect_timeout` and `request_timeout` instead
    of `u64`.
  - `PersistedDocumentsManager` now accepts `Duration` for `connect_timeout` and `request_timeout`
    instead of `u64`.
  - Use original `graphql-parser` and `graphql-tools` crates instead of forked versions.

## 0.0.1

### Patch Changes

- [#7143](https://github.com/graphql-hive/console/pull/7143)
  [`b80e896`](https://github.com/graphql-hive/console/commit/b80e8960f492e3bcfe1012caab294d9066d86fe3)
  Thanks [@ardatan](https://github.com/ardatan)! - Extract Hive Console integration implementation
  into a new package `hive-console-sdk` which can be used by any Rust library for Hive Console
  integration

  It also includes a refactor to use less Mutexes like replacing `lru` + `Mutex` with the
  thread-safe `moka` package. Only one place that handles queueing uses `Mutex` now.
