Skip to main content

rpc_dart_websocket 0.6.0 copy "rpc_dart_websocket: ^0.6.0" to clipboard
rpc_dart_websocket: ^0.6.0 copied to clipboard

Web-safe subset of rpc_dart_transports providing WebSocket caller/responder transports (caller + server) for Dart2JS/WASM builds.

0.6.0 #

  • Breaking:
    • headersProvider: and reconnectFactory: on the caller are replaced by RpcClientConnection; build headers: inside its factory, which runs for every connection.
    • A failed connect is a gRPC status, and a disconnected transport refuses in one shape.
    • A stopped server refuses connections instead of abandoning them.
    • The endpoint callbacks are refused. createWithContracts passes logController through.
  • New:
    • maxConnections.
    • bindRpcWebSocketHttpServer bounds the upgrade request.
    • The caller transport reports when it is ready.
    • Half-open detection where the platform drops ping.
    • frameProgressTimeout (default 60 s, null disables): while a frame is unfinished its bytes must keep arriving within the window or the connection is closed, on the server upgrade path and the client connect alike. pingInterval fires only on total silence, so a peer dripping one byte at a time used to hold its connection past any keepalive; between frames there is no deadline, and an idle connection is a legitimate one.
    • A one-time warning when neither allowedOrigins nor allowUpgrade is configured, to the new optional logger: parameter (stderr fallback): an ungated server upgrades any origin, cross-site WebSocket hijacking included, and the gate cannot be defaulted because the allowed origins are the application's to know. The warning makes an ungated deployment a visible choice.
  • Hardening:
    • connect() is bounded by default.
    • An unfinished message is bounded before dart:io buffers it, and a message in thousands of fragments is refused.
    • Inbound pings are rate-limited.
    • Reading stops while 1 MiB of answers is unsent.
    • Credentials and close reasons no longer reach the log unescaped.
    • Several inputs that killed the server no longer do: a repeated Sec-WebSocket-Key and a refused frame during the handshake.
    • A raw socket closed under an established channel is survived.
  • Fixed:
    • RpcClientConnection reconnects after a server restart.
    • A peer client can answer calls.
    • A reused peer stream id gets its own answer.
    • An ended connection returns its maxConnections slot.
    • A refused request with a stalled body receives its 400/403. The refusal drain cancelled the request-body subscription before writing the status, and cancelling a dart:io request stream tears the connection down — the peer read a TCP reset instead of the answer. The response is written first, the cancellation after.

0.5.0 #

Added #

  • connect() takes headers and connectTimeout. Neither had any way through: an auth header could not be attached to the handshake at all, and a server that accepted the TCP connection and then never completed the upgrade hung the caller forever. Both are re-applied on reconnect.
  • RpcWebSocketNonBinaryFrame — the error raised for a TEXT frame on a binary channel, marked IRpcAdvisoryChannelError so it stops at the connection instead of failing every call in flight.

Fixed #

  • A call landing inside a reconnect is refused rather than served by a dead socket. send, reads and sendDirectObject all now see the window.

Changed #

  • Requires rpc_dart 6.1, for IRpcAdvisoryChannelError.

0.4.0 #

Breaking #

  • permessage-deflate is off by default, on the server and in what the client offers. It is a decompression bomb with no output bound: 0.25 MiB uploaded expanded to 516 MiB of RSS (2071x), against 2.7x with it off. The inflation happens inside dart:io, which exposes no limit, so the only lever is not negotiating the extension. Re-enable it deliberately if both peers are trusted.
  • pingInterval defaults to 30s on the server. A peer that completes the handshake and then goes silent used to hold its connection, endpoint and contracts forever.
  • Requires rpc_dart 6. See its changelog — notably that a handler's bare Exception text no longer reaches the caller, and that a response ending without a grpc-status now raises UNAVAILABLE instead of ending cleanly.

Security #

  • A server can refuse a cross-origin handshake (opt-in): a browser will happily let any page open a WebSocket to your server.
  • A duplicated Origin header no longer kills the server process.
  • The drain on a refused upgrade is bounded, so refusing a connection is cheaper than accepting one rather than more expensive.
  • The inbound message ceiling is pinned by a test rather than claimed in a doc comment: a 64 MiB message closes the connection with 4400 and the reason naming the buffer overflow, three 8 MiB messages are accepted. What bounds it is maxMessageLengthBytes; the peak allocation cannot be helped, because dart:io buffers a whole message before delivering it, so what matters is that the connection closes — a surviving one is an unlimited supply of peaks.

Fixed #

  • A dead call's teardown acted on a live one after a reconnect, because the stream id had been reused.
  • Concurrent reconnect() orphaned a socket per attempt.
  • Keepalive on both halves, which is the only way to notice a half-open path; neither caller noticed the peer had died.
  • Graceful drain on stop() (opt-in), and the server stops accepting before it drains.
  • A framing violation hung up without saying so, and a non-binary frame was dropped silently instead of reported.
  • The peer's close code reaches the caller as a gRPC status instead of a blanket UNAVAILABLE.
  • close() deadlocked when nothing listened to incoming.
  • A failed start() left the server claiming to run, and a call after a failed reconnect killed the isolate.
  • A socket that arrives after the transport has closed is closed, not leaked.
  • The endpoint is released when onEndpointCreated throws.
  • The transport no longer hides its security policy from the endpoint, and a throwing observability callback no longer kills the server.

0.3.0 #

Fixed #

  • Per-connection endpoints are closed when their connection ends; they were never released, so every connection leaked one.

Changed #

  • Requires rpc_dart 5. See its changelog: flow control is on by default, an expired deadline is now RpcDeadlineExceededException on every shape, and a stream that ends without a trailer raises UNAVAILABLE.

0.2.3 #

  • Fixed: RpcWebSocketCallerTransport no longer permanently closes itself when the underlying socket drops gracefully (server-side FIN) and a reconnectFactory is configured. Previously the onDone cascade flipped the transport to closed, so a later reconnect() returned "Transport closed" — defeating reconnect after a server-initiated drop. The stable incomingMessages stream now survives the drop so subscribers persist and reconnect() can re-attach. This is the recovery path the rpc_dart_log client relies on. Without a reconnectFactory the transport still closes fully on drop (unchanged).
  • Expanded test coverage of the flagship streaming transport:
    • test/websocket_rpc_contract_test.dart: full typed RPC contract end-to-end over a real dart:io WebSocket server (RpcWebSocketServer + RpcResponderEndpoint/RpcCallerEndpoint, ephemeral localhost port). Covers unary, server-stream (ordered delivery + completion), client-stream (aggregation), bidirectional (ordered echo), typed RpcStatusException propagation, mid-stream cancellation (no hang, transport stays usable), concurrent calls/streams (no cross-wiring), and a high-volume ordered stream.
    • test/websocket_reconnect_test.dart: reconnect coverage (previously zero). Proves reconnect() re-establishes the socket, the stable incomingMessages stream survives for pre-existing subscribers, requests issued after reconnect reach a freshly-bound server, full endpoint-level RPC recovers after a server swap, the no-factory/already-closed paths report correctly, and a regression guard for the graceful-drop fix above.

0.2.2 #

  • Web-correctness verification: the client transport (RpcWebSocketCallerTransport / RpcWebSocketChannel) is confirmed dart2js-safe. No dart:io on the client path; the frame multiplexer header uses only 32-bit ByteData ops (no setUint64/getUint64), so it is safe under dart2js' 32-bit integer semantics.
  • Added test/websocket_web_smoke_test.dart: frame round-trip plus caller/responder round-trips over an in-memory WebSocketChannel pair (no dart:io). Passes on VM, node, and chrome (fvm dart test -p vm|node|chrome).
  • Added async and stream_channel dev dependencies for the in-memory channel pair used by the web smoke test.

0.2.1 #

  • RpcWebSocketServer: added onPeerEndpointCreated callback — when set, each accepted connection creates an RpcPeerEndpoint instead of RpcResponderEndpoint, enabling bidirectional server-initiated calls over WebSocket.
  • RpcWebSocketCallerTransport.connect(): now awaits WebSocketChannel.ready before returning, so connection errors are reported at connect time rather than leaking as unhandled stream errors.
  • Updated to rpc_dart: ^3.1.0.

0.2.0 #

  • Updated to rpc_dart: ^3.0.0.
  • Migrated to 3-layer transport architecture (IRpcChannel / IRpcMultiplexedChannel / RpcChannelTransport).
  • WebSocket metadata encoding switched to binary CBOR for consistency with core.

0.1.0 #

  • Initial release: WebSocket caller/responder transports for rpc_dart (web-safe, works on Dart2JS/WASM).
0
likes
150
points
710
downloads

Documentation

API reference

Publisher

verified publisherrpc.nogipx.dev

Weekly Downloads

Web-safe subset of rpc_dart_transports providing WebSocket caller/responder transports (caller + server) for Dart2JS/WASM builds.

Homepage
Repository (GitHub)
View/report issues

Topics

#rpc #websocket

License

MIT (license)

Dependencies

crypto, rpc_dart, web_socket_channel

More

Packages that depend on rpc_dart_websocket