Skip to content

About

React hooks and a provider for the browser WebTransport API

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

react-webtransport

React hooks and a provider for the browser WebTransport API. It keeps one connection, datagram reader, and datagram writer behind a small React API and leaves the underlying byte streams intact.

The package pairs naturally with channels-webtransport, but it does not depend on Django or prescribe an application protocol.

0.0.x is experimental. Browser WebTransport and the companion Channels ASGI contract are still evolving.

Backend compatibility: channels-webtransport 0.0.1 currently uses PyWebTransport 0.20.1. PyWebTransport documents that browser clients are not interoperable yet, with the matching Chrome issue still open. The React package works with native browser WebTransport, but a real browser cannot currently reach that Django backend until its transport dependency fixes the protocol mismatch.

Install

bun add react-webtransport

WebTransport requires a secure context and an HTTP/3-capable server. For local self-signed certificates, pass a SHA-256 certificate hash through serverCertificateHashes; the certificate must be short-lived enough for the browser to accept it.

Provider

import {
  WebTransportProvider,
  useWebTransport,
  useWebTransportDatagrams,
} from "react-webtransport";

function App() {
  return (
    <WebTransportProvider
      url={async () => {
        const response = await fetch("/api/webtransport-ticket", { method: "POST" });
        const { url } = await response.json();
        return url;
      }}
    >
      <RealtimePanel />
    </WebTransportProvider>
  );
}

function RealtimePanel() {
  const { status, connect, reconnect, close } = useWebTransport();
  const { send, sendJson } = useWebTransportDatagrams({
    onDatagram: (bytes) => console.log("raw", bytes),
    onJson: (value) => console.log("json", value),
    onJsonError: ({ error, data }) => console.warn("not JSON", error, data),
  });

  return (
    <>
      <p>{status}</p>
      <button onClick={() => void connect()}>Connect</button>
      <button onClick={() => void reconnect()}>Refresh ticket and reconnect</button>
      <button onClick={() => void send(new TextEncoder().encode("hello"))}>Send bytes</button>
      <button onClick={() => void sendJson({ type: "ping" })}>Send JSON</button>
      <button onClick={() => void close()}>Close</button>
    </>
  );
}

autoConnect defaults to true. Set it to false when connection setup must follow a user action. A URL resolver runs for every connect() and reconnect(), making short-lived ticket query parameters straightforward.

Keep an inline options object stable with useMemo; changing url, options, or transportFactory replaces the provider's controller and closes the previous session.

Streams

Streams remain raw Web Streams. The package deliberately adds no record framing:

const { createBidirectionalStream } = useWebTransportStreams();
const stream = await createBidirectionalStream();

const writer = stream.writable.getWriter();
await writer.write(new TextEncoder().encode("request bytes"));
await writer.close();

const reader = stream.readable.getReader();
const response = await reader.read();

Version 0.0.1 exposes client-created bidirectional and unidirectional streams, matching channels-webtransport 0.0.1. It does not add stream message framing or server-created stream helpers.

Optional fails-components adapter

Install the optional peer and import the explicit subpath:

bun add @fails-components/webtransport
import { failsTransportFactory } from "react-webtransport/fails";

<WebTransportProvider url={url} transportFactory={failsTransportFactory}>
  {children}
</WebTransportProvider>;

@fails-components/webtransport can fall back to its own WebSocket protocol. That fallback requires the corresponding fails-components server and is not implemented by channels-webtransport. Native WebTransport remains this package's default and has no extra runtime dependency.

Django Channels

Use a normal Channels-style consumer on the Python side:

from channels_webtransport import AsyncWebTransportConsumer


class EchoConsumer(AsyncWebTransportConsumer):
    async def receive_datagram(self, data: bytes) -> None:
        await self.send_datagram(data)

    async def receive_stream(self, stream: int, data: bytes, end_stream: bool) -> None:
        await self.send_stream(stream, data, end_stream=end_stream)

Authenticate the WebTransport CONNECT request with scope headers or, more conveniently in a browser, a short-lived ticket embedded in the URL returned by the provider's async resolver.

API

  • WebTransportProvider — owns a shared connection.
  • useWebTransport() — state plus connect, reconnect, and close.
  • useWebTransportDatagrams() — raw/JSON subscriptions plus send and sendJson.
  • useWebTransportStreams() — raw stream creation methods.
  • WebTransportController — the same lifecycle as an imperative API.
  • nativeTransportFactory — the default browser constructor adapter.
  • react-webtransport/fails — optional fails-components factory.

There is no automatic reconnect, outgoing queue, or replay. Sending while disconnected rejects with WebTransportClientError and code NOT_CONNECTED.

Development and browser test

bun install
bun run check
bun run test:e2e

The E2E script installs the Django example, generates a 13-day localhost certificate, starts a browser-compatible HTTP/3 echo server from @fails-components/webtransport, serves the React example with Vite, and drives Chromium through agent-browser. It verifies native WebTransport connection state, raw datagrams, JSON datagrams, and a bidirectional stream over real QUIC. The separate Django example is kept as the intended Channels integration and can be exercised once PyWebTransport's browser incompatibility is resolved upstream.

MIT licensed.

About

React hooks and a provider for the browser WebTransport API

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages