Skip to content

Conversation

@dkorittki
Copy link
Contributor

@dkorittki dkorittki commented Nov 28, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Improved delivery of errors for GraphQL subscriptions over SSE and WebSocket, ensuring downstream errors are flushed and subscriptions are properly completed.
    • Ensured HTTP response streams are flushed reliably to complete SSE/HTTP responses.
  • Tests

    • Added test coverage for SSE subscription error scenarios, verifying error delivery sequence and earlier response body closure.

✏️ Tip: You can customize this high-level summary in your review settings.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/cosmo-docs.
  • I have read the Contributors Guide.

When we write errors to a connection backed by HttpFlushWriter (used on subscriptions via SSE/Multipart) we do not flush the connection as oposed to a websocket connection, where this actually happens. I fixed it by simply checking if we are dealing with a flush writer and flush if so. Added a test to back this up.

@coderabbitai
Copy link

coderabbitai bot commented Nov 28, 2025

Walkthrough

Moved an early HTTP response body close in an SSE subscription test, added an SSE subtest asserting error propagation when a subgraph returns 403, added an HTTP flush branch in GraphQLHandler.WriteError, and ensured subscription error writes flush and mark completion in executeSubscription.

Changes

Cohort / File(s) Summary
SSE test & new subtest
router-tests/http_subscriptions_test.go
Moved resp.Body.Close() to immediately after the HTTP request. Added subtest "should write an error on sse" that configures a subgraph to return HTTP 403 with a JSON error, sends a GraphQL subscription over SSE, reads raw SSE lines, and asserts an event: next line, an error data: line containing Subscription Upgrade request failed with statusCode 403, followed by two blank lines.
GraphQL handler flush path
router/core/graphql_handler.go
In GraphQLHandler.WriteError, after flushing the websocket writer, added a conditional branch to call Flush() on an HttpFlushWriter so HTTP writers are flushed similarly. No change to error payloads.
Subscription error finalization
router/core/websocket.go
In executeSubscription, after writing a subscription resolution error, added a flush of the response writer and a call to mark the subscription as complete instead of returning immediately.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check SSE test assertions for platform-dependent newline/blank-line behavior and raw SSE parsing.
  • Verify the exact error message/JSON emitted by the mocked subgraph matches the test expectation.
  • Ensure HttpFlushWriter.Flush() ordering is correct and does not introduce races with websocket flushes or connection teardown.
  • Confirm executeSubscription's added completion call doesn't affect metrics, cleanup, or downstream lifecycle hooks.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: ensuring errors are flushed on SSE (Server-Sent Events) streams in the router.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Nov 28, 2025

Router image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-7a0496b0fcc1c199982273d0ea1c4cf997a866c5

@codecov
Copy link

codecov bot commented Nov 28, 2025

Codecov Report

❌ Patch coverage is 50.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.55%. Comparing base (a53bb35) to head (1973c6c).
⚠️ Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
router/core/websocket.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2377       +/-   ##
===========================================
+ Coverage   42.75%   61.55%   +18.79%     
===========================================
  Files        1030      229      -801     
  Lines      142648    23816   -118832     
  Branches     8660        0     -8660     
===========================================
- Hits        60984    14659    -46325     
+ Misses      79997     7919    -72078     
+ Partials     1667     1238      -429     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dkorittki
Copy link
Contributor Author

Does Codecov recognize that tests have been added to the router-tests package? Seems like not.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
router-tests/http_subscriptions_test.go (1)

202-268: Consider verifying stream completion after the error.

The successful SSE test explicitly checks for an "event: complete" message (line 186), but this error test ends after asserting the two blank lines without verifying whether a completion event is sent or whether the stream closes cleanly with no further messages. Consider adding an assertion to confirm the expected stream termination behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8275f and 4510955.

📒 Files selected for processing (1)
  • router-tests/http_subscriptions_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:17-55
Timestamp: 2025-08-28T09:17:49.477Z
Learning: The Cosmo router uses a custom, intentionally rigid multipart implementation for GraphQL subscriptions. The multipart parsing in test files should remain strict and not be made more tolerant, as this rigidity is by design.
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2273
File: router/core/graphql_handler.go:0-0
Timestamp: 2025-11-19T15:13:57.821Z
Learning: In the Cosmo router (wundergraph/cosmo), error handling follows a two-phase pattern: (1) Prehandler phase handles request parsing, validation, and setup errors using `httpGraphqlError` and `writeOperationError` (in files like graphql_prehandler.go, operation_processor.go, parse_multipart.go, batch.go); (2) Execution phase handles resolver execution errors using `WriteError` in GraphQLHandler.ServeHTTP. Because all `httpGraphqlError` instances are caught in the prehandler before ServeHTTP is invoked, any error type checks for `httpGraphqlError` in the execution-phase WriteError method are unreachable code.
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:100-108
Timestamp: 2025-08-28T09:18:10.121Z
Learning: In router-tests/http_subscriptions_test.go heartbeat tests, the message ordering should remain strict with data messages followed by heartbeat messages, as the timing is deterministic and known by design in the Cosmo router implementation.
📚 Learning: 2025-08-28T09:18:10.121Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:100-108
Timestamp: 2025-08-28T09:18:10.121Z
Learning: In router-tests/http_subscriptions_test.go heartbeat tests, the message ordering should remain strict with data messages followed by heartbeat messages, as the timing is deterministic and known by design in the Cosmo router implementation.

Applied to files:

  • router-tests/http_subscriptions_test.go
📚 Learning: 2025-10-01T20:39:16.113Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2252
File: router-tests/telemetry/telemetry_test.go:9684-9693
Timestamp: 2025-10-01T20:39:16.113Z
Learning: Repo preference: In router-tests/telemetry/telemetry_test.go, keep strict > 0 assertions for request.operation.*Time (parsingTime, normalizationTime, validationTime, planningTime) in telemetry-related tests; do not relax to >= 0 unless CI flakiness is observed.

Applied to files:

  • router-tests/http_subscriptions_test.go
📚 Learning: 2025-08-20T10:08:17.857Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2155
File: router/core/router.go:1857-1866
Timestamp: 2025-08-20T10:08:17.857Z
Learning: router/pkg/config/config.schema.json forbids null values for traffic_shaping.subgraphs: additionalProperties references $defs.traffic_shaping_subgraph_request_rule with type "object". Therefore, in core.NewSubgraphTransportOptions, dereferencing each subgraph rule pointer is safe under schema-validated configs, and a nil-check is unnecessary.

Applied to files:

  • router-tests/http_subscriptions_test.go
📚 Learning: 2025-09-17T20:55:39.456Z
Learnt from: SkArchon
Repo: wundergraph/cosmo PR: 2172
File: router/core/graph_server.go:0-0
Timestamp: 2025-09-17T20:55:39.456Z
Learning: The Initialize method in router/internal/retrytransport/manager.go has been updated to properly handle feature-flag-only subgraphs by collecting subgraphs from both routerConfig.GetSubgraphs() and routerConfig.FeatureFlagConfigs.ConfigByFeatureFlagName, ensuring all subgraphs receive retry configuration.

Applied to files:

  • router-tests/http_subscriptions_test.go
📚 Learning: 2025-11-19T15:13:57.821Z
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2273
File: router/core/graphql_handler.go:0-0
Timestamp: 2025-11-19T15:13:57.821Z
Learning: In the Cosmo router (wundergraph/cosmo), error handling follows a two-phase pattern: (1) Prehandler phase handles request parsing, validation, and setup errors using `httpGraphqlError` and `writeOperationError` (in files like graphql_prehandler.go, operation_processor.go, parse_multipart.go, batch.go); (2) Execution phase handles resolver execution errors using `WriteError` in GraphQLHandler.ServeHTTP. Because all `httpGraphqlError` instances are caught in the prehandler before ServeHTTP is invoked, any error type checks for `httpGraphqlError` in the execution-phase WriteError method are unreachable code.

Applied to files:

  • router-tests/http_subscriptions_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-router
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: image_scan
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: build_test
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
router-tests/http_subscriptions_test.go (3)

139-139: Good resource management practice.

Moving the defer immediately after acquiring the response ensures proper cleanup even if subsequent assertions fail.


202-268: Test effectively validates error propagation over SSE streams.

The test structure mirrors the successful SSE test appropriately and correctly simulates a subgraph error scenario. The middleware configuration and SSE parsing logic are sound.


260-266: SSE error responses end with two blank lines instead of one, creating an asymmetry with successful messages.

The test at lines 260-266 expects two consecutive blank lines after the error message. In contrast, successful SSE messages (lines 171, 181, 197), heartbeat events, and complete events all terminate with a single blank line. The error path writes event: next\ndata: followed by requestErrors.WriteResponse(w), then Flush(), while successful responses go through HttpFlushWriter with explicit \n\n separation. Verify whether this two-blank-line termination for errors is intentional per the GraphQL-core SSE specification or if the error response path should align with the single-blank-line pattern.

Copy link
Contributor

@alepane21 alepane21 left a comment

Choose a reason for hiding this comment

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

LGTM!

@dkorittki
Copy link
Contributor Author

Note: Did some local tests to see if it works, but only with one simultaneous client. Gonna be sure and test with the Apollo client with some simultaneous connections.

@dkorittki
Copy link
Contributor Author

dkorittki commented Dec 8, 2025

I did some tests with a custom script using apollo client with both graphql-ws and graphql-sse as connection clients.

The error seems to be propagated correctly to clients on sse, now matching what ws returns. Here are log outputs:

ws-client

Starting subscription...
Received: {
  data: undefined,
  error: CombinedGraphQLErrors: My Test Error
      at Object.error (file:///[...]/apollo-client-demo/node_modules/@apollo/client/link/subscriptions/index.js:88:43)
      at Object.e12e92bd-23ca-497c-a384-e19a5651940e (file:///[...]/apollo-client-demo/node_modules/graphql-ws/dist/client.js:338:22)
      at emit (file:///[...]/apollo-client-demo/node_modules/graphql-ws/dist/client.js:75:58)
      at Object.emit (file:///[...]/apollo-client-demo/node_modules/graphql-ws/dist/client.js:100:11)
      at socket2.onmessage (file:///[...]/apollo-client-demo/node_modules/graphql-ws/dist/client.js:203:21)
      at [nodejs.internal.kHybridDispatch] (node:internal/event_target:827:20)
      at WebSocket.dispatchEvent (node:internal/event_target:762:26)
      at fireEvent (node:internal/deps/undici/undici:11663:14)
      at websocketMessageReceived (node:internal/deps/undici/undici:11685:7)
      at ByteParser.run (node:internal/deps/undici/undici:12307:19) {
    errors: [ [Object] ],
    data: undefined,
    extensions: undefined
  }
}

sse-client

Starting subscription...
Received: {
  data: undefined,
  error: CombinedGraphQLErrors: My Test Error
      at file:///[...]/apollo-client-demo/node_modules/@apollo/client/core/QueryManager.js:475:36
      at /[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/operators/map.js:10:37
      at OperatorSubscriber._this._next (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/operators/OperatorSubscriber.js:33:21)
      at Subscriber.next (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/Subscriber.js:51:18)
      at Subscriber._next (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/Subscriber.js:80:26)
      at Subscriber.next (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/Subscriber.js:51:18)
      at /[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/Subject.js:69:34
      at Object.errorContext (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/util/errorContext.js:22:9)
      at Subject.next (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/Subject.js:59:24)
      at Object.next (/[...]/apollo-client-demo/node_modules/rxjs/dist/cjs/internal/operators/share.js:69:58) {
    errors: [ [Object] ],
    data: null,
    extensions: undefined
  }
}

The only difference is that sse-client keeps reconnecting after the error. This seems to stem from the sse-client itself and has been the case before this change. It was just silent, no log output in that case, because the router never returned data on the connection prior to closing it.

I suspect the sse-client retries because we never sent a complete event after the error. According to the SSE specification, a complete event needs to be sent whenever we want to close the connection, which in this case is true. I'll see how we can add this to the code and if it really makes sense.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
router/core/websocket.go (1)

1050-1067: Consider also cleaning up subscriptions state when subscription setup fails

In the SubscriptionResponsePlan error path you now emit the error, flush, and send a complete, which is good for client semantics. However, this path doesn’t remove the entry from h.subscriptions, so operations that fail during AsyncResolveGraphQLSubscription will leave behind a mapping from msg.ID to subscriptionID.

By contrast, WebSocketConnectionHandler.Complete deletes the subscription ID before sending complete. To avoid accumulating stale entries on long‑lived connections, consider also deleting the subscription here (e.g., h.subscriptions.Delete(registration.msg.ID)), or refactoring through a helper that both sends error/complete and cleans up the state while preserving the desired flush/complete ordering.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d2dd99 and 0b323e0.

📒 Files selected for processing (1)
  • router/core/websocket.go (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:17-55
Timestamp: 2025-08-28T09:17:49.477Z
Learning: The Cosmo router uses a custom, intentionally rigid multipart implementation for GraphQL subscriptions. The multipart parsing in test files should remain strict and not be made more tolerant, as this rigidity is by design.
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2273
File: router/core/graphql_handler.go:0-0
Timestamp: 2025-11-19T15:13:57.821Z
Learning: In the Cosmo router (wundergraph/cosmo), error handling follows a two-phase pattern: (1) Prehandler phase handles request parsing, validation, and setup errors using `httpGraphqlError` and `writeOperationError` (in files like graphql_prehandler.go, operation_processor.go, parse_multipart.go, batch.go); (2) Execution phase handles resolver execution errors using `WriteError` in GraphQLHandler.ServeHTTP. Because all `httpGraphqlError` instances are caught in the prehandler before ServeHTTP is invoked, any error type checks for `httpGraphqlError` in the execution-phase WriteError method are unreachable code.
📚 Learning: 2025-11-19T15:13:57.821Z
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2273
File: router/core/graphql_handler.go:0-0
Timestamp: 2025-11-19T15:13:57.821Z
Learning: In the Cosmo router (wundergraph/cosmo), error handling follows a two-phase pattern: (1) Prehandler phase handles request parsing, validation, and setup errors using `httpGraphqlError` and `writeOperationError` (in files like graphql_prehandler.go, operation_processor.go, parse_multipart.go, batch.go); (2) Execution phase handles resolver execution errors using `WriteError` in GraphQLHandler.ServeHTTP. Because all `httpGraphqlError` instances are caught in the prehandler before ServeHTTP is invoked, any error type checks for `httpGraphqlError` in the execution-phase WriteError method are unreachable code.

Applied to files:

  • router/core/websocket.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-router
  • GitHub Check: build_test
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_push_image
  • GitHub Check: Analyze (go)
  • GitHub Check: build_test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
router/core/graphql_handler.go (1)

435-441: Consider logging flush errors instead of discarding them.

Both the websocket and HTTP flush error results are currently discarded. While this is consistent with the existing pattern, logging these errors could help diagnose issues where clients don't receive error responses due to flush failures (e.g., broken connections, write timeouts).

Apply this diff to log flush errors for both paths:

 	if wsRw, ok := w.(*websocketResponseWriter); ok {
-		_ = wsRw.Flush()
+		if err := wsRw.Flush(); err != nil {
+			requestLogger.Debug("Failed to flush websocket error response", zap.Error(err))
+		}
 	}

 	if httpRw, ok := w.(*HttpFlushWriter); ok {
-		_ = httpRw.Flush()
+		if err := httpRw.Flush(); err != nil {
+			requestLogger.Debug("Failed to flush HTTP error response", zap.Error(err))
+		}
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b323e0 and 1973c6c.

📒 Files selected for processing (2)
  • router/core/graphql_handler.go (1 hunks)
  • router/core/websocket.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • router/core/websocket.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2273
File: router/core/graphql_handler.go:0-0
Timestamp: 2025-11-19T15:13:57.821Z
Learning: In the Cosmo router (wundergraph/cosmo), error handling follows a two-phase pattern: (1) Prehandler phase handles request parsing, validation, and setup errors using `httpGraphqlError` and `writeOperationError` (in files like graphql_prehandler.go, operation_processor.go, parse_multipart.go, batch.go); (2) Execution phase handles resolver execution errors using `WriteError` in GraphQLHandler.ServeHTTP. Because all `httpGraphqlError` instances are caught in the prehandler before ServeHTTP is invoked, any error type checks for `httpGraphqlError` in the execution-phase WriteError method are unreachable code.
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:17-55
Timestamp: 2025-08-28T09:17:49.477Z
Learning: The Cosmo router uses a custom, intentionally rigid multipart implementation for GraphQL subscriptions. The multipart parsing in test files should remain strict and not be made more tolerant, as this rigidity is by design.
📚 Learning: 2025-11-19T15:13:57.821Z
Learnt from: dkorittki
Repo: wundergraph/cosmo PR: 2273
File: router/core/graphql_handler.go:0-0
Timestamp: 2025-11-19T15:13:57.821Z
Learning: In the Cosmo router (wundergraph/cosmo), error handling follows a two-phase pattern: (1) Prehandler phase handles request parsing, validation, and setup errors using `httpGraphqlError` and `writeOperationError` (in files like graphql_prehandler.go, operation_processor.go, parse_multipart.go, batch.go); (2) Execution phase handles resolver execution errors using `WriteError` in GraphQLHandler.ServeHTTP. Because all `httpGraphqlError` instances are caught in the prehandler before ServeHTTP is invoked, any error type checks for `httpGraphqlError` in the execution-phase WriteError method are unreachable code.

Applied to files:

  • router/core/graphql_handler.go
🧬 Code graph analysis (1)
router/core/graphql_handler.go (1)
router/core/flushwriter.go (1)
  • HttpFlushWriter (34-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: build_test
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./events)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
router/core/graphql_handler.go (1)

438-441: LGTM! Flush implementation correctly mirrors websocket pattern.

The added flush for HttpFlushWriter ensures that error responses are immediately sent to SSE and multipart subscription clients, fixing the issue where errors were buffered and not delivered. The implementation is consistent with the existing websocket flush pattern.

@github-actions
Copy link

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions bot added Stale and removed Stale labels Dec 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants