fix(client, server): preserve message ordering for blob messages in peer adapters#1621
Conversation
…eer adapters Blob messages require an async step to load bytes before sending, while text messages are sent synchronously. This meant that when a blob message was queued before a text message, the text message could reach the peer first, breaking expected ordering.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/interop
@orpc/json-schema
@orpc/nest
@orpc/next
@orpc/openapi
@orpc/opentelemetry
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/tanstack-query
@orpc/valibot
@orpc/zod
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Caution
WebSocketHandler.upgrade passes a Promise<Uint8Array> to .message() when the event payload is a Blob, because loadBytes is not awaited. Awaiting the Blob load is required for the sequential ordering fix to work.
Reviewed changes — the PR removes async Blob loading from the text-or-bytes normalization path and wraps WebSocket/MessagePort message handlers in sequential queues so that blob-to-binary conversion doesn't let later text/bytes messages overtake earlier blob messages.
- Synchronous
toStringOrBytesin@orpc/sharednow concatenates arrays directly instead of constructing aBlob, and no longer acceptsBlobinputs. - Client WebSocket transport uses
sequentialplus an explicitawait loadBytes(event.data)for blob payloads, keeping decode/dispatch order. - Server WebSocket handler uses
sequentialin.upgrade()and synchronoustoStringOrBytesin.message(). - MessagePort client/server switch from
isPlainObjecttoisPeerMessagevalidation and return explicit matched results. - Crossws handler and test coverage updated; the previously skipped crossws parallel-stream test is now re-enabled.
- Docs/JSDoc refined to warn about ordering and consistent peer instances.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the latest commit addressed the prior Blob-in-upgrade() ordering concern and tightened peer lifecycle handling across adapters.
- Awaited
loadBytesinWebSocketHandler.upgradeso Blob payloads are fully loaded beforethis.message(...)runs, fixing thePromise<Uint8Array>bug flagged in the previous review. - Reordered close cleanup in
MessagePortHandler.closeandWebSocketHandler.closeto delete the peer from the map before awaitingpeer.close(), avoiding races where an in-flight message could reach a closing peer. - Awaited
peer.close()inMessagePortLinkTransport's close listener so the client transport waits for shutdown. - Documented the non-blocking dispatch in
WebSocketLinkTransportwith a comment explaining whypeer.message(...)is intentionally not awaited. - Added/adjusted tests to cover Blob messages through
WebSocketHandler.upgradeand to verify idempotent close handling.
Targeted tests pass, including the re-enabled crossws parallel stream cases.
Kimi K2 (free via Pullfrog for OSS) | 𝕏

Blob messages require an async step to load bytes before handling, while text messages are handled synchronously. This meant that when a blob message was queued before a text message, the text message could reach the peer first, breaking expected ordering.