Skip to content

Add opt-in 8-byte-aligned binary framing for WebSocket and HTTP batch RPC - #291

Draft
teamchong wants to merge 2 commits into
cloudflare:mainfrom
teamchong:feat/binary-framing
Draft

teamchong wants to merge 2 commits into
cloudflare:mainfrom
teamchong:feat/binary-framing

Conversation

@teamchong

Copy link
Copy Markdown
Collaborator

Builds on jsonCompatibleWithBytes from #186 to support native binary framing over WebSocket (src/websocket.ts) and HTTP batch (src/batch.ts) without Base64 overhead.

Problem

Even with RpcTransportWithCustomEncoding (encodingLevel: "jsonCompatibleWithBytes"), the built-in WebSocket and HTTP batch transports still used encodingLevel: "string", Base64-encoding every Uint8Array, ArrayBuffer, and TypedArray inside JSON text frames (+33% wire size and encode/decode copies).

Mechanism

Adds a compact binary frame codec (encodeBinaryFrame / decodeBinaryFrame in src/serialize.ts) and wires WebSocketFrameTransport, BatchClientTransport, and BatchServerTransport onto RpcTransportWithCustomEncoding (encodingLevel: "jsonCompatibleWithBytes"):

  • 8-byte-aligned frame layout:
    • Bytes 0..3: \x89CWB magic
    • Bytes 4..7: little-endian uint32 UTF-8 JSON header byte length
    • Bytes 8..8+headerByteLength: UTF-8 JSON header where ["bytes", Uint8Array, typeName?] leaves are replaced by ["bytes", attachmentIndex, byteOffset, byteLength, typeName?] (and literal arrays beginning with "bytes" and a number/null second element are escaped as ["bytes", null, ...])
    • 0..7 zero padding bytes to align the attachments section to an 8-byte boundary
    • Concatenated raw binary attachments, each padded to an 8-byte boundary
  • Zero-copy decode on little-endian platforms: decodeBinaryFrame slices 8-byte-aligned Uint8Array views into the frame's ArrayBuffer, and Evaluator constructs Float64Array, Int32Array, DataView, etc. directly over view.buffer at view.byteOffset when aligned.
  • Backward-compatible negotiation (options.binary?: boolean):
    • WebSocket: defaults to text JSON frames when options.binary is omitted, accepts both text and binary frames on receive, and auto-upgrades replies to binary after receiving a binary frame from the peer. Setting options.binary: true sends binary frames immediately; options.binary: false keeps outgoing frames as text.
    • HTTP batch: sends Content-Type: application/x-capnweb-bin when options.binary: true (or when Request has Content-Type: application/x-capnweb-bin), and advertises Accept: application/x-capnweb-bin, text/plain;q=0.9, */*;q=0.8 unless options.binary === false. Server handlers (newHttpBatchRpcResponse, nodeHttpBatchRpcResponse) auto-detect binary requests by Content-Type or \x89CWB magic and reply in binary when requested or accepted.
Before:
["push",["pipeline",0,"echo",[["bytes","AQIDBA==","Int32Array"]]]]

After (application/x-capnweb-bin / WebSocket binary frame):
\x89CWB + uint32le(headerLen) + ["push",["pipeline",0,"echo",[["bytes",0,0,4,"Int32Array"]]]] + pad8 + <4 raw bytes>

@changeset-bot

changeset-bot Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5e80fa9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/capnweb@291
npm i https://pkg.pr.new/cloudflare/capnweb/capnweb-validate@291

commit: 5e80fa9

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