Skip to content

refactor(wasm): inject IO from JS instead of creating WebSockets internally#1111

Open
heeckhau wants to merge 5 commits intomainfrom
injectio
Open

refactor(wasm): inject IO from JS instead of creating WebSockets internally#1111
heeckhau wants to merge 5 commits intomainfrom
injectio

Conversation

@heeckhau
Copy link
Member

@heeckhau heeckhau commented Feb 16, 2026

Depends on #1100 — target branch will update to main after merge.

Summary

sdk-core extraction

Protocol logic (prover setup, TLS connection, request sending, reveal) is moved from the wasm crate
into a new sdk-core crate with no platform dependencies. The wasm crate becomes a thin
wasm_bindgen layer that converts JS types and delegates to sdk-core. This enables future
native/mobile SDK bindings that share the same core logic.

IO injection

WASM methods previously took URL strings and created WebSockets internally via ws_stream_wasm.
Now they accept an IoChannel object with read(), write(), close() methods, injected from JS.
sdk-core defines a platform-agnostic Io trait (AsyncRead + AsyncWrite + Send + Unpin)
with a WASM adapter (JsIoAdapter) that bridges JS Promises to Rust's async polling model.
The host environment controls transport creation, lifecycle, and error handling — WASM only consumes bytes.
Removes ws_stream_wasm (and transitively web-sys) from the WASM crate.

Browser event loop: fire-and-forget writes

The old poll_write started a JS Promise and polled it to completion. In the browser, this deadlocks:
the Rust future can't progress until the Promise resolves, but the Promise is a microtask blocked
behind the Rust future on the same single-threaded executor. Since WebSocket send() is synchronous
(it buffers internally), we skip awaiting the Promise entirely and return Ready immediately.
Same for poll_close. Errors surface on subsequent calls.

This is orthogonal to #1100, which fixes a different microtask saturation issue in the MPC actor loop.

Builds on #1100.

Testing

Tested end-to-end with the tlsn-extension:
proof generation completes successfully with IO injected from JavaScript via WebSocket.
tlsnotary/tlsn-extension#248

@heeckhau heeckhau requested review from sinui0 and th4s February 16, 2026 09:32
Base automatically changed from refactor/remove-actor to main February 23, 2026 17:58
heeckhau added 3 commits March 9, 2026 11:15
- Extract platform-agnostic sdk-core crate (SdkProver, SdkVerifier, BoxedIo, Io trait)
- WASM crate becomes thin binding layer injecting JS-backed IO streams
- Simplify AsyncWrite/poll_close to fire-and-forget pattern
Move HTTP transcript parsing and handler-to-byte-range mapping from
TypeScript into Rust sdk-core, using spansy for HTTP/JSON parsing.
This enables mobile (iOS/Android) reuse of the range extraction logic.

- Add Handler types (HandlerType, HandlerPart, HandlerAction, etc.)
- Add compute_reveal() that maps handlers to byte ranges via spansy
- Support all handler parts: start line, method, headers, body, regex
- Add WASM binding in crates/wasm via serde_wasm_bindgen
- Include comprehensive tests (24 test cases)
…o sdk-core

- Move platform-agnostic logging types (LoggingLevel, LoggingConfig,
  CrateLogFilter, SpanEvent) and filter logic to sdk-core so mobile
  can reuse them
- Replace tracing-web with wasm-tracing to remove web-sys from the
  WASM dependency tree
- Remove unused time crate dependency
- Clean up dead .with_timer().without_time() chain
heeckhau added 2 commits March 9, 2026 12:15
Replace Rc<RefCell> with Arc<Mutex> in JsIoAdapter to make the state
thread-safe, narrowing the unsafe Send impl to only cover the JsIo
JS handle. Handle mutex poison errors gracefully instead of panicking.

Make HyperIo::new safe by moving the unsafe into poll_read where
the actual MaybeUninit invariant lives, removing the burden from callers.
When a JS string body is passed through wasm-bindgen, it arrives as
serde_json::Value::String. Re-serializing this with serde_json::to_vec
wraps it in extra quotes, causing the HTTP parser to fail with
"trailing characters" errors.

Handle Value::String specially by using the raw string bytes directly.

Fixes tlsnotary/tlsn-extension#254
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