Skip to content

feat: Subscriptions#620

Open
enisdenjo wants to merge 202 commits intomainfrom
not-kamil-subs
Open

feat: Subscriptions#620
enisdenjo wants to merge 202 commits intomainfrom
not-kamil-subs

Conversation

@enisdenjo
Copy link
Member

@enisdenjo enisdenjo commented Dec 13, 2025

Closes #313
Ref router-165

Implement SSE, Incremental Delivery over HTTP, Apollo's Multipart HTTP, WebSocket and HTTP Callback specs for subscriptions when communicating with subgraphs or clients with entity resolution capabilities.

Documentation

See PR in docs repo.

Streaming execution result

lib/executor/src/execution/plan.rs@QueryPlanExecutionResult

The execution pipeline returns QueryPlanExecutionResult - an enum that can be either a single response or a stream:

pub enum QueryPlanExecutionResult {
    Single(PlanExecutionOutput),
    Stream(PlanSubscriptionOutput),
}

This separation allows the query planner and executor to operate independently from transport concerns, making future improvements (like connection repair and silent retries) easier to implement.

Owned query plan execution context values for streaming

lib/executor/src/execution/plan.rs

Subscriptions require long-lived contexts that outlive request lifetimes. The subscription stream closure requires 'static data, so QueryPlanExecutionOpts fields captured by the stream are Arc-wrapped so they can be cheaply cloned per event without deep-copying:

  • operation_for_plan: Arc<OperationDefinition>
  • variable_values: Arc<Option<HashMap<String, sonic_rs::Value>>>
  • client_request: Arc<ClientRequestDetails>
  • introspection_context: Arc<IntrospectionContext>
  • executors, projection_plan, headers_plan are Arc at the call site

IntrospectionContext carries no lifetime parameter - query is Option<Arc<OperationDefinition>> and schema is Arc<Document>, both sourced from already-Arc-wrapped data in SupergraphData (planner.consumer_schema.document) and SchemaMetadata.

SupergraphData.subgraph_executor_map, SupergraphData.metadata, and RouterSharedState.headers_plan are Arc at the source and are threaded through QueryPlanExecutionOpts and IntrospectionContext as Arc instead of borrowed references. SubgraphExecutorMap contains multiple DashMaps so keeping it behind Arc is especially important. The subscription path does cheap ref-count bumps. The query/mutation path just derefs.

This enables entity resolution to happen independently for each subscription event and allows remaining plan nodes to be processed after the subscription fetch.

Unified execution inner path for subscriptions

lib/executor/src/execution/plan.rs@execute_query_plan_with_data

The post-fetch logic (plugin hooks, plan node execution, projection, error aggregation) lives in a private execute_query_plan_with_data(data, opts) function shared by both the query/mutation path and the subscription stream. Each subscription event reconstructs an opts from cloned Arcs and calls execute_query_plan_with_data, meaning subscription events go through the full execution pipeline including plugins.

Error serialization helper

lib/executor/src/execution/plan.rs@FailedExecutionResult

FailedExecutionResult is a serializable struct with a serialize() method (including a safe fallback if serialization itself fails) used in both the subscription stream and the pipeline error handler.

Error messages in the subscription stream

When a subscription subgraph stream yields an error it is converted through with_plan_context (which attaches the subgraph name) and then From<PlanExecutionError> for GraphQLError, producing a message that includes the actual underlying error detail. For example:

"Error reading SSE subscription stream: Stream read error: error reading a body from connection"

Subscription handlers

The router respects the client's Accept header to determine response format:

  • text/event-stream → SSE responses
  • multipart/mixed → Incremental Delivery over HTTP
  • multipart/mixed;subscriptionSpec="1.0" → Apollo multipart HTTP
  • Returns 406 Not Acceptable if subscription is requested over unsupported transport
  • Handles errors by emitting an error event and completing the stream
  • Heartbeats every 10 seconds (except for incremental delivery, doesn't have it)
  • Of course protocols used between router and subgraphs and clients can be different

Same behavior is expected when communicating with subgraphs.

SSE

lib/executor/src/executors/sse.rs

Implements the GraphQL over SSE spec distinct connection mode.

Multipart protocol

lib/executor/src/executors/multipart_subscribe.rs

Implements Apollo's multipart HTTP spec and GraphQL's Incremental Delivery over HTTP RFC.

WebSockets

Read stacked PR #738

Plugin system

The WS server assembles a synthetic http request for every ws operation message allowing the plugin system to run as usual for the supported execution paths. (No subscriptions because the plugin system generally does not support subscriptions - yet).

HTTP Callbacks

Read stacked PR #831

Entity resolution

lib/executor/src/execution/plan.rs@execute_query_plan

When a subscription emits data that references entities from other subgraphs, the router:

  1. Receives subscription event from primary subgraph
  2. Executes remaining plan nodes (flatten, fetch, etc.) to populate missing fields
  3. Projects the complete response
  4. Streams the full response to client

Subscription node in query plan

In PlanNode::from_fetch_step in plan_nodes.rs, when building a node from a fetch step, if the step has no response path and its operation kind is Subscription, it directly produces a PlanNode::Subscription instead of PlanNode::Fetch.

Subgraph executor subscribe method

lib/executor/src/executors/common.rs@subscribe

The HTTP executor has a subscribe() method that:

  • Negotiates content-type (prefers multipart, falls back to SSE)
  • Establishes long-lived connections to subgraphs
  • Returns a BoxStream<HttpExecutionResponse> for downstream processing

WebSocket executor

lib/executor/src/executors/websocket.rs
lib/executor/src/executors/graphql_transport_ws.rs

Request preparation (building a SubscribePayload and optional ConnectionInitPayload from a SubgraphExecutionRequest) is handled by a shared build_subscribe_payload function. WsClient::subscribe takes a single SubscribePayload argument. SubscribePayload derives Default.

HTTP callback executor

lib/executor/src/executors/http_callback.rs

The subscription extension is injected by mutating execution_request.extensions in place via get_or_insert_default() before delegating to the shared build_request_body.

Configure to only enable/disable subscriptions

The supported subscription protocols are inherently HTTP and do not need a "protocol" configuration option. Hive Router sends an accept header listing all supported protocols for subscriptions over HTTP and the subgraph is free to choose whichever one it supports.

Whether we really want to limit specific protocols is up to discussion but objectively there is no benefit since they're all streamed HTTP.

Hence, you can only:

supergraph:
  source: file
  path: supergraph.graphql
subscriptions:
  enabled: true

P.S. if the subscriptions are disabled, the router will respond when receiving a subscription request:

HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json

{"errors":[{"message":"Subscriptions are not supported","extensions":{"code":"SUBSCRIPTIONS_NOT_SUPPORTED"}}]}

No Silent Retries & Upstream Connection Repair

Most GraphQL subgraph implementations are stateless for subscriptions and have no concept of "continuing" from where they left off after a connection loss. Implementing retry logic on the router side would create false expectations - users would assume all events are delivered, but some would be lost when the subgraph creates a fresh subscription.

This is fundamentally why the EDFS (Event-Driven Federated Subscriptions) and callback protocols exist. To avoid misleading behavior and keep the PR focused on the core functionality, connection repair is not implemented.

TODO

  • documentation
  • changesets
  • e2e tests for error handling
  • e2e tests for header propagation
  • use details from the actual client request for entity resolution towards subgraphs of events
  • test subgraph disconnect propagation
  • use apollo's multipart http payload for transport erros
  • test client disconnect propagation
    • hard to test, would need changing the source code because async being state machines allows it just to stop execution in any suspended state
  • usage reporting (bin/router/src/pipeline/mod.rs#305)
  • performance considerations
  • entity resolution failures dont end the stream, should they? a subgraph might recover, usually you dont end the whole stream. they should not end the stream actually they SHOULD because the router might not guarantee the subgraph will recover and the client might ignore the error keeping the gateway in an infinite error loop wasting resources
  • subscriptions deduplication (same subs same selection sets same headers)
  • reloading the supergraph notifies the subscribers
  • limits, things like client connection or event queue
  • configure enable/disable subscriptions
  • configure accepted protocols
    • no need, all these here fall under "http" protocols and can be negotiated over http. read description
  • stream errors when accepting only streaming content types
  • validate config allowing only one subscriptions transport
  • plugin system
  • remove ntex patch Configure web test server port ntex-rs/ntex#790 and after main is rebased because there are some other necessary refactors for latest ntex v3

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @enisdenjo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces comprehensive support for GraphQL subscriptions within the router. It fundamentally changes how the router handles long-lived connections and streaming data, moving from a single-response model to one that can manage continuous data flows. This enables real-time data updates for clients and subgraphs, complete with dynamic protocol negotiation and on-the-fly entity resolution for each event in a subscription stream.

Highlights

  • GraphQL Subscriptions Support: The router now fully supports GraphQL subscriptions, implementing both Server-Sent Events (SSE) and Apollo's Multipart HTTP protocols for communication with subgraphs and clients.
  • Streaming Execution Result: The execution pipeline has been refactored to return a QueryPlanExecutionResult enum, which can be either a single response or a stream, enabling native handling of long-lived subscription connections.
  • Owned Context for Streaming: A new OwnedQueryPlanExecutionContext is introduced to manage long-lived contexts required for subscriptions, allowing entity resolution to occur independently for each event within a stream.
  • Dynamic Subscription Handlers: The router intelligently determines the appropriate subscription protocol (SSE or Multipart) based on the client's Accept header, returning a 406 Not Acceptable if unsupported transports are requested.
  • Entity Resolution for Subscription Events: The router can now perform entity resolution for subscription events, fetching missing fields from other subgraphs after receiving initial data from the primary subgraph, and then streaming the complete response to the client.
  • Subscription Node in Query Plan: A new SubscriptionNode has been added to the query planner, specifically designed to wrap primary fetch operations for subscriptions, enabling complex plans that include entity resolution.
  • Subgraph Executor subscribe() Method: The HTTP executor gains a subscribe() method, allowing the router to negotiate content-type (preferring multipart), establish long-lived connections to subgraphs, and return a BoxStream for downstream processing.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new functionality for GraphQL subscriptions, including support for SSE and multipart protocols, entity resolution for subscription events, and updates to the query planner. The overall architecture is well-thought-out, especially the separation of concerns with QueryPlanExecutionResult and the use of an owned context for long-lived subscriptions.

My review has identified a critical safety issue regarding an unsafe block that could lead to a use-after-free bug. I've also found several areas where manual JSON construction is used, which is brittle and should be replaced with safer serialization. Additionally, there are opportunities to improve performance in the stream handling logic by reducing string allocations, and a potential panic in the benchmark code. Please see the detailed comments for suggestions on how to address these points.

@github-actions
Copy link

github-actions bot commented Dec 13, 2025

k6-benchmark results

     ✓ response code was 200
     ✓ no graphql errors
     ✓ valid response structure

     █ setup

     checks.........................: 100.00% ✓ 219618      ✗ 0    
     data_received..................: 6.4 GB  213 MB/s
     data_sent......................: 86 MB   2.9 MB/s
     http_req_blocked...............: avg=3.82µs  min=652ns   med=1.76µs  max=11.8ms   p(90)=2.47µs   p(95)=2.85µs  
     http_req_connecting............: avg=983ns   min=0s      med=0s      max=3.3ms    p(90)=0s       p(95)=0s      
     http_req_duration..............: avg=19.99ms min=1.93ms  med=19.08ms max=113.52ms p(90)=27.34ms  p(95)=30.39ms 
       { expected_response:true }...: avg=19.99ms min=1.93ms  med=19.08ms max=113.52ms p(90)=27.34ms  p(95)=30.39ms 
     http_req_failed................: 0.00%   ✓ 0           ✗ 73226
     http_req_receiving.............: avg=169.9µs min=25.55µs med=40.41µs max=84.13ms  p(90)=113.69µs p(95)=445.72µs
     http_req_sending...............: avg=25.02µs min=5.59µs  med=10.82µs max=19.83ms  p(90)=16.87µs  p(95)=29.84µs 
     http_req_tls_handshaking.......: avg=0s      min=0s      med=0s      max=0s       p(90)=0s       p(95)=0s      
     http_req_waiting...............: avg=19.8ms  min=1.84ms  med=18.93ms max=63.93ms  p(90)=27.06ms  p(95)=30.01ms 
     http_reqs......................: 73226   2435.907331/s
     iteration_duration.............: avg=20.48ms min=5.15ms  med=19.46ms max=253.55ms p(90)=27.8ms   p(95)=30.96ms 
     iterations.....................: 73206   2435.242019/s
     vus............................: 50      min=50        max=50 
     vus_max........................: 50      min=50        max=50 

@github-actions
Copy link

github-actions bot commented Dec 13, 2025

🐋 This PR was built and pushed to the following Docker images:

Image Names: ghcr.io/graphql-hive/router

Platforms: linux/amd64,linux/arm64

Image Tags: ghcr.io/graphql-hive/router:pr-620 ghcr.io/graphql-hive/router:sha-5b300c5

Docker metadata
{
"buildx.build.provenance/linux/amd64": {
  "builder": {
    "id": "https://github.com/graphql-hive/router/actions/runs/23447240895/attempts/1"
  },
  "buildType": "https://mobyproject.org/buildkit@v1",
  "materials": [
    {
      "uri": "pkg:docker/docker/dockerfile@1.22",
      "digest": {
        "sha256": "4a43a54dd1fedceb30ba47e76cfcf2b47304f4161c0caeac2db1c61804ea3c91"
      }
    },
    {
      "uri": "pkg:docker/gcr.io/distroless/cc-debian12@latest?platform=linux%2Famd64",
      "digest": {
        "sha256": "329e54034ce498f9c6b345044e8f530c6691f99e94a92446f68c0adf9baa8464"
      }
    }
  ],
  "invocation": {
    "configSource": {
      "entryPoint": "router.Dockerfile"
    },
    "parameters": {
      "frontend": "gateway.v0",
      "args": {
        "cmdline": "docker/dockerfile:1.22",
        "label:org.opencontainers.image.created": "2026-03-23T16:19:58.482Z",
        "label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
        "label:org.opencontainers.image.licenses": "MIT",
        "label:org.opencontainers.image.revision": "5b300c5ef067668ed53d0d7d90058088f3ba5976",
        "label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.title": "router",
        "label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.vendor": "theguild",
        "label:org.opencontainers.image.version": "pr-620",
        "source": "docker/dockerfile:1.22"
      },
      "locals": [
        {
          "name": "context"
        },
        {
          "name": "dockerfile"
        }
      ]
    },
    "environment": {
      "github_actor": "enisdenjo",
      "github_actor_id": "11807600",
      "github_event_name": "pull_request",
      "github_event_payload": {
        "action": "synchronize",
        "after": "6cb2e62d38d3570fce6efdee36f86d745ca8d31d",
        "before": "f1e9e1e3386eeddc6f86966ec2ed2e3de189145d",
        "enterprise": {
          "avatar_url": "https://avatars.githubusercontent.com/b/187753?v=4",
          "created_at": "2024-07-02T08:52:28Z",
          "description": "",
          "html_url": "https://github.com/enterprises/the-guild",
          "id": 187753,
          "name": "The Guild",
          "node_id": "E_kgDOAALdaQ",
          "slug": "the-guild",
          "updated_at": "2026-03-11T16:47:15Z",
          "website_url": "https://the-guild.dev/"
        },
        "number": 620,
        "organization": {
          "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
          "description": "Schema registry, analytics and gateway for GraphQL federation and other GraphQL APIs.",
          "events_url": "https://api.github.com/orgs/graphql-hive/events",
          "hooks_url": "https://api.github.com/orgs/graphql-hive/hooks",
          "id": 182742256,
          "issues_url": "https://api.github.com/orgs/graphql-hive/issues",
          "login": "graphql-hive",
          "members_url": "https://api.github.com/orgs/graphql-hive/members{/member}",
          "node_id": "O_kgDOCuRs8A",
          "public_members_url": "https://api.github.com/orgs/graphql-hive/public_members{/member}",
          "repos_url": "https://api.github.com/orgs/graphql-hive/repos",
          "url": "https://api.github.com/orgs/graphql-hive"
        },
        "pull_request": {
          "_links": {
            "comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/620/comments"
            },
            "commits": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/620/commits"
            },
            "html": {
              "href": "https://github.com/graphql-hive/router/pull/620"
            },
            "issue": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/620"
            },
            "review_comment": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}"
            },
            "review_comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/620/comments"
            },
            "self": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/620"
            },
            "statuses": {
              "href": "https://api.github.com/repos/graphql-hive/router/statuses/6cb2e62d38d3570fce6efdee36f86d745ca8d31d"
            }
          },
          "active_lock_reason": null,
          "additions": 8456,
          "assignee": null,
          "assignees": [],
          "author_association": "MEMBER",
          "auto_merge": null,
          "base": {
            "label": "graphql-hive:main",
            "ref": "main",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 8,
              "forks_count": 8,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": true,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 58,
              "open_issues_count": 58,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-03-23T16:07:10Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 5895,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 78,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-03-21T17:31:04Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 78,
              "watchers_count": 78,
              "web_commit_signoff_required": false
            },
            "sha": "72cf0ec5dc15f3540814a753fb4871ea2107054c",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "body": "Closes #313 \r\nRef router-165\r\n\r\nImplement [SSE](https://github.com/enisdenjo/graphql-sse/blob/918b9d414a4f938c715a8f8bc13184c0849eac50/PROTOCOL.md#distinct-connections-mode), [Incremental Delivery over HTTP](https://github.com/graphql/graphql-over-http/blob/d312e43384006fa323b918d49cfd9fbd76ac1257/rfcs/IncrementalDelivery.md), [Apollo's Multipart HTTP](https://www.apollographql.com/docs/graphos/routing/operations/subscriptions/multipart-protocol), [WebSocket](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) and [HTTP Callback](https://www.apollographql.com/docs/graphos/routing/operations/subscriptions/callback-protocol) specs for subscriptions when communicating with subgraphs or clients with entity resolution capabilities.\r\n\r\n\r\n# Streaming execution result\r\n\r\n```\r\nlib/executor/src/execution/plan.rs@QueryPlanExecutionResult\r\n```\r\n\r\nThe execution pipeline now returns `QueryPlanExecutionResult` - an enum that can be either a single response or a stream:\r\n\r\n```rust\r\npub enum QueryPlanExecutionResult {\r\n    Single(PlanExecutionOutput),\r\n    Stream(PlanSubscriptionOutput),\r\n}\r\n```\r\n\r\nThis separation allows the query planner and executor to operate independently from transport concerns, making future improvements (like connection repair and silent retries) easier to implement.\r\n\r\n# Owned query plan execution context values for streaming\r\n\r\n```\r\nlib/executor/src/execution/plan.rs\r\n```\r\n\r\nSubscriptions require long-lived contexts that outlive request lifetimes, so we clone all of the necessary context values:\r\n\r\n- `Arc`-wrapped shared data\r\n- Enables entity resolution to happen independently for each subscription event\r\n- Processes remaining plan nodes after the subscription fetch\r\n\r\n## Avoid deep clones of shared data on every subscription setup\r\n\r\n`QueryPlanExecutionOpts` received `executors`, `projection_plan`, `headers_plan`, and `schema_metadata` as borrowed references. The subscription stream closure requires `'static` data, so these were deep-cloned into `Arc` on every subscription setup:\r\n\r\n```rust\r\nlet executors: Arc<SubgraphExecutorMap> = opts.executors.clone().into();\r\nlet projection_plan: Arc<Vec<FieldProjectionPlan>> = opts.projection_plan.clone().into();\r\nlet headers_plan: Arc<HeaderRulesPlan> = opts.headers_plan.clone().into();\r\nlet schema_metadata: Arc<SchemaMetadata> = Arc::new(opts.introspection_context.metadata.clone());\r\n```\r\n\r\n`SubgraphExecutorMap` contains multiple `DashMap`s, making its clone particularly expensive.\r\n\r\nWrapped `SupergraphData.subgraph_executor_map`, `SupergraphData.metadata`, and `RouterSharedState.headers_plan` in `Arc` at the source and threaded them through `QueryPlanExecutionOpts` and `IntrospectionContext` as `Arc` instead of borrowed references. `projection_plan` was already `Arc` at the source but was dereffed to a borrow before reaching `QueryPlanExecutionOpts`, now passed as `Arc` directly. The subscription path now does cheap ref-count bumps. The query/mutation path just derefs.\r\n\r\n# Subscription handlers\r\n\r\nThe router respects the client's `Accept` header to determine response format:\r\n\r\n- `text/event-stream` → SSE responses\r\n- `multipart/mixed` → Incremental Delivery over HTTP\r\n- `multipart/mixed;subscriptionSpec=\"1.0\"` → Apollo multipart HTTP\r\n- Returns `406 Not Acceptable` if subscription is requested over unsupported transport\r\n- Handles errors by emitting an error event and completing the stream\r\n- Heartbeats every 10 seconds (except for incremental delivery, doesn't have it)\r\n- Of course protocols used between router and subgraphs and clients can be different\r\n\r\nSame behavior is expected when communicating with subgraphs.\r\n\r\n## SSE\r\n\r\n```\r\nlib/executor/src/executors/sse.rs\r\n```\r\n\r\nImplements the [GraphQL over SSE spec distinct connection mode](https://github.com/enisdenjo/graphql-sse/blob/918b9d414a4f938c715a8f8bc13184c0849eac50/PROTOCOL.md#distinct-connections-mode).\r\n\r\n## Multipart protocol\r\n\r\n```\r\nlib/executor/src/executors/multipart_subscribe.rs\r\n```\r\n\r\nImplements [Apollo's multipart HTTP spec](https://www.apollographql.com/docs/graphos/routing/operations/subscriptions/multipart-protocol) and [GraphQL's Incremental Delivery over HTTP RFC](https://github.com/graphql/graphql-over-http/blob/d312e43384006fa323b918d49cfd9fbd76ac1257/rfcs/IncrementalDelivery.md).\r\n\r\n# WebSockets\r\n\r\nRead stacked PR #738\r\n\r\n## Plugin system\r\n\r\nThe WS server assembles a synthetic http request for every ws operation message allowing the plugin system to run as usual for the supported execution paths. (No subscriptions because the plugin system generally does not support subscriptions - yet).\r\n\r\n# HTTP Callbacks\r\n\r\nRead stacked PR #831 \r\n\r\n# Entity resolution\r\n\r\n```\r\nlib/executor/src/execution/plan.rs@execute_query_plan\r\n```\r\n\r\nWhen a subscription emits data that references entities from other subgraphs, the router:\r\n\r\n1. Receives subscription event from primary subgraph\r\n2. Executes remaining plan nodes (flatten, fetch, etc.) to populate missing fields\r\n3. Projects the complete response\r\n4. Streams the full response to client\r\n\r\n# Subscription node in query plan\r\n\r\nIn PlanNode::from_fetch_step in `plan_nodes.rs`, when building a node from a fetch step, if the step has no response path and its operation kind is Subscription, it now directly produces a PlanNode::Subscription instead of PlanNode::Fetch.\r\n\r\n# Subgraph executor subscribe method\r\n\r\n```\r\nlib/executor/src/executors/common.rs@subscribe\r\n```\r\n\r\nThe HTTP executor gains a `subscribe()` method that:\r\n\r\n- Negotiates content-type (prefers multipart, falls back to SSE)\r\n- Establishes long-lived connections to subgraphs\r\n- Returns a `BoxStream<HttpExecutionResponse>` for downstream processing\r\n\r\n# Configure to only enable/disable subscriptions\r\n\r\nThe supported subscription protocols in this PR are inherintly HTTP and do not need a \"protocol\" configuration option. Hive Router will send an accept header listing all supported protocols for subscriptions over HTTP and the subgraph is free to choose whichever one it supports.\r\n\r\nWhether we really _want_ to limit specific protocols is up to discussion but objectively there is no benefit since they're all streamed HTTP.\r\n\r\nHence, you can only:\r\n\r\n```yaml\r\nsupergraph:\r\n    source: file\r\n    path: supergraph.graphql\r\nsubscriptions:\r\n    enabled: true\r\n```\r\n\r\nP.S. if the subscriptions are disabled, the router will respond with when receiving a subscription request:\r\n\r\n```\r\nHTTP/1.1 415 Unsupported Media Type\r\nContent-Type: application/json\r\n\r\n{\"errors\":[{\"message\":\"Subscriptions are not supported\",\"extensions\":{\"code\":\"SUBSCRIPTIONS_NOT_SUPPORT\"}}]}\r\n```\r\n\r\n# No Silent Retries & Upstream Connection Repair\r\n\r\nMost GraphQL subgraph implementations are stateless for subscriptions and have no concept of \"continuing\" from where they left off after a connection loss. Implementing retry logic on the router side would create false expectations - users would assume all events are delivered, but some would be lost when the subgraph creates a fresh subscription.\r\n\r\nThis is fundamentally why the EDFS (Event-Driven Federated Subscriptions) and callback protocols exist. To avoid misleading behavior and keep the PR focused on the core functionality, connection repair is not implemented.\r\n\r\n# TODO\r\n\r\n- [x] [documentation](https://github.com/graphql-hive/console/pull/7472)\r\n  - [ ] now with WS and HTTP callbacks\r\n  - [ ] dont forget to document that WS assembles a synthetic http request \r\n- [ ] changesets\r\n- [x] e2e tests for error handling\r\n- [x] e2e tests for header propagation\r\n- [x] use details from the actual client request for entity resolution towards subgraphs of events\r\n- [x] test subgraph disconnect propagation\r\n- [ ] use apollo's multipart http payload for transport erros\r\n- [ ] ~~test client disconnect propagation~~\r\n  - hard to test, would need changing the source code because async being state machines allows it just to stop execution in any suspended state\r\n- [ ] usage reporting (bin/router/src/pipeline/mod.rs#305)\r\n- [ ] performance considerations\r\n- [x] entity resolution failures dont end the stream, should they? a subgraph might recover, usually you dont end the whole stream. ~~**they should not end the stream**~~ actually they SHOULD because the router might not guarantee the subgraph will recover and the client might ignore the error keeping the gateway in an infinite error loop wasting resources\r\n- [ ] subscriptions deduplication (same subs same selection sets same headers)\r\n- [ ] reloading the supergraph notifies the subscribers\r\n- [ ] limits, things like client connection or event queue\r\n- [x] configure enable/disable subscriptions\r\n- [ ] ~~configure accepted protocols~~\r\n  - no need, all these here fall under \"http\" protocols and can be negotiated over http. read description\r\n- [x] stream errors when accepting only streaming content types\r\n- [ ] validate config allowing only one subscriptions transport\r\n- [ ] plugin system\r\n- [ ] remove ntex patch https://github.com/ntex-rs/ntex/pull/790 and after main is rebased because there are some other necessary refactors for latest ntex v3",
          "changed_files": 59,
          "closed_at": null,
          "comments": 3,
          "comments_url": "https://api.github.com/repos/graphql-hive/router/issues/620/comments",
          "commits": 200,
          "commits_url": "https://api.github.com/repos/graphql-hive/router/pulls/620/commits",
          "created_at": "2025-12-13T05:59:56Z",
          "deletions": 341,
          "diff_url": "https://github.com/graphql-hive/router/pull/620.diff",
          "draft": false,
          "head": {
            "label": "graphql-hive:not-kamil-subs",
            "ref": "not-kamil-subs",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 8,
              "forks_count": 8,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": true,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 58,
              "open_issues_count": 58,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-03-23T16:07:10Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 5895,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 78,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-03-21T17:31:04Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 78,
              "watchers_count": 78,
              "web_commit_signoff_required": false
            },
            "sha": "6cb2e62d38d3570fce6efdee36f86d745ca8d31d",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "html_url": "https://github.com/graphql-hive/router/pull/620",
          "id": 3098392050,
          "issue_url": "https://api.github.com/repos/graphql-hive/router/issues/620",
          "labels": [],
          "locked": false,
          "maintainer_can_modify": false,
          "merge_commit_sha": "bf93129b5b605d9e7603c79908f7b5c6ca603cef",
          "mergeable": null,
          "mergeable_state": "unknown",
          "merged": false,
          "merged_at": null,
          "merged_by": null,
          "milestone": null,
          "node_id": "PR_kwDONSTNFM64rbXy",
          "number": 620,
          "patch_url": "https://github.com/graphql-hive/router/pull/620.patch",
          "rebaseable": null,
          "requested_reviewers": [
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/3680083?v=4",
              "events_url": "https://api.github.com/users/dotansimha/events{/privacy}",
              "followers_url": "https://api.github.com/users/dotansimha/followers",
              "following_url": "https://api.github.com/users/dotansimha/following{/other_user}",
              "gists_url": "https://api.github.com/users/dotansimha/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/dotansimha",
              "id": 3680083,
              "login": "dotansimha",
              "node_id": "MDQ6VXNlcjM2ODAwODM=",
              "organizations_url": "https://api.github.com/users/dotansimha/orgs",
              "received_events_url": "https://api.github.com/users/dotansimha/received_events",
              "repos_url": "https://api.github.com/users/dotansimha/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/dotansimha/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/dotansimha/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/dotansimha",
              "user_view_type": "public"
            },
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/8167190?v=4",
              "events_url": "https://api.github.com/users/kamilkisiela/events{/privacy}",
              "followers_url": "https://api.github.com/users/kamilkisiela/followers",
              "following_url": "https://api.github.com/users/kamilkisiela/following{/other_user}",
              "gists_url": "https://api.github.com/users/kamilkisiela/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/kamilkisiela",
              "id": 8167190,
              "login": "kamilkisiela",
              "node_id": "MDQ6VXNlcjgxNjcxOTA=",
              "organizations_url": "https://api.github.com/users/kamilkisiela/orgs",
              "received_events_url": "https://api.github.com/users/kamilkisiela/received_events",
              "repos_url": "https://api.github.com/users/kamilkisiela/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/kamilkisiela/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/kamilkisiela/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/kamilkisiela",
              "user_view_type": "public"
            },
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/20847995?v=4",
              "events_url": "https://api.github.com/users/ardatan/events{/privacy}",
              "followers_url": "https://api.github.com/users/ardatan/followers",
              "following_url": "https://api.github.com/users/ardatan/following{/other_user}",
              "gists_url": "https://api.github.com/users/ardatan/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/ardatan",
              "id": 20847995,
              "login": "ardatan",
              "node_id": "MDQ6VXNlcjIwODQ3OTk1",
              "organizations_url": "https://api.github.com/users/ardatan/orgs",
              "received_events_url": "https://api.github.com/users/ardatan/received_events",
              "repos_url": "https://api.github.com/users/ardatan/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/ardatan/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/ardatan/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/ardatan",
              "user_view_type": "public"
            }
          ],
          "requested_teams": [],
          "review_comment_url": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}",
          "review_comments": 20,
          "review_comments_url": "https://api.github.com/repos/graphql-hive/router/pulls/620/comments",
          "state": "open",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/6cb2e62d38d3570fce6efdee36f86d745ca8d31d",
          "title": "feat: Subscriptions",
          "updated_at": "2026-03-23T16:07:12Z",
          "url": "https://api.github.com/repos/graphql-hive/router/pulls/620",
          "user": {
            "avatar_url": "https://avatars.githubusercontent.com/u/11807600?v=4",
            "events_url": "https://api.github.com/users/enisdenjo/events{/privacy}",
            "followers_url": "https://api.github.com/users/enisdenjo/followers",
            "following_url": "https://api.github.com/users/enisdenjo/following{/other_user}",
            "gists_url": "https://api.github.com/users/enisdenjo/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/enisdenjo",
            "id": 11807600,
            "login": "enisdenjo",
            "node_id": "MDQ6VXNlcjExODA3NjAw",
            "organizations_url": "https://api.github.com/users/enisdenjo/orgs",
            "received_events_url": "https://api.github.com/users/enisdenjo/received_events",
            "repos_url": "https://api.github.com/users/enisdenjo/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/enisdenjo/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/enisdenjo/subscriptions",
            "type": "User",
            "url": "https://api.github.com/users/enisdenjo",
            "user_view_type": "public"
          }
        },
        "repository": {
          "allow_forking": true,
          "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
          "archived": false,
          "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
          "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
          "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
          "clone_url": "https://github.com/graphql-hive/router.git",
          "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
          "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
          "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
          "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
          "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
          "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
          "created_at": "2024-11-20T16:16:12Z",
          "custom_properties": {
            "vanta_production_branch_name": "main"
          },
          "default_branch": "main",
          "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
          "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
          "disabled": false,
          "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
          "events_url": "https://api.github.com/repos/graphql-hive/router/events",
          "fork": false,
          "forks": 8,
          "forks_count": 8,
          "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
          "full_name": "graphql-hive/router",
          "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
          "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
          "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
          "git_url": "git://github.com/graphql-hive/router.git",
          "has_discussions": false,
          "has_downloads": true,
          "has_issues": true,
          "has_pages": false,
          "has_projects": false,
          "has_pull_requests": true,
          "has_wiki": false,
          "homepage": "https://the-guild.dev/graphql/hive/docs/router",
          "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
          "html_url": "https://github.com/graphql-hive/router",
          "id": 891604244,
          "is_template": false,
          "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
          "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
          "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
          "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
          "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
          "language": "Rust",
          "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
          "license": {
            "key": "mit",
            "name": "MIT License",
            "node_id": "MDc6TGljZW5zZTEz",
            "spdx_id": "MIT",
            "url": "https://api.github.com/licenses/mit"
          },
          "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
          "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
          "mirror_url": null,
          "name": "router",
          "node_id": "R_kgDONSTNFA",
          "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
          "open_issues": 58,
          "open_issues_count": 58,
          "owner": {
            "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
            "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
            "followers_url": "https://api.github.com/users/graphql-hive/followers",
            "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
            "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/graphql-hive",
            "id": 182742256,
            "login": "graphql-hive",
            "node_id": "O_kgDOCuRs8A",
            "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
            "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
            "repos_url": "https://api.github.com/users/graphql-hive/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
            "type": "Organization",
            "url": "https://api.github.com/users/graphql-hive",
            "user_view_type": "public"
          },
          "private": false,
          "pull_request_creation_policy": "all",
          "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
          "pushed_at": "2026-03-23T16:07:10Z",
          "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
          "size": 5895,
          "ssh_url": "git@github.com:graphql-hive/router.git",
          "stargazers_count": 78,
          "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
          "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
          "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
          "svn_url": "https://github.com/graphql-hive/router",
          "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
          "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
          "topics": [
            "apollo-federation",
            "federation",
            "federation-gateway",
            "graphql",
            "graphql-federation",
            "router"
          ],
          "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
          "updated_at": "2026-03-21T17:31:04Z",
          "url": "https://api.github.com/repos/graphql-hive/router",
          "visibility": "public",
          "watchers": 78,
          "watchers_count": 78,
          "web_commit_signoff_required": false
        },
        "sender": {
          "avatar_url": "https://avatars.githubusercontent.com/u/11807600?v=4",
          "events_url": "https://api.github.com/users/enisdenjo/events{/privacy}",
          "followers_url": "https://api.github.com/users/enisdenjo/followers",
          "following_url": "https://api.github.com/users/enisdenjo/following{/other_user}",
          "gists_url": "https://api.github.com/users/enisdenjo/gists{/gist_id}",
          "gravatar_id": "",
          "html_url": "https://github.com/enisdenjo",
          "id": 11807600,
          "login": "enisdenjo",
          "node_id": "MDQ6VXNlcjExODA3NjAw",
          "organizations_url": "https://api.github.com/users/enisdenjo/orgs",
          "received_events_url": "https://api.github.com/users/enisdenjo/received_events",
          "repos_url": "https://api.github.com/users/enisdenjo/repos",
          "site_admin": false,
          "starred_url": "https://api.github.com/users/enisdenjo/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/enisdenjo/subscriptions",
          "type": "User",
          "url": "https://api.github.com/users/enisdenjo",
          "user_view_type": "public"
        }
      },
      "github_job": "docker",
      "github_ref": "refs/pull/620/merge",
      "github_ref_name": "620/merge",
      "github_ref_protected": "false",
      "github_ref_type": "branch",
      "github_repository": "graphql-hive/router",
      "github_repository_id": "891604244",
      "github_repository_owner": "graphql-hive",
      "github_repository_owner_id": "182742256",
      "github_run_attempt": "1",
      "github_run_id": "23447240895",
      "github_run_number": "2067",
      "github_runner_arch": "X64",
      "github_runner_environment": "github-hosted",
      "github_runner_image_os": "ubuntu24",
      "github_runner_image_version": "20260309.50.1",
      "github_runner_name": "GitHub Actions 1000682180",
      "github_runner_os": "Linux",
      "github_runner_tracking_id": "github_8291d775-1d94-4e70-8613-a53b43c008df",
      "github_server_url": "https://github.com",
      "github_triggering_actor": "enisdenjo",
      "github_workflow": "build-router",
      "github_workflow_ref": "graphql-hive/router/.github/workflows/build-router.yaml@refs/pull/620/merge",
      "github_workflow_sha": "5b300c5ef067668ed53d0d7d90058088f3ba5976",
      "platform": "linux/amd64"
    }
  }
},
"buildx.build.provenance/linux/arm64": {
  "builder": {
    "id": "https://github.com/graphql-hive/router/actions/runs/23447240895/attempts/1"
  },
  "buildType": "https://mobyproject.org/buildkit@v1",
  "materials": [
    {
      "uri": "pkg:docker/docker/dockerfile@1.22",
      "digest": {
        "sha256": "4a43a54dd1fedceb30ba47e76cfcf2b47304f4161c0caeac2db1c61804ea3c91"
      }
    },
    {
      "uri": "pkg:docker/gcr.io/distroless/cc-debian12@latest?platform=linux%2Farm64",
      "digest": {
        "sha256": "329e54034ce498f9c6b345044e8f530c6691f99e94a92446f68c0adf9baa8464"
      }
    }
  ],
  "invocation": {
    "configSource": {
      "entryPoint": "router.Dockerfile"
    },
    "parameters": {
      "frontend": "gateway.v0",
      "args": {
        "cmdline": "docker/dockerfile:1.22",
        "label:org.opencontainers.image.created": "2026-03-23T16:19:58.482Z",
        "label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
        "label:org.opencontainers.image.licenses": "MIT",
        "label:org.opencontainers.image.revision": "5b300c5ef067668ed53d0d7d90058088f3ba5976",
        "label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.title": "router",
        "label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.vendor": "theguild",
        "label:org.opencontainers.image.version": "pr-620",
        "source": "docker/dockerfile:1.22"
      },
      "locals": [
        {
          "name": "context"
        },
        {
          "name": "dockerfile"
        }
      ]
    },
    "environment": {
      "github_actor": "enisdenjo",
      "github_actor_id": "11807600",
      "github_event_name": "pull_request",
      "github_event_payload": {
        "action": "synchronize",
        "after": "6cb2e62d38d3570fce6efdee36f86d745ca8d31d",
        "before": "f1e9e1e3386eeddc6f86966ec2ed2e3de189145d",
        "enterprise": {
          "avatar_url": "https://avatars.githubusercontent.com/b/187753?v=4",
          "created_at": "2024-07-02T08:52:28Z",
          "description": "",
          "html_url": "https://github.com/enterprises/the-guild",
          "id": 187753,
          "name": "The Guild",
          "node_id": "E_kgDOAALdaQ",
          "slug": "the-guild",
          "updated_at": "2026-03-11T16:47:15Z",
          "website_url": "https://the-guild.dev/"
        },
        "number": 620,
        "organization": {
          "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
          "description": "Schema registry, analytics and gateway for GraphQL federation and other GraphQL APIs.",
          "events_url": "https://api.github.com/orgs/graphql-hive/events",
          "hooks_url": "https://api.github.com/orgs/graphql-hive/hooks",
          "id": 182742256,
          "issues_url": "https://api.github.com/orgs/graphql-hive/issues",
          "login": "graphql-hive",
          "members_url": "https://api.github.com/orgs/graphql-hive/members{/member}",
          "node_id": "O_kgDOCuRs8A",
          "public_members_url": "https://api.github.com/orgs/graphql-hive/public_members{/member}",
          "repos_url": "https://api.github.com/orgs/graphql-hive/repos",
          "url": "https://api.github.com/orgs/graphql-hive"
        },
        "pull_request": {
          "_links": {
            "comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/620/comments"
            },
            "commits": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/620/commits"
            },
            "html": {
              "href": "https://github.com/graphql-hive/router/pull/620"
            },
            "issue": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/620"
            },
            "review_comment": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}"
            },
            "review_comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/620/comments"
            },
            "self": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/620"
            },
            "statuses": {
              "href": "https://api.github.com/repos/graphql-hive/router/statuses/6cb2e62d38d3570fce6efdee36f86d745ca8d31d"
            }
          },
          "active_lock_reason": null,
          "additions": 8456,
          "assignee": null,
          "assignees": [],
          "author_association": "MEMBER",
          "auto_merge": null,
          "base": {
            "label": "graphql-hive:main",
            "ref": "main",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 8,
              "forks_count": 8,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": true,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 58,
              "open_issues_count": 58,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-03-23T16:07:10Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 5895,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 78,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-03-21T17:31:04Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 78,
              "watchers_count": 78,
              "web_commit_signoff_required": false
            },
            "sha": "72cf0ec5dc15f3540814a753fb4871ea2107054c",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "body": "Closes #313 \r\nRef router-165\r\n\r\nImplement [SSE](https://github.com/enisdenjo/graphql-sse/blob/918b9d414a4f938c715a8f8bc13184c0849eac50/PROTOCOL.md#distinct-connections-mode), [Incremental Delivery over HTTP](https://github.com/graphql/graphql-over-http/blob/d312e43384006fa323b918d49cfd9fbd76ac1257/rfcs/IncrementalDelivery.md), [Apollo's Multipart HTTP](https://www.apollographql.com/docs/graphos/routing/operations/subscriptions/multipart-protocol), [WebSocket](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) and [HTTP Callback](https://www.apollographql.com/docs/graphos/routing/operations/subscriptions/callback-protocol) specs for subscriptions when communicating with subgraphs or clients with entity resolution capabilities.\r\n\r\n\r\n# Streaming execution result\r\n\r\n```\r\nlib/executor/src/execution/plan.rs@QueryPlanExecutionResult\r\n```\r\n\r\nThe execution pipeline now returns `QueryPlanExecutionResult` - an enum that can be either a single response or a stream:\r\n\r\n```rust\r\npub enum QueryPlanExecutionResult {\r\n    Single(PlanExecutionOutput),\r\n    Stream(PlanSubscriptionOutput),\r\n}\r\n```\r\n\r\nThis separation allows the query planner and executor to operate independently from transport concerns, making future improvements (like connection repair and silent retries) easier to implement.\r\n\r\n# Owned query plan execution context values for streaming\r\n\r\n```\r\nlib/executor/src/execution/plan.rs\r\n```\r\n\r\nSubscriptions require long-lived contexts that outlive request lifetimes, so we clone all of the necessary context values:\r\n\r\n- `Arc`-wrapped shared data\r\n- Enables entity resolution to happen independently for each subscription event\r\n- Processes remaining plan nodes after the subscription fetch\r\n\r\n## Avoid deep clones of shared data on every subscription setup\r\n\r\n`QueryPlanExecutionOpts` received `executors`, `projection_plan`, `headers_plan`, and `schema_metadata` as borrowed references. The subscription stream closure requires `'static` data, so these were deep-cloned into `Arc` on every subscription setup:\r\n\r\n```rust\r\nlet executors: Arc<SubgraphExecutorMap> = opts.executors.clone().into();\r\nlet projection_plan: Arc<Vec<FieldProjectionPlan>> = opts.projection_plan.clone().into();\r\nlet headers_plan: Arc<HeaderRulesPlan> = opts.headers_plan.clone().into();\r\nlet schema_metadata: Arc<SchemaMetadata> = Arc::new(opts.introspection_context.metadata.clone());\r\n```\r\n\r\n`SubgraphExecutorMap` contains multiple `DashMap`s, making its clone particularly expensive.\r\n\r\nWrapped `SupergraphData.subgraph_executor_map`, `SupergraphData.metadata`, and `RouterSharedState.headers_plan` in `Arc` at the source and threaded them through `QueryPlanExecutionOpts` and `IntrospectionContext` as `Arc` instead of borrowed references. `projection_plan` was already `Arc` at the source but was dereffed to a borrow before reaching `QueryPlanExecutionOpts`, now passed as `Arc` directly. The subscription path now does cheap ref-count bumps. The query/mutation path just derefs.\r\n\r\n# Subscription handlers\r\n\r\nThe router respects the client's `Accept` header to determine response format:\r\n\r\n- `text/event-stream` → SSE responses\r\n- `multipart/mixed` → Incremental Delivery over HTTP\r\n- `multipart/mixed;subscriptionSpec=\"1.0\"` → Apollo multipart HTTP\r\n- Returns `406 Not Acceptable` if subscription is requested over unsupported transport\r\n- Handles errors by emitting an error event and completing the stream\r\n- Heartbeats every 10 seconds (except for incremental delivery, doesn't have it)\r\n- Of course protocols used between router and subgraphs and clients can be different\r\n\r\nSame behavior is expected when communicating with subgraphs.\r\n\r\n## SSE\r\n\r\n```\r\nlib/executor/src/executors/sse.rs\r\n```\r\n\r\nImplements the [GraphQL over SSE spec distinct connection mode](https://github.com/enisdenjo/graphql-sse/blob/918b9d414a4f938c715a8f8bc13184c0849eac50/PROTOCOL.md#distinct-connections-mode).\r\n\r\n## Multipart protocol\r\n\r\n```\r\nlib/executor/src/executors/multipart_subscribe.rs\r\n```\r\n\r\nImplements [Apollo's multipart HTTP spec](https://www.apollographql.com/docs/graphos/routing/operations/subscriptions/multipart-protocol) and [GraphQL's Incremental Delivery over HTTP RFC](https://github.com/graphql/graphql-over-http/blob/d312e43384006fa323b918d49cfd9fbd76ac1257/rfcs/IncrementalDelivery.md).\r\n\r\n# WebSockets\r\n\r\nRead stacked PR #738\r\n\r\n## Plugin system\r\n\r\nThe WS server assembles a synthetic http request for every ws operation message allowing the plugin system to run as usual for the supported execution paths. (No subscriptions because the plugin system generally does not support subscriptions - yet).\r\n\r\n# HTTP Callbacks\r\n\r\nRead stacked PR #831 \r\n\r\n# Entity resolution\r\n\r\n```\r\nlib/executor/src/execution/plan.rs@execute_query_plan\r\n```\r\n\r\nWhen a subscription emits data that references entities from other subgraphs, the router:\r\n\r\n1. Receives subscription event from primary subgraph\r\n2. Executes remaining plan nodes (flatten, fetch, etc.) to populate missing fields\r\n3. Projects the complete response\r\n4. Streams the full response to client\r\n\r\n# Subscription node in query plan\r\n\r\nIn PlanNode::from_fetch_step in `plan_nodes.rs`, when building a node from a fetch step, if the step has no response path and its operation kind is Subscription, it now directly produces a PlanNode::Subscription instead of PlanNode::Fetch.\r\n\r\n# Subgraph executor subscribe method\r\n\r\n```\r\nlib/executor/src/executors/common.rs@subscribe\r\n```\r\n\r\nThe HTTP executor gains a `subscribe()` method that:\r\n\r\n- Negotiates content-type (prefers multipart, falls back to SSE)\r\n- Establishes long-lived connections to subgraphs\r\n- Returns a `BoxStream<HttpExecutionResponse>` for downstream processing\r\n\r\n# Configure to only enable/disable subscriptions\r\n\r\nThe supported subscription protocols in this PR are inherintly HTTP and do not need a \"protocol\" configuration option. Hive Router will send an accept header listing all supported protocols for subscriptions over HTTP and the subgraph is free to choose whichever one it supports.\r\n\r\nWhether we really _want_ to limit specific protocols is up to discussion but objectively there is no benefit since they're all streamed HTTP.\r\n\r\nHence, you can only:\r\n\r\n```yaml\r\nsupergraph:\r\n    source: file\r\n    path: supergraph.graphql\r\nsubscriptions:\r\n    enabled: true\r\n```\r\n\r\nP.S. if the subscriptions are disabled, the router will respond with when receiving a subscription request:\r\n\r\n```\r\nHTTP/1.1 415 Unsupported Media Type\r\nContent-Type: application/json\r\n\r\n{\"errors\":[{\"message\":\"Subscriptions are not supported\",\"extensions\":{\"code\":\"SUBSCRIPTIONS_NOT_SUPPORT\"}}]}\r\n```\r\n\r\n# No Silent Retries & Upstream Connection Repair\r\n\r\nMost GraphQL subgraph implementations are stateless for subscriptions and have no concept of \"continuing\" from where they left off after a connection loss. Implementing retry logic on the router side would create false expectations - users would assume all events are delivered, but some would be lost when the subgraph creates a fresh subscription.\r\n\r\nThis is fundamentally why the EDFS (Event-Driven Federated Subscriptions) and callback protocols exist. To avoid misleading behavior and keep the PR focused on the core functionality, connection repair is not implemented.\r\n\r\n# TODO\r\n\r\n- [x] [documentation](https://github.com/graphql-hive/console/pull/7472)\r\n  - [ ] now with WS and HTTP callbacks\r\n  - [ ] dont forget to document that WS assembles a synthetic http request \r\n- [ ] changesets\r\n- [x] e2e tests for error handling\r\n- [x] e2e tests for header propagation\r\n- [x] use details from the actual client request for entity resolution towards subgraphs of events\r\n- [x] test subgraph disconnect propagation\r\n- [ ] use apollo's multipart http payload for transport erros\r\n- [ ] ~~test client disconnect propagation~~\r\n  - hard to test, would need changing the source code because async being state machines allows it just to stop execution in any suspended state\r\n- [ ] usage reporting (bin/router/src/pipeline/mod.rs#305)\r\n- [ ] performance considerations\r\n- [x] entity resolution failures dont end the stream, should they? a subgraph might recover, usually you dont end the whole stream. ~~**they should not end the stream**~~ actually they SHOULD because the router might not guarantee the subgraph will recover and the client might ignore the error keeping the gateway in an infinite error loop wasting resources\r\n- [ ] subscriptions deduplication (same subs same selection sets same headers)\r\n- [ ] reloading the supergraph notifies the subscribers\r\n- [ ] limits, things like client connection or event queue\r\n- [x] configure enable/disable subscriptions\r\n- [ ] ~~configure accepted protocols~~\r\n  - no need, all these here fall under \"http\" protocols and can be negotiated over http. read description\r\n- [x] stream errors when accepting only streaming content types\r\n- [ ] validate config allowing only one subscriptions transport\r\n- [ ] plugin system\r\n- [ ] remove ntex patch https://github.com/ntex-rs/ntex/pull/790 and after main is rebased because there are some other necessary refactors for latest ntex v3",
          "changed_files": 59,
          "closed_at": null,
          "comments": 3,
          "comments_url": "https://api.github.com/repos/graphql-hive/router/issues/620/comments",
          "commits": 200,
          "commits_url": "https://api.github.com/repos/graphql-hive/router/pulls/620/commits",
          "created_at": "2025-12-13T05:59:56Z",
          "deletions": 341,
          "diff_url": "https://github.com/graphql-hive/router/pull/620.diff",
          "draft": false,
          "head": {
            "label": "graphql-hive:not-kamil-subs",
            "ref": "not-kamil-subs",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 8,
              "forks_count": 8,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": true,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 58,
              "open_issues_count": 58,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-03-23T16:07:10Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 5895,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 78,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-03-21T17:31:04Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 78,
              "watchers_count": 78,
              "web_commit_signoff_required": false
            },
            "sha": "6cb2e62d38d3570fce6efdee36f86d745ca8d31d",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "html_url": "https://github.com/graphql-hive/router/pull/620",
          "id": 3098392050,
          "issue_url": "https://api.github.com/repos/graphql-hive/router/issues/620",
          "labels": [],
          "locked": false,
          "maintainer_can_modify": false,
          "merge_commit_sha": "bf93129b5b605d9e7603c79908f7b5c6ca603cef",
          "mergeable": null,
          "mergeable_state": "unknown",
          "merged": false,
          "merged_at": null,
          "merged_by": null,
          "milestone": null,
          "node_id": "PR_kwDONSTNFM64rbXy",
          "number": 620,
          "patch_url": "https://github.com/graphql-hive/router/pull/620.patch",
          "rebaseable": null,
          "requested_reviewers": [
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/3680083?v=4",
              "events_url": "https://api.github.com/users/dotansimha/events{/privacy}",
              "followers_url": "https://api.github.com/users/dotansimha/followers",
              "following_url": "https://api.github.com/users/dotansimha/following{/other_user}",
              "gists_url": "https://api.github.com/users/dotansimha/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/dotansimha",
              "id": 3680083,
              "login": "dotansimha",
              "node_id": "MDQ6VXNlcjM2ODAwODM=",
              "organizations_url": "https://api.github.com/users/dotansimha/orgs",
              "received_events_url": "https://api.github.com/users/dotansimha/received_events",
              "repos_url": "https://api.github.com/users/dotansimha/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/dotansimha/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/dotansimha/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/dotansimha",
              "user_view_type": "public"
            },
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/8167190?v=4",
              "events_url": "https://api.github.com/users/kamilkisiela/events{/privacy}",
              "followers_url": "https://api.github.com/users/kamilkisiela/followers",
              "following_url": "https://api.github.com/users/kamilkisiela/following{/other_user}",
              "gists_url": "https://api.github.com/users/kamilkisiela/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/kamilkisiela",
              "id": 8167190,
              "login": "kamilkisiela",
              "node_id": "MDQ6VXNlcjgxNjcxOTA=",
              "organizations_url": "https://api.github.com/users/kamilkisiela/orgs",
              "received_events_url": "https://api.github.com/users/kamilkisiela/received_events",
              "repos_url": "https://api.github.com/users/kamilkisiela/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/kamilkisiela/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/kamilkisiela/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/kamilkisiela",
              "user_view_type": "public"
            },
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/20847995?v=4",
              "events_url": "https://api.github.com/users/ardatan/events{/privacy}",
              "followers_url": "https://api.github.com/users/ardatan/followers",
              "following_url": "https://api.github.com/users/ardatan/following{/other_user}",
              "gists_url": "https://api.github.com/users/ardatan/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/ardatan",
              "id": 20847995,
              "login": "ardatan",
              "node_id": "MDQ6VXNlcjIwODQ3OTk1",
              "organizations_url": "https://api.github.com/users/ardatan/orgs",
              "received_events_url": "https://api.github.com/users/ardatan/received_events",
              "repos_url": "https://api.github.com/users/ardatan/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/ardatan/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/ardatan/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/ardatan",
              "user_view_type": "public"
            }
          ],
          "requested_teams": [],
          "review_comment_url": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}",
          "review_comments": 20,
          "review_comments_url": "https://api.github.com/repos/graphql-hive/router/pulls/620/comments",
          "state": "open",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/6cb2e62d38d3570fce6efdee36f86d745ca8d31d",
          "title": "feat: Subscriptions",
          "updated_at": "2026-03-23T16:07:12Z",
          "url": "https://api.github.com/repos/graphql-hive/router/pulls/620",
          "user": {
            "avatar_url": "https://avatars.githubusercontent.com/u/11807600?v=4",
            "events_url": "https://api.github.com/users/enisdenjo/events{/privacy}",
            "followers_url": "https://api.github.com/users/enisdenjo/followers",
            "following_url": "https://api.github.com/users/enisdenjo/following{/other_user}",
            "gists_url": "https://api.github.com/users/enisdenjo/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/enisdenjo",
            "id": 11807600,
            "login": "enisdenjo",
            "node_id": "MDQ6VXNlcjExODA3NjAw",
            "organizations_url": "https://api.github.com/users/enisdenjo/orgs",
            "received_events_url": "https://api.github.com/users/enisdenjo/received_events",
            "repos_url": "https://api.github.com/users/enisdenjo/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/enisdenjo/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/enisdenjo/subscriptions",
            "type": "User",
            "url": "https://api.github.com/users/enisdenjo",
            "user_view_type": "public"
          }
        },
        "repository": {
          "allow_forking": true,
          "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
          "archived": false,
          "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
          "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
          "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
          "clone_url": "https://github.com/graphql-hive/router.git",
          "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
          "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
          "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
          "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
          "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
          "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
          "created_at": "2024-11-20T16:16:12Z",
          "custom_properties": {
            "vanta_production_branch_name": "main"
          },
          "default_branch": "main",
          "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
          "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
          "disabled": false,
          "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
          "events_url": "https://api.github.com/repos/graphql-hive/router/events",
          "fork": false,
          "forks": 8,
          "forks_count": 8,
          "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
          "full_name": "graphql-hive/router",
          "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
          "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
          "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
          "git_url": "git://github.com/graphql-hive/router.git",
          "has_discussions": false,
          "has_downloads": true,
          "has_issues": true,
          "has_pages": false,
          "has_projects": false,
          "has_pull_requests": true,
          "has_wiki": false,
          "homepage": "https://the-guild.dev/graphql/hive/docs/router",
          "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
          "html_url": "https://github.com/graphql-hive/router",
          "id": 891604244,
          "is_template": false,
          "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
          "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
          "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
          "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
          "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
          "language": "Rust",
          "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
          "license": {
            "key": "mit",
            "name": "MIT License",
            "node_id": "MDc6TGljZW5zZTEz",
            "spdx_id": "MIT",
            "url": "https://api.github.com/licenses/mit"
          },
          "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
          "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
          "mirror_url": null,
          "name": "router",
          "node_id": "R_kgDONSTNFA",
          "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
          "open_issues": 58,
          "open_issues_count": 58,
          "owner": {
            "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
            "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
            "followers_url": "https://api.github.com/users/graphql-hive/followers",
            "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
            "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/graphql-hive",
            "id": 182742256,
            "login": "graphql-hive",
            "node_id": "O_kgDOCuRs8A",
            "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
            "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
            "repos_url": "https://api.github.com/users/graphql-hive/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
            "type": "Organization",
            "url": "https://api.github.com/users/graphql-hive",
            "user_view_type": "public"
          },
          "private": false,
          "pull_request_creation_policy": "all",
          "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
          "pushed_at": "2026-03-23T16:07:10Z",
          "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
          "size": 5895,
          "ssh_url": "git@github.com:graphql-hive/router.git",
          "stargazers_count": 78,
          "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
          "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
          "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
          "svn_url": "https://github.com/graphql-hive/router",
          "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
          "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
          "topics": [
            "apollo-federation",
            "federation",
            "federation-gateway",
            "graphql",
            "graphql-federation",
            "router"
          ],
          "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
          "updated_at": "2026-03-21T17:31:04Z",
          "url": "https://api.github.com/repos/graphql-hive/router",
          "visibility": "public",
          "watchers": 78,
          "watchers_count": 78,
          "web_commit_signoff_required": false
        },
        "sender": {
          "avatar_url": "https://avatars.githubusercontent.com/u/11807600?v=4",
          "events_url": "https://api.github.com/users/enisdenjo/events{/privacy}",
          "followers_url": "https://api.github.com/users/enisdenjo/followers",
          "following_url": "https://api.github.com/users/enisdenjo/following{/other_user}",
          "gists_url": "https://api.github.com/users/enisdenjo/gists{/gist_id}",
          "gravatar_id": "",
          "html_url": "https://github.com/enisdenjo",
          "id": 11807600,
          "login": "enisdenjo",
          "node_id": "MDQ6VXNlcjExODA3NjAw",
          "organizations_url": "https://api.github.com/users/enisdenjo/orgs",
          "received_events_url": "https://api.github.com/users/enisdenjo/received_events",
          "repos_url": "https://api.github.com/users/enisdenjo/repos",
          "site_admin": false,
          "starred_url": "https://api.github.com/users/enisdenjo/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/enisdenjo/subscriptions",
          "type": "User",
          "url": "https://api.github.com/users/enisdenjo",
          "user_view_type": "public"
        }
      },
      "github_job": "docker",
      "github_ref": "refs/pull/620/merge",
      "github_ref_name": "620/merge",
      "github_ref_protected": "false",
      "github_ref_type": "branch",
      "github_repository": "graphql-hive/router",
      "github_repository_id": "891604244",
      "github_repository_owner": "graphql-hive",
      "github_repository_owner_id": "182742256",
      "github_run_attempt": "1",
      "github_run_id": "23447240895",
      "github_run_number": "2067",
      "github_runner_arch": "X64",
      "github_runner_environment": "github-hosted",
      "github_runner_image_os": "ubuntu24",
      "github_runner_image_version": "20260309.50.1",
      "github_runner_name": "GitHub Actions 1000682180",
      "github_runner_os": "Linux",
      "github_runner_tracking_id": "github_8291d775-1d94-4e70-8613-a53b43c008df",
      "github_server_url": "https://github.com",
      "github_triggering_actor": "enisdenjo",
      "github_workflow": "build-router",
      "github_workflow_ref": "graphql-hive/router/.github/workflows/build-router.yaml@refs/pull/620/merge",
      "github_workflow_sha": "5b300c5ef067668ed53d0d7d90058088f3ba5976",
      "platform": "linux/amd64"
    }
  }
},
"buildx.build.ref": "builder-e7be889d-796a-4da0-a657-80971e1cbb89/builder-e7be889d-796a-4da0-a657-80971e1cbb890/520u3dkxvkvlmo5vx2ackvwi1",
"containerimage.descriptor": {
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "digest": "sha256:b3f3e459270a807e8053a8d2c73f6854a0c343b750aa67212355b5274f964949",
  "size": 1609
},
"containerimage.digest": "sha256:b3f3e459270a807e8053a8d2c73f6854a0c343b750aa67212355b5274f964949",
"image.name": "ghcr.io/graphql-hive/router:pr-620,ghcr.io/graphql-hive/router:sha-5b300c5"
}

pub struct SubscriptionNode {
pub primary: Box<PlanNode>, // Use Box to prevent size issues
// A subscription node can only really have a primary fetch node.
pub primary: FetchNode,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FetchNode is a concrete type and not an enum so I dropped the box because the compiler will know the size. Right?

@enisdenjo enisdenjo marked this pull request as ready for review March 19, 2026 21:39
@enisdenjo enisdenjo requested a review from ardatan March 19, 2026 21:51
ardatan and others added 2 commits March 24, 2026 19:33
Co-authored-by: Denis Badurina <denis@denelop.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: GraphQL Subscriptions

3 participants