Skip to content

Releases: ueberdosis/hocuspocus

v4.3.0

18 Jun 10:37
v4.3.0
1129ae0

Choose a tag to compare

What's Changed

  • feat: add afterHandleMessage hook to run after message handling completion by @janthurau in #1112
  • feat: enforce pre-auth resource limits to safeguard server stability by @janthurau in #1113

Full Changelog: v4.2.0...v4.3.0

v4.2.0

12 Jun 12:20
v4.2.0
94fa0c7

Choose a tag to compare

What's Changed

  • feat: add unloadImmediately option to disconnect() for configurable document persistence behavior by @janthurau in #1111

Full Changelog: v4.1.2...v4.2.0

v4.1.2

11 Jun 12:41
v4.1.2
f3d761d

Choose a tag to compare

What's Changed

New Contributors

Full Changelog: v4.1.1...v4.1.2

v4.1.1

10 Jun 07:17
v4.1.1
a07826a

Choose a tag to compare

What's Changed

  • fix: client-initiated broadcastStateless by @janthurau in #1103
  • Fix memory leak: destroy scratch Awareness objects in MessageReceiver by @Copilot in #1109
  • Feature: expose sessionAwareness in provider-react HocuspocusRoom by @t-schorn in #1104

New Contributors

Full Changelog: v4.1.0...v4.1.1

v4.1.0

20 May 11:45
v4.1.0
702ec72

Choose a tag to compare

What's Changed

  • feat(server): add beforeHandleAwareness hook by @dschmidt in #1096
  • fix(server): wrap awareness origin as TransactionOrigin by @dschmidt in #1094

New Contributors

Full Changelog: v4.0.0...v4.1.0

v4.0.0

23 Apr 11:23
v4.0.0
1c1b348

Choose a tag to compare

Hocuspocus v4.0 Release Notes

Hocuspocus v4 is a major release that brings cross-runtime support, improved type safety, and important bug fixes. This release focuses on making Hocuspocus run beyond Node.js -- on Bun, Deno, Cloudflare Workers, and Node with uWebSockets -- while improving the developer experience with generic Context typing and structured transaction origins.

Backward Compatibility

A v3 provider can connect to a v4 server, and a v4 provider can connect to a v3 server. The wire protocol remains compatible in both directions:

  • v3 provider -> v4 server: The server accepts plain document names (no session routing key), does not require Pong responses, and handles auth messages without a provider version string.
  • v4 provider -> v3 server: The provider defaults to sessionAwareness: false, so it sends plain document names. The extra version string in the auth message is ignored by the v3 server as trailing data. The provider does not require server-initiated Ping messages.
  • Session awareness caveat: If sessionAwareness: true is explicitly enabled on a v4 provider connecting to a v3 server, the server will treat the composite routing key (documentName\0sessionId) as a literal document name, creating unintended documents. Keep sessionAwareness: false (the default) when connecting to a v3 server.

Highlights

Cross-Runtime Support

Hocuspocus is no longer tied to the Node.js ws library. The server now uses crossws, a universal WebSocket adapter, enabling Hocuspocus to run on:

  • Node.js (with ws or uWebSockets.js)
  • Bun
  • Deno
  • Cloudflare Workers

The built-in Server class continues to work as before for Node.js users. For other runtimes, use Hocuspocus directly with handleConnection(), which now accepts any WebSocketLike object and a web-standard Request.

Generic Context Type

All core classes and hook payloads now accept a generic Context type parameter, enabling end-to-end type safety:

interface MyContext {
  userId: string;
  permissions: string[];
}

const server = Server.configure<MyContext>({
  async onAuthenticate({ context, token }) {
    // context is typed as MyContext
    return { userId: '123', permissions: ['read', 'write'] };
  },
  async onChange({ context }) {
    // context.userId is typed as string
    console.log(context.userId);
  },
});

The generic defaults to any, so existing code without explicit typing continues to work.

Ordered Message Processing

Document updates are now processed sequentially in the order they are received. Previously, concurrent messages could be processed out of order if async hooks were involved. A new internal message queue ensures CRDT updates are applied consistently.

Web Standard Request/Headers

Hook payloads now use the web-standard Request and Headers objects instead of Node.js IncomingMessage and IncomingHttpHeaders. This aligns with the cross-runtime goal and provides a consistent API across all environments.

New Features

Server

  • Cross-runtime WebSocket support via crossws -- Bun, Deno, Cloudflare Workers, Node/uWebSockets all supported (non-breaking)
  • Generic Context type parameter on Hocuspocus, Server, Extension, Connection, ClientConnection, DirectConnection, and all hook payloads (non-breaking -- defaults to any)
  • Structured transaction origins -- new TransactionOrigin union type (ConnectionTransactionOrigin | RedisTransactionOrigin | LocalTransactionOrigin) with helper functions isTransactionOrigin() and shouldSkipStoreHooks() (breaking -- see upgrade guide)
  • onLoadDocument now accepts Uint8Array returns -- extensions can return raw Yjs updates instead of constructing a full Y.Doc, simplifying storage extensions (non-breaking)
  • handleConnection() returns ClientConnection -- enables programmatic access to the connection lifecycle for custom integrations (non-breaking)
  • Ordered message processing -- messages are queued and processed sequentially per connection (non-breaking)
  • Session awareness -- the server supports session-aware multiplexing, allowing multiple providers with the same document name on a single WebSocket. Each provider gets a unique sessionId routed via a composite key. The server transparently falls back to plain document names for v3 providers (non-breaking)
  • Auth retry support -- failed authentication now properly cleans up state, allowing clients to retry without reconnecting (non-breaking)
  • DirectConnection context -- openDirectConnection(documentName, context) now accepts and propagates a context object (non-breaking)
  • Store hooks on all changes -- onStoreDocument is now triggered on any document change (not just WebSocket-originated ones), with explicit opt-out via skipStoreHooks on LocalTransactionOrigin (non-breaking)
  • Provider version awareness -- the provider version is available on Connection.providerVersion and in hook payloads (onConnect, onAuthenticate, connected), making it easier to introduce protocol changes in a backward-compatible way (non-breaking)
  • SkipFurtherHooksError -- extensions can throw SkipFurtherHooksError (from @hocuspocus/common) in onStoreDocument to signal that persistence was handled and remaining hooks should be skipped (non-breaking)

Provider

  • Session awareness -- new sessionAwareness option (default: false). When enabled, the provider embeds a unique sessionId in the document name field of every message, enabling multiple providers with the same document name on one WebSocket. Keep disabled when connecting to a v3 server (non-breaking)
  • Provider version sent during auth -- the provider now sends its package version to the server in the authentication message. The extra field is safely ignored by v3 servers (non-breaking)
  • Awareness message deduplication -- when the WebSocket is not yet open and messages are queued, duplicate awareness messages for the same document are deduplicated, keeping only the latest one (non-breaking)
  • Application-level Ping/Pong -- new MessageType.Ping (9) and MessageType.Pong (10). The provider responds to server Ping messages with Pong, replacing WebSocket-level ping/pong which is not available in all runtimes. The provider works fine without receiving Pings (e.g., when connected to a v3 server) (non-breaking)
  • ws package types removed -- the provider no longer imports Event, MessageEvent, or CloseEvent from the ws package. It uses web-standard types and types from @hocuspocus/common instead (breaking for TypeScript users who relied on ws types being re-exported)
  • CloseEvent shape simplified -- the CloseEvent passed to onClose callbacks no longer includes target and type fields. Only code and reason remain (breaking if your onClose handler reads event.target or event.type)
  • Attach collision detection -- HocuspocusProviderWebsocket.attach() now throws an error if you try to attach two authenticated providers with the same effective name. Previously it silently overwrote the existing provider (non-breaking for correct usage; may surface existing bugs)
  • Unknown message types handled gracefully -- unknown message types now log console.error instead of throwing. This makes rolling out future protocol additions easier (non-breaking)

Bug Fixes

Server

  • Auth state reset on failure -- when authentication fails, document state is cleaned up so the client can send a new auth message without reconnecting (#944) (non-breaking)
  • onLoadDocument accepts Uint8Array -- the callback now correctly handles both Y.Doc and Uint8Array returns (#795, #271) (non-breaking)
  • Close code type check -- close event codes are now properly validated as numbers (#1062) (non-breaking)
  • Store hooks reliability -- onStoreDocument now triggers on any document change, preventing accidental data loss when updates lacked a Yjs origin (non-breaking)
  • onStoreDocument payload type -- the Database extension and Logger extension now correctly type the parameter as onStoreDocumentPayload instead of the incorrect onChangePayload / onDisconnectPayload (non-breaking)
  • Document name validation -- empty and whitespace-only document names are now rejected on both WebSocket connections and direct connections (non-breaking)
  • Store hook retry on failure -- when onStoreDocument hooks throw, the document stays in memory and retries are attempted to avoid data loss (non-breaking)
  • Graceful shutdown flushes pending stores -- Server.destroy() now immediately executes all pending debounced onStoreDocument calls, ensuring documents are persisted before the server exits (even when unloadImmediately: false) (non-breaking)
  • Memory optimization -- outgoing Yjs update messages are now encoded once and shared across connections instead of being re-created per connection (non-breaking)

Provider

  • Unknown message types no longer crash the provider -- console.error instead of throw. This makes future protocol additions easier (non-breaking)

Infrastructure Changes

  • Package manager: migrated from npm to pnpm workspaces
  • Bundler: migrated from Rollup to Rolldown
  • SQLite extension: migrated from sqlite3 to better-sqlite3 (synchronous API, actively maintained)
  • Node.js requirement: >=22 (specified in @hocuspocus/server)
  • Default timeout: increased from 30s to 60s
  • Lerna: upgraded to v9 with pnpm as npm client

Upgrade Guide: v3 to v4

1. Update Dependencies

# Install v4
npm install @hocuspocus/server@^4.0.0 @hocuspocus/provid...
Read more

v3.4.4

25 Jan 20:49
v3.4.4
d3a252b

Choose a tag to compare

What's Changed

Full Changelog: v3.4.3...v3.4.4

v3.4.3

15 Dec 12:25
v3.4.3
cc66673

Choose a tag to compare

  • trusted publishing test

Full Changelog: v3.4.2...v3.4.3

v3.4.2

15 Dec 12:19
v3.4.2
8d20212

Choose a tag to compare

What's Changed

  • fix: fixes memory leak under high load
  • chore: testing new publish workflow

Full Changelog: v3.4.1...v3.4.2

v3.4.1

09 Dec 13:33
v3.4.1
f1d282d

Choose a tag to compare

What's Changed

  • fix: extension-redis: on awareness crasah prevention and memory leak onStoreDocument by @matteotarantino-algor in #1032

  • build(deps): bump hono from 4.10.2 to 4.10.3 by @dependabot[bot] in #1016

  • WIP: chore: remove docs as they are now present in @ueberdosis/tiptap-docs by @janthurau in #952

  • build(deps): bump actions/checkout from 5 to 6 by @dependabot[bot] in #1023

  • build(deps): bump glob from 10.4.5 to 10.5.0 by @dependabot[bot] in #1021

  • Add the missing test for not unloading before ongoing save is finished by @raimohanska in #1025

  • build(deps): bump next from 15.4.7 to 15.4.8 by @dependabot[bot] in #1030

  • build(deps): bump next from 15.4.7 to 15.4.8 in /playground/frontend by @dependabot[bot] in #1026

New Contributors

Full Changelog: v3.4.0...v3.4.1