Skip to content

feat: relay over crossws pub/sub and upgrade to crossws 0.4 - #16

Open
benjamincanac wants to merge 2 commits into
pi0:mainfrom
benjamincanac:feat/crossws-pubsub
Open

feat: relay over crossws pub/sub and upgrade to crossws 0.4#16
benjamincanac wants to merge 2 commits into
pi0:mainfrom
benjamincanac:feat/crossws-pubsub

Conversation

@benjamincanac

Copy link
Copy Markdown

Summary

Replaces the manual per-peer broadcast loop with crossws pub/sub (peer.subscribe on open, origin.publish to relay updates & awareness). This is the abstraction crossws sync backplanes extend, so once a backplane is configured on the adapter, cross-instance relay (Redis/Postgres/etc.) works transparently with no changes to y-crossws. The old for (peer of peerIds) peer.send() loop bypassed crossws pub/sub entirely and could never benefit from a backplane.

Also upgrades crossws to ^0.4.6, fixes a provider connect bug, and adds a test suite.

Changes

  • refactor(server) — relay doc + awareness updates over crossws pub/sub instead of a manual peer loop. publish excludes the sender (verified in the node adapter), so each update goes to every other room subscriber.
  • chore(deps) — upgrade crossws to ^0.4.6; switch the CF playground to the unified crossws/adapters/cloudflare adapter (still wires up the Durable Object); drop now-unnecessary @ts-expect-errors.
  • fix(provider) — initialize ws as null instead of undefined. connect()/setupWS() gate on ws === null, so the old undefined default made the first connect() a silent no-op.
  • test — add a Vitest suite exercising the server (raw protocol clients: doc sync, CRDT merge, awareness both ways, awareness-cleared-on-disconnect) and the bundled WebsocketProvider (connect + sync), over real WebSockets on ephemeral ports. Wired into pnpm test.
  • docs — add a "Multi-instance deployments" section.

Scope / known limitation

This is correct for a single instance and Cloudflare (single Durable Object). It does not by itself make multi-instance (e.g. Vercel horizontal scaling) work:

  1. crossws 0.4.6 has no sync backplane yet — the vercel adapter is the node adapter, so publish is in-process only. Cross-instance relay needs #192.
  2. Even with a message backplane, each instance keeps its own server-side Y.Doc (used for writeSyncStep1 + persistence). A client joining a "cold" instance can miss history that only lives on another instance — backplanes relay messages, not doc state.

Both are documented in code comments and the README, framed as known limitations rather than something this PR claims to solve. Happy to align with the upcoming crossws/nitro sync engine.

Test plan

  • pnpm test — lint + types + Vitest (4 tests) ✅
  • Manual: pnpm build --stub && pnpm play:node, open /tiptap/ in two windows → live sync + cursors ✅

Replace the manual per-peer broadcast loop with crossws pub/sub
(peer.subscribe on open, origin.publish to relay). This is the
abstraction crossws sync backplanes extend, so cross-instance relay
(e.g. Redis/Postgres via h3js/crossws#192) works transparently once
configured on the adapter, with no changes here. Relay stays local to a
single instance otherwise — documented as a known limitation.

- chore(deps): upgrade crossws to ^0.4.6; switch CF playground to the
  unified `crossws/adapters/cloudflare` adapter and drop now-stale
  `@ts-expect-error`s.
- fix(provider): initialize `ws` as `null` (not `undefined`) so the
  `ws === null` guards in connect()/setupWS() fire — the old default
  made the first connect() a silent no-op.
- test: add a Vitest suite (server + provider) over real WebSockets on
  ephemeral ports, wired into `pnpm test`.
- docs: add a "Multi-instance deployments" section covering the sync
  backplane and the message-vs-doc-state caveat.
@benjamincanac
benjamincanac marked this pull request as ready for review June 25, 2026 08:27
- Add a pkg-pr-new workflow that builds and publishes a continuous
  preview release on pushes to main and PRs, so reviewers can install
  the package straight from a commit/PR.
- Run `pnpm vitest run` in the ci workflow now that a test suite exists
  (previously only lint + types + build ran).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant