Repository navigation
Releases
partyserver@0.5.10
Patch Changes
- #417
5ce45b7Thanks @threepointone! - Inherit hibernation settings when a Server subclass declares partial static options.
partyserver@0.5.9
Patch Changes
- #415
1eb112fThanks @mattzcarey! - Allow@cloudflare/workers-typesv5 as a peer dependency. PartyServer remains compatible with v4 while projects using Wrangler 4.108 and newer can install the v5 runtime types without a peer dependency conflict.
partysocket@1.3.0
Minor Changes
- #409
6b97742Thanks @threepointone! - AddshouldReconnectOnClose, allowing callers to stop automatic reconnects for terminal close events while preserving the existing reconnect-by-default behavior.
partyserver@0.5.8
Patch Changes
- #407
2be6104Thanks @threepointone! - Encode thex-partykit-propsheader as base64 so props containing non-ASCII characters (e.g. accented names like "Usuário") no longer trigger workerd's "header value contains non-ASCII characters" warning, which would throw aTypeErrorin browser fetch implementations. The header is decoded back to the original Unicode payload on the server, and raw-JSON values from older callers are still accepted for backwards compatibility.
partyserver@0.5.7
Patch Changes
-
#405
7dbf92cThanks @threepointone! - Accept non-hibernating WebSocket connections in half-open mode (accept({ allowHalfOpen: true })).On compatibility dates
>= 2026-04-07theweb_socket_auto_reply_to_closeflag makes the runtime send a reciprocal Close frame and tear the socket down automatically. For a non-hibernating PartyServer (hibernate: false), the Durable Object sits on the server end of a connection that the runtime tunnels back to the client, so that auto-teardown could fire through an already-severed tunnel — surfacing as a spurious retryableNetwork connection lost.rejection (for example when a Durable Object is reset while a connection is still open). Half-open mode keeps PartyServer's existing close handling in control; it already reciprocates the peer's Close frame on every compatibility date, so client behavior is unchanged.Also in this release, two related WebSocket fixes that keep behavior consistent across all compatibility dates:
- Pin
binaryTypeto"arraybuffer"for non-hibernating connections. On compatibility dates>= 2026-03-17thewebsocket_standard_binary_typeflag flips the default server-sidebinaryTypefrom"arraybuffer"to"blob", so binary frames arrived asBlobinstead ofArrayBufferon the in-memory path. PartyServer (and frameworks built on it, e.g. Cloudflare Agents) have always receivedArrayBuffer, so it is now pinned back inaccept(). This is a no-op on older dates and corrective on newer ones; the Hibernation API is unaffected (it always deliversArrayBuffer). - Stop reporting transport-teardown errors as
onError. A retryableNetwork connection lost./WebSocket peer disconnectederror that fires on an already closing/closed connection is the socket going away during the close handshake, not an application error. It is now suppressed when the connection isCLOSING/CLOSED(detected via the structuredretryableflag, with a message fallback), so it no longer spams logs on abrupt client disconnects. Genuine mid-connection (OPEN) errors still reachonError.
- Pin
partysocket@1.2.0
Minor Changes
-
#403
7e042ebThanks @threepointone! - Make buffered messages and connection teardown reliable across socket replacement and explicit close (see cloudflare/agents#1738).close()now dispatches itscloseevent synchronously (mirroring howreconnect()already dispatched its synthetic close). Consumers that detach their listeners right after closing — like the React hooks during cleanup — previously never observed the terminal close event, leaving "connection closed" handling (pending-call rejection, state resets) to never run. Afterclose()returns,readyStatereportsCLOSEDimmediately, even while the underlying socket finishes its closing handshake. Code that attached acloselistener after callingclose()and relied on the event arriving asynchronously must attach the listener first.send()now returns aboolean:trueif the message was transmitted immediately over an open connection,falseif it was buffered (delivered when the connection next opens, always before theopenevent is dispatched) or dropped becausemaxEnqueuedMessageswas reached. Callers implementing request/response protocols can use this to know whether a request is actually in flight.- New
drainQueuedMessages()method removes and returns all messages that were buffered bysend()but never transmitted, so a socket that's being discarded can hand its unsent buffer to a replacement instead of silently losing it. - React hooks (
usePartySocket,useWebSocket) now migrate buffered messages when they replace the socket because connection options changed. By default, buffered messages transfer only when the destination is unchanged (e.g. onlyquery— credentials — changed); if destination options (room,party,path,host, URL, ...) changed, the messages are discarded with a warning rather than delivered to a destination they weren't composed for. The newtransferEnqueuedMessagesoption overrides this:truealways transfers,falsenever does. - Warn when
send()is called afterclose(). Messages sent against a permanently closed socket are buffered into a queue that nothing will ever flush (unlessreconnect()is called later), which silently strands the message — and any caller waiting on a reply. This usually indicates a stale socket reference in the caller. The message is still buffered for backwards compatibility; the warning is emitted once per close cycle and resets onreconnect().
partysocket@1.1.19
partyserver@0.5.6
Patch Changes
- #399
f772382Thanks @threepointone! - Retry transient Durable Object routing errors fromroutePartykitRequestandgetServerByName, and expose route-level retry configuration.
partyserver@0.5.5
Patch Changes
- #394
9a927a3Thanks @threepointone! - Don't reciprocate the WebSocket close handshake when the runtime delivers a reserved close code (1005,1006,1015). These codes are synthesized by the runtime when the peer didn't actually send a Close frame — there is no handshake to complete. The earlier0.5.4change ([#393](https://github.com/cloudflare/partykit/issues/393)) normalized these to1000and tried to send a reciprocating Close frame anyway; in cross-isolate transports (notably WebSocket pairs that flow back through Durable Object RPC, e.g. Cloudflare Agents sub-agents) the reciprocation would succeed synchronously but schedule an outbound write on a transport whose peer was already gone. The runtime then rejected that write asynchronously withNetwork connection lost, escapingcloseQuietly's synchronoustry/catchand surfacing as an unhandled promise rejection in tests and production logs. The fix is to skip the reciprocation for reserved codes — there's nothing to acknowledge to a peer that didn't speak. The narrow user-visible behavior change: a client that callsws.close()with no code on compat dates< 2026-04-07(no auto-reply) will now observe a non-clean close instead of a clean1000close, because the framework no longer fabricates a reciprocation. Clients that pass an explicit close code are unaffected.
partyserver@0.5.4
Patch Changes
-
#391
6273c96Thanks @threepointone! - Persist a__ps_namefallback for name-based Durable Objects during initialization. This lets alarm handlers recoverthis.nameeven when firing on a stale on-disk alarm record that was scheduled by an older workerd version that didn't yet persistnameinto the alarm record. See #390. -
#393
5335251Thanks @threepointone! - Complete the WebSocket close handshake when a client initiates the close. Previously, both the hibernatingwebSocketClosehandler and the non-hibernating close-event listener forwarded to useronClosebut never sent a reciprocal Close frame, leaving clients stuck inCLOSINGuntil they timed out and reported1006(abnormal closure). The framework now reciprocates the peer's Close frame in afinallyblock on both paths — required by the Hibernation API on every compat date, and required by the standardaccept()API on compat dates before2026-04-07(where the runtime'sweb_socket_auto_reply_to_closeflag isn't yet active). Callingclose()on an already-closed socket is a silent no-op, so user code that already callsconnection.close(...)fromonCloseis unaffected. Reserved close codes (1005,1006,1015) are normalized to1000before reciprocation so they don't throwInvalidAccessError. See #389.