Skip to content

fix(realtime): send typed array broadcast payloads as binary - #2772

Open
Abhishek-B-R wants to merge 1 commit into
supabase:masterfrom
Abhishek-B-R:fix/realtime-typed-array-broadcast
Open

Abhishek-B-R wants to merge 1 commit into
supabase:masterfrom
Abhishek-B-R:fix/realtime-typed-array-broadcast

Conversation

@Abhishek-B-R

Copy link
Copy Markdown

🔍 Description

What changed?

The realtime serializer now sends a broadcast payload as binary when it is any ArrayBufferView (Uint8Array, Node.js Buffer, DataView, other typed arrays), not only when it is a plain ArrayBuffer. Only the bytes the view covers are copied, so a view into a larger buffer (a pooled Buffer, or subarray()) sends just its own bytes.

Why was this change needed?

channel.send({ type: 'broadcast', event, payload: new Uint8Array([1, 4]) }) over the WebSocket goes down the JSON path, because _binaryEncodeUserBroadcastPush only checks for ArrayBuffer. JSON.stringify turns the typed array into an object, so the frame carries {"0":1,"1":4} with the JSON encoding flag and every subscriber receives { '0': 1, '1': 4 } instead of an ArrayBuffer.

httpSend() already treats ArrayBuffer.isView(payload) as binary and sends it as application/octet-stream, so the same payload worked over REST and broke over the socket. Libraries that hand you a Uint8Array (Yjs updates, protobuf encoders, TextEncoder) hit this directly.

📸 Screenshots/Examples

Encoding the same message with new Uint8Array([1, 4]) as the payload:

Before (encoding byte 0x01 = JSON):

\x03\x02\x01\x03\x0a\x00\x01 101 top user-event {"0":1,"1":4}

After (encoding byte 0x00 = binary), identical to what an ArrayBuffer payload produces:

\x03\x02\x01\x03\x0a\x00\x00 101 top user-event \x01\x04

Tests added in test/serializer.test.ts: a Uint8Array payload, a subarray() view into a larger buffer (checks only the viewed bytes are sent), and a DataView. All three fail on master and pass with the change.

What I ran in packages/core/realtime-js:

  • npx vitest run: 26 files, 478 passed, 1 skipped
  • tsc -p tsconfig.json and tsc -p tsconfig.module.json: clean
  • prettier --check on both changed files: clean

🔄 Breaking changes

  • This PR contains no breaking changes

Plain ArrayBuffer and JSON payloads encode byte for byte the same as before.

📋 Checklist

  • I have read the Contributing Guidelines
  • My PR title follows the conventional commit format: <type>(<scope>): <description>
  • I have run pnpm nx format to ensure consistent code formatting
  • I have added tests for new functionality (if applicable)
  • I have updated documentation (if applicable)

📝 Additional notes

The deprecated implicit REST fallback inside send() (used when the socket can't push) still JSON-encodes the payload, including a plain ArrayBuffer. I left that alone since it is slated for removal and httpSend() is the supported REST path.

The binary serializer only treated an ArrayBuffer payload as binary. A
Uint8Array, Node.js Buffer or DataView went down the JSON path, so the
bytes were sent as {"0":1,"1":4} with the JSON encoding flag and
subscribers received an object instead of an ArrayBuffer. httpSend()
already sends any ArrayBufferView as application/octet-stream.

Encode ArrayBufferView payloads with the binary encoding, copying only
the bytes the view covers so a Buffer from the pool does not leak its
neighbours.
@Abhishek-B-R
Abhishek-B-R requested review from a team as code owners October 19, 2026 08:04
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b701942d-2408-4c14-81f5-2851f0b93664
📥 Commits

Reviewing files that changed from the base of the PR and between bb56484 and c82fc13.

📒 Files selected for processing: 2
  • packages/core/realtime-js/src/lib/serializer.ts
  • packages/core/realtime-js/test/serializer.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

📝 Summary

Summary by CodeRabbit

  • New Features
    • Realtime broadcasts now accept typed arrays and DataView values as binary payloads, alongside ArrayBuffer.
    • When a view covers only part of its underlying buffer, broadcasts include only the bytes within that view. JSON payload handling remains supported.

The serializer now recognizes typed-array and DataView payloads as binary user-broadcast pushes. It encodes only the bytes within each view. JSON payload encoding and the shared push encoder now use Uint8Array data directly. Tests cover Uint8Array, a subarray with a nonzero offset, and DataView payloads.

Priority: ➖ Normal

Change: Bug fix

Merge Risk: ⚪ Minimal · up to c82fc

Joined WebSocket broadcasts now preserve typed-array and DataView bytes. The separate implicit REST fallback remains JSON-only; no actionable merge-blocking risk is established.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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