Skip to content

feat(transport): websocket transport support#290

Open
o-az wants to merge 2 commits intomainfrom
o-az/ws-transport-support
Open

feat(transport): websocket transport support#290
o-az wants to merge 2 commits intomainfrom
o-az/ws-transport-support

Conversation

@o-az
Copy link
Copy Markdown
Member

@o-az o-az commented Apr 2, 2026

Adds a working end-to-end websocket transport for tempo.session().

This keeps the initial 402 bootstrap over HTTP, then moves the rest of the session flow onto the websocket: initial auth, mid-stream voucher top-ups, final stop/close, and settlement receipt. The app layer only sees streamed content.

Also fixes a few issues that showed up once the flow was exercised end to end:

  • close() on an active websocket now does an explicit stop/finalize handshake before signing the final close credential
  • payment control frames no longer leak to app listeners
  • websocket voucher/close signing is pinned to the active socket’s challenge/session state
  • added integration coverage for the normal websocket flow and mid-stream close path

Includes a runnable examples/session/ws demo:

CleanShot.2026-04-02.at.15.25.31.mp4

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 2, 2026

Open in StackBlitz

npm i https://pkg.pr.new/mppx@290

commit: 6c122c6

@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 2, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​ws@​8.18.11001007480100
Updatedws@​8.19.0 ⏵ 8.20.09810010090100

View full report

@tempoxyz-bot
Copy link
Copy Markdown

tempoxyz-bot commented Apr 2, 2026

👁️ Cyclops Security Review

6c122c6

🧭 Auditing · mode=normal · workers 0/3 done (3 left) · verify pending 0

Worker Engine Progress Status
pr-290-w1 gemini-3.1-pro-preview 🔍 thread-1 · · Running
pr-290-w2 amp/deep 🔍 thread-1 · · Running
pr-290-w3 gpt-5.4 🔍 thread-1 · · Running
⚙️ Controls
  • 🚀 Keep only 1 remaining iteration per worker after the current work finishes.
  • 👀 Keep only 2 remaining iterations per worker after the current work finishes.
  • ❤️ Let only worker 1 continue; other workers skip queued iterations.
  • 😄 Let only worker 2 continue; other workers skip queued iterations.
  • 🎉 End faster by skipping queued iterations and moving toward consolidation.
  • 😕 Stop active workers/verifiers now and start consolidation immediately.

📜 3 events

🔍 pr-290-w1 iter 1/3 [audit-ripple.md]
🔍 pr-290-w3 iter 1/3 [audit-deep-focus.md]
🔍 pr-290-w2 iter 1/3 [audit-focused.md]

@brendanjryan
Copy link
Copy Markdown
Collaborator

brendanjryan commented Apr 2, 2026

left some comments on overall design -- especially given sensitivity here for security flows

kicked off a cyclops run too

can you attach a diagram / flow of the state machine? is hard to understand from code alone

@o-az
Copy link
Copy Markdown
Member Author

o-az commented Apr 2, 2026

@brendanjryan
Fair call. This is still pretty procedural. The goal of this PR wasn’t to land the final abstraction so much as to get a working end-to-end websocket shape for tempo.session() that we can actually use and evaluate.

so I'm thinking of it as implementation-first, not protocol-final:

  • HTTP 402 bootstrap
  • in-band websocket auth / voucher top-ups / close
  • final settlement still delegated to the existing session semantics

In other words, it's not “this is now the protocol”. It’s more “this is a concrete state machine that works, and we can use it to decide what the right generalized protocol shape should be.”

Added a verbose diagram below since I agree it’s hard to reason about from code alone.

stateDiagram-v2
  [*] --> Idle

  Idle --> Probe402: client GET /ws/chat (HTTP)
  Probe402 --> WsConnect: 402 + Payment challenge
  Probe402 --> Failed: no challenge / invalid challenge

  WsConnect --> AwaitAuthReceipt: open websocket\n send initial authorization frame
  WsConnect --> Failed: ws open fails

  AwaitAuthReceipt --> Streaming: server verifies open\n sends payment-receipt
  AwaitAuthReceipt --> Failed: payment-error / socket close

  Streaming --> AwaitVoucher: server sends payment-need-voucher
  AwaitVoucher --> Streaming: client sends higher cumulative voucher\nserver verifies + sends payment-receipt

  Streaming --> AwaitCloseReady: client requests close
  AwaitVoucher --> AwaitCloseReady: client requests close while paused for coverage

  AwaitCloseReady --> AwaitCloseReceipt: server stops stream\ncomputes final spent\nsends payment-close-ready\nclient signs final close credential
  AwaitCloseReady --> Failed: payment-error / socket close

  AwaitCloseReceipt --> Settled: server verifies close\nsettles onchain\nsends payment-receipt
  AwaitCloseReceipt --> Failed: payment-error / socket close

  Settled --> Closed: websocket closes
  Closed --> [*]
  Failed --> [*]

Loading

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.

3 participants