Skip to content

Releases: graphql-hive/router

hive-router-internal 0.0.41 (2026-08-10)

Choose a tag to compare

@knope-bot knope-bot released this 10 Aug 10:06
baf8056

Features

Expose log correlation to the plugin system

Plugins can now attach a custom correlation (e.g. a tenant or project ID) to every log line of the current request via hive_router::set_log_correlation(key, value), callable from any hook, alongside the built-in request_id and trace_id.

Fixes #1350

Expose the request summary to the plugin system

Plugins can now enrich the request summary log line with custom attributes via hive_router::set_summary_attribute(key, value), callable from any hook (e.g. on_http_request, on_graphql_analysis).

Fixes #1368

Expose the summary message to the plugin system

Plugins can now override the request summary log line's message via hive_router::set_summary_message(message), callable from any hook.

Fixes #1378

Fixes

Add apollo_graphos supergraph source

Adds a new apollo_graphos supergraph source that fetches the supergraph schema from Apollo GraphOS's managed federation Uplink, for routers migrating from Apollo Router/Gateway without needing a separate schema-delivery pipeline.

Configure it with graph_ref and key (or the APOLLO_GRAPH_REF/APOLLO_KEY environment variables), and optionally endpoint (defaults to Apollo's GCP and AWS Uplink endpoints, tried in order), timeout and accept_invalid_certs.

Closes #505

hive-router-config 0.1.11 (2026-08-10)

Choose a tag to compare

@knope-bot knope-bot released this 10 Aug 10:06
baf8056

Features

Add apollo_graphos supergraph source

Adds a new apollo_graphos supergraph source that fetches the supergraph schema from Apollo GraphOS's managed federation Uplink, for routers migrating from Apollo Router/Gateway without needing a separate schema-delivery pipeline.

Configure it with graph_ref and key (or the APOLLO_GRAPH_REF/APOLLO_KEY environment variables), and optionally endpoint (defaults to Apollo's GCP and AWS Uplink endpoints, tried in order), timeout and accept_invalid_certs.

Closes #505

hive-router 0.0.87 (2026-08-05)

Choose a tag to compare

@knope-bot knope-bot released this 06 Aug 06:20
56cf846

Features

Attach the correlation request-id to the root HTTP server span

The root http.server OpenTelemetry span now carries a router.request_id attribute, set to the same request-id used for log correlation (either the incoming correlation header, e.g. x-request-id, or an auto-generated one). This makes it possible to join a trace directly to its logs without cross-referencing trace IDs.

Fixes #1353

Add jwt.scopes_claim

Adds a new jwt.scopes_claim configuration option that lets you specify which JWT claim the @requiresScopes directive should read authorization data from, instead of the hardcoded scope/scopes claim.

This is useful for identity providers that grant authorization data under a different claim name — for example, Microsoft Entra ID, which issues app roles under a roles claim rather than scope. Setting jwt.scopes_claim: roles allows @requiresScopes to authorize requests using Entra app roles without requiring any changes to how the claim is issued.

Add limits.max_request_header_size

Adds a new limits.max_request_header_size configuration option (default: 64KiB) that rejects requests whose HTTP headers exceed the configured size with 431 Request Header Fields Too Large, before the request is processed.

Since the router propagates client headers (cookies, JWTs) to subgraphs, requests with oversized headers would previously be forwarded and rejected by the subgraph server's own header limit (e.g. Tomcat's 8KB default), surfacing as a confusing subgraph error. With this limit, such requests are rejected at the router with a clear error.

Fixes

Expose request correlation IDs to plugins and middlewares

Request/trace correlation IDs are now extracted and scoped by a dedicated middleware that wraps the entire request pipeline, instead of only inside the GraphQL handler.

This means plugins, the coprocessor runtime, and any other middleware can now log with the same request_id/trace_id as the rest of the request.

Fixes #1351

Register the state the subscription callback handler extracts

The subscription callback handler could not serve a single request: every call failed the ntex State extractor with App state is not configured, to configure use App::state(), returning a 500 to the subgraph. Because callbacks are how the subgraph delivers events back to the router, any subscription using the callback transport silently stopped producing messages.

handle_callback extracts two pieces of state:

callback_subscriptions: web::types::State<CallbackSubscriptionsMap>,
telemetry_context:      web::types::State<std::sync::Arc<TelemetryContext>>,

Neither listener registered a matching pair:

  • the dedicated callback server (subscriptions.callback.listen set) registered the map, but passed telemetry.context — a bare TelemetryContext, since Telemetry::context is not an Arc — where the handler asks for State<Arc<TelemetryContext>>;
  • the main server (no listen, callback mounted on the main app) registered Arc<TelemetryContext> via shared_state.telemetry_context, but never registered CallbackSubscriptionsMap at all.

State<T> is generic, so both mismatches compile; they only fail when the extractor runs. That makes the callback protocol broken in both configurations, with no config-level workaround.

The dedicated server now takes its telemetry context from shared_state.telemetry_context, the same Arc the main server already registers, and the main server gains the missing map.

The e2e suite does not catch this: TestRouter builds its own ntex App rather than reusing the one run_router assembles, and its copy happens to register both states correctly — it reads the telemetry context from shared_state (already an Arc) and registers callback_subscriptions on the main app. listen_on_different_port therefore passes against a build whose callback endpoint 500s on every request.

Accept multipart streaming types with boundary parameters

Hive Router now accepts boundary parameters on multipart/mixed values in the Accept header. This prevents Apollo Client's default Accept header from returning 415 Unsupported Media Type while leaving response boundary selection to the router.

Seed the embedded Hive Laboratory from the router config

Adds optional keys under laboratory: operations, named operations that each open in a pre-filled tab, and collections, named groups of operations shown in the Laboratory's sidebar. Each operation may carry variables, headers and extensions as native YAML maps.

Seeded values are embedded in the served page and visible via "view source", so they must not contain secrets. Seeded operations and collections are refreshed from config on every reload; work a user creates themselves is preserved.

Upgrade to latest laboratory

Upgrades the embedded @graphql-hive/laboratory from 0.2.0 to 0.2.3.

Added

  • Copy as cURL in the operation toolbar.
  • A reload-schema button in the builder, which introspects over the network even when a schema was
    supplied by the host, and spins while the request is in flight. It replaces the previous
    "restore default endpoint" button; restoreDefaultEndpoint remains available on the API.
  • introspection.pollSchema setting to turn off the 5 second introspection poll and refresh the
    schema only on demand.
  • enableFullScreen prop (default true) so hosts that already fill the viewport can hide the
    full screen control.
  • The Query Plan tab is now always shown, with an empty state explaining that plans appear when
    the gateway returns extensions.queryPlan.

Fixed

  • The builder no longer collapses expanded fields while introspection is polling. An unchanged
    schema previously produced a new GraphQLSchema on every poll, resetting expansion to the depth
    of the current document.
  • Editor hovers now appear on mouse over, so validation messages and schema documentation are
    readable.
  • Monaco's folding chevrons render as icons instead of empty squares. Font faces are now
    registered on the document, where browsers resolve them, rather than inside the shadow root
    where they are ignored.
  • Response size is shown in real units instead of always reading 0KB, and is measured in UTF-8
    bytes.
  • Tooltips attached with asChild now appear. Button, TooltipTrigger and AlertDialogTrigger
    did not forward refs, leaving the tooltip without an element to anchor to.
  • The builder's tree/list toggle is controlled, cannot be deselected into an empty state, and is
    disabled with an explanation until a search is active.
  • The Query Plan panel no longer throws while rendering when a response body is not JSON.
  • monaco-graphql is initialized once and updated in place, so variables validation registers
    regardless of which editor mounts first and survives an endpoint change.
  • Removed invalid nested buttons in builder and collection rows, which also makes the collection
    edit and delete actions keyboard reachable.
  • The query plan visualization no longer updates state during render.
  • The builder no longer resets its view when toggling settings, by hardening the merge code.

hive-router-plan-executor 7.0.2 (2026-08-05)

Choose a tag to compare

@knope-bot knope-bot released this 06 Aug 06:20
56cf846

Fixes

Attach the correlation request-id to the root HTTP server span

The root http.server OpenTelemetry span now carries a router.request_id attribute, set to the same request-id used for log correlation (either the incoming correlation header, e.g. x-request-id, or an auto-generated one). This makes it possible to join a trace directly to its logs without cross-referencing trace IDs.

Fixes #1353

Add jwt.scopes_claim

Adds a new jwt.scopes_claim configuration option that lets you specify which JWT claim the @requiresScopes directive should read authorization data from, instead of the hardcoded scope/scopes claim.

This is useful for identity providers that grant authorization data under a different claim name — for example, Microsoft Entra ID, which issues app roles under a roles claim rather than scope. Setting jwt.scopes_claim: roles allows @requiresScopes to authorize requests using Entra app roles without requiring any changes to how the claim is issued.

Add limits.max_request_header_size

Adds a new limits.max_request_header_size configuration option (default: 64KiB) that rejects requests whose HTTP headers exceed the configured size with 431 Request Header Fields Too Large, before the request is processed.

Since the router propagates client headers (cookies, JWTs) to subgraphs, requests with oversized headers would previously be forwarded and rejected by the subgraph server's own header limit (e.g. Tomcat's 8KB default), surfacing as a confusing subgraph error. With this limit, such requests are rejected at the router with a clear error.

Seed the embedded Hive Laboratory from the router config

Adds optional keys under laboratory: operations, named operations that each open in a pre-filled tab, and collections, named groups of operations shown in the Laboratory's sidebar. Each operation may carry variables, headers and extensions as native YAML maps.

Seeded values are embedded in the served page and visible via "view source", so they must not contain secrets. Seeded operations and collections are refreshed from config on every reload; work a user creates themselves is preserved.

hive-router-internal 0.0.40 (2026-08-05)

Choose a tag to compare

@knope-bot knope-bot released this 06 Aug 06:20
56cf846

Features

Attach the correlation request-id to the root HTTP server span

The root http.server OpenTelemetry span now carries a router.request_id attribute, set to the same request-id used for log correlation (either the incoming correlation header, e.g. x-request-id, or an auto-generated one). This makes it possible to join a trace directly to its logs without cross-referencing trace IDs.

Fixes #1353

Fixes

Add jwt.scopes_claim

Adds a new jwt.scopes_claim configuration option that lets you specify which JWT claim the @requiresScopes directive should read authorization data from, instead of the hardcoded scope/scopes claim.

This is useful for identity providers that grant authorization data under a different claim name — for example, Microsoft Entra ID, which issues app roles under a roles claim rather than scope. Setting jwt.scopes_claim: roles allows @requiresScopes to authorize requests using Entra app roles without requiring any changes to how the claim is issued.

Add limits.max_request_header_size

Adds a new limits.max_request_header_size configuration option (default: 64KiB) that rejects requests whose HTTP headers exceed the configured size with 431 Request Header Fields Too Large, before the request is processed.

Since the router propagates client headers (cookies, JWTs) to subgraphs, requests with oversized headers would previously be forwarded and rejected by the subgraph server's own header limit (e.g. Tomcat's 8KB default), surfacing as a confusing subgraph error. With this limit, such requests are rejected at the router with a clear error.

Seed the embedded Hive Laboratory from the router config

Adds optional keys under laboratory: operations, named operations that each open in a pre-filled tab, and collections, named groups of operations shown in the Laboratory's sidebar. Each operation may carry variables, headers and extensions as native YAML maps.

Seeded values are embedded in the served page and visible via "view source", so they must not contain secrets. Seeded operations and collections are refreshed from config on every reload; work a user creates themselves is preserved.

hive-router-config 0.1.10 (2026-08-05)

Choose a tag to compare

@knope-bot knope-bot released this 06 Aug 06:20
56cf846

Features

Add jwt.scopes_claim

Adds a new jwt.scopes_claim configuration option that lets you specify which JWT claim the @requiresScopes directive should read authorization data from, instead of the hardcoded scope/scopes claim.

This is useful for identity providers that grant authorization data under a different claim name — for example, Microsoft Entra ID, which issues app roles under a roles claim rather than scope. Setting jwt.scopes_claim: roles allows @requiresScopes to authorize requests using Entra app roles without requiring any changes to how the claim is issued.

Add limits.max_request_header_size

Adds a new limits.max_request_header_size configuration option (default: 64KiB) that rejects requests whose HTTP headers exceed the configured size with 431 Request Header Fields Too Large, before the request is processed.

Since the router propagates client headers (cookies, JWTs) to subgraphs, requests with oversized headers would previously be forwarded and rejected by the subgraph server's own header limit (e.g. Tomcat's 8KB default), surfacing as a confusing subgraph error. With this limit, such requests are rejected at the router with a clear error.

Fixes

Seed the embedded Hive Laboratory from the router config

Adds optional keys under laboratory: operations, named operations that each open in a pre-filled tab, and collections, named groups of operations shown in the Laboratory's sidebar. Each operation may carry variables, headers and extensions as native YAML maps.

Seeded values are embedded in the served page and visible via "view source", so they must not contain secrets. Seeded operations and collections are refreshed from config on every reload; work a user creates themselves is preserved.

hive-router 0.0.86 (2026-07-28)

Choose a tag to compare

@knope-bot knope-bot released this 28 Jul 19:22
595b767

Fixes

Regular queries no longer count toward max_long_lived_clients

The long-lived client limit (traffic_shaping.router.max_long_lived_clients) classified requests from the Accept header alone, so clients that advertise streaming support on every operation (e.g. urql sends ..., text/event-stream, multipart/mixed) had all of their queries and mutations counted against — and, past the limit, rejected by — the limit.

Long-lived clients are now counted where they actually become known:

  • WebSocket connections are still reserved at upgrade time.
  • HTTP subscriptions reserve a slot once the parsed operation is known to be a subscription — still before any planning/execution work — and release it when the client stream ends.

Regular queries and mutations never count toward the limit, regardless of their Accept header, matching the documented behavior. Over-limit rejections keep the same response (503, Retry-After: 5, Too many long-lived clients) and now happen inside the request span, so they are visible to tracing.

Replaced logging request-id generator

Version 0.0.85 introduced new logging runtime that uses Sonyflake crate to generate request-id in requests that doesn't have it passed via HTTP headers.

The Sonyflake runtime can fail on some OS configurations.

This change replaces the Sonyflake runtime with uuid generator, that's more fail-safe.

hive-router-plan-executor 7.0.1 (2026-07-28)

Choose a tag to compare

@knope-bot knope-bot released this 28 Jul 19:22
595b767

Fixes

Regular queries no longer count toward max_long_lived_clients

The long-lived client limit (traffic_shaping.router.max_long_lived_clients) classified requests from the Accept header alone, so clients that advertise streaming support on every operation (e.g. urql sends ..., text/event-stream, multipart/mixed) had all of their queries and mutations counted against — and, past the limit, rejected by — the limit.

Long-lived clients are now counted where they actually become known:

  • WebSocket connections are still reserved at upgrade time.
  • HTTP subscriptions reserve a slot once the parsed operation is known to be a subscription — still before any planning/execution work — and release it when the client stream ends.

Regular queries and mutations never count toward the limit, regardless of their Accept header, matching the documented behavior. Over-limit rejections keep the same response (503, Retry-After: 5, Too many long-lived clients) and now happen inside the request span, so they are visible to tracing.

Replaced logging request-id generator

Version 0.0.85 introduced new logging runtime that uses Sonyflake crate to generate request-id in requests that doesn't have it passed via HTTP headers.

The Sonyflake runtime can fail on some OS configurations.

This change replaces the Sonyflake runtime with uuid generator, that's more fail-safe.

hive-router-internal 0.0.39 (2026-07-28)

Choose a tag to compare

@knope-bot knope-bot released this 28 Jul 19:22
595b767

Fixes

Regular queries no longer count toward max_long_lived_clients

The long-lived client limit (traffic_shaping.router.max_long_lived_clients) classified requests from the Accept header alone, so clients that advertise streaming support on every operation (e.g. urql sends ..., text/event-stream, multipart/mixed) had all of their queries and mutations counted against — and, past the limit, rejected by — the limit.

Long-lived clients are now counted where they actually become known:

  • WebSocket connections are still reserved at upgrade time.
  • HTTP subscriptions reserve a slot once the parsed operation is known to be a subscription — still before any planning/execution work — and release it when the client stream ends.

Regular queries and mutations never count toward the limit, regardless of their Accept header, matching the documented behavior. Over-limit rejections keep the same response (503, Retry-After: 5, Too many long-lived clients) and now happen inside the request span, so they are visible to tracing.

Replaced logging request-id generator

Version 0.0.85 introduced new logging runtime that uses Sonyflake crate to generate request-id in requests that doesn't have it passed via HTTP headers.

The Sonyflake runtime can fail on some OS configurations.

This change replaces the Sonyflake runtime with uuid generator, that's more fail-safe.

hive-router-config 0.1.9 (2026-07-28)

Choose a tag to compare

@knope-bot knope-bot released this 28 Jul 19:22
595b767

Fixes

Regular queries no longer count toward max_long_lived_clients

The long-lived client limit (traffic_shaping.router.max_long_lived_clients) classified requests from the Accept header alone, so clients that advertise streaming support on every operation (e.g. urql sends ..., text/event-stream, multipart/mixed) had all of their queries and mutations counted against — and, past the limit, rejected by — the limit.

Long-lived clients are now counted where they actually become known:

  • WebSocket connections are still reserved at upgrade time.
  • HTTP subscriptions reserve a slot once the parsed operation is known to be a subscription — still before any planning/execution work — and release it when the client stream ends.

Regular queries and mutations never count toward the limit, regardless of their Accept header, matching the documented behavior. Over-limit rejections keep the same response (503, Retry-After: 5, Too many long-lived clients) and now happen inside the request span, so they are visible to tracing.