Co-Authored-By: gpt-5.6-sol <noreply@openai.com>
webnet
A TypeScript monorepo for transport-based networking, anchored by a WebAssembly Tailscale SDK. It provides a layered stack of packages — from raw transport and virtual filesystem abstractions through HTTP, WebSocket, WebDAV, FTP, SSH, SFTP, SMB, and Taildrive — that work in browsers, Node.js, and any environment that can supply a transport.
Those packages exist to be composed into an application. That application is Tailshare.
Tailshare
packages/tailshare is the flagship application of this repository, and the reason the rest of it exists. It is a browser app that joins a tailnet directly from the page and moves files across it, and it is the intended surface for everything the stack implements: Tailscale connectivity over WebAssembly, remote filesystems browsed over the protocol packages, and peer-to-peer transfers with no server in the middle.
The other packages are libraries; Tailshare is the product. When a capability lands in a library package — or is planned in the open issues — Tailshare is where it is expected to become usable. example-app and test-app are development and protocol-testing surfaces, not the product.
Tailshare is under active development and does not yet expose the whole stack. Its README tracks what works today and what the open issues intend for it.
Inspiration
This is heavily inspired by the WebVM networking stack that leverages Tailscale in the browser. Note that this doesn't lift any code from that project, only ideas.
Another inspiration is the ElysiaJS documentation that seemingly allows running a webserver from the docs directly in the browser (even if it is just a feature of the framework itself and not real networking).
How it works
Tailscale already ships a tsconnect package that compiles the IPN (in-process networking) stack to WASM via GOARCH=wasm. This repo builds on top of that with a layered set of packages:
- Patching tsconnect: the
tailscalesubmodule tracks a fork on thewebnetbranch that extends the Go-to-JS bridge (wasm_js.go) to expose lower-level networking primitives: raw TCP/UDP connections, ICMP, TLS dialing, and TCP listening. @webnet/transport: declares theRawTransport,RawListener, andRawDialerinterfaces, plus buffer utilities and transport implementations for loopback, Node.js streams, and WebRTC.@webnet/state-transfer: provides the genericStateTransferableownership-transfer contract and runtime type guard without transport or protocol dependencies.@webnet/tsconnect: builds the WASM artifact, ships it alongside a Mozilla CA bundle andwasm_exec.js, and wraps the raw JS bridge in typed TypeScript classes. ItsConn,TCPListener, andIPNDialerimplement the@webnet/transportinterfaces, making it a drop-in transport source for the rest of the stack.@webnet/tsconnect-redux/@webnet/tsconnect-react: Redux Toolkit (RTK) slice and React hooks/context for IPN state management and control, extracted from the core SDK so consumers can bring their own UI framework.@webnet/tsconnect-worker: runs the IPN in aSharedWorker, synchronizes state through Redux, and can fall back to the main thread when workers are unavailable.@webnet/vfs: defines the shared async virtual filesystem used by the file protocols, with in-memory, Node.js, and File System Access API implementations.- Protocol packages: client and server implementations for HTTP, WebSocket, WebDAV, FTP/FTPS, SSH, and SFTP are built on the transport and VFS layers, alongside an SMB client.
@webnet/http-staticserves a VFS over HTTP, while@webnet/taildriveconnects WebDAV shares to Tailscale peers. - Apps and UI helpers: reusable browser and React utilities support the example and test applications, and above all Tailshare, the flagship app that composes the whole stack into a usable product.
Packages
Each package has its own README with entry points and usage; the table links to them.
| Package | Description |
|---|---|
packages/tailshare |
Flagship application: tailnet file sharing in the browser |
packages/transport |
Transport interfaces with loopback, Node.js streams, and WebRTC implementations |
packages/state-transfer |
Generic ownership-transfer contract and runtime type guard |
packages/tsconnect |
Tailscale WASM SDK, IPN lifecycle, typed wrappers, and transport implementation |
packages/tsconnect-worker |
SharedWorker and main-thread bindings for @webnet/tsconnect with Redux state synchronization |
packages/tsconnect-redux |
Redux Toolkit slice, bindings, actions, and selectors for IPN state management |
packages/tsconnect-react |
React hooks and context for IPN state management and control |
packages/vfs |
Async virtual filesystem interface, implementations, fallbacks, and conformance tests |
packages/http |
HTTP/1.1 client and server, connection pool, redirect following, and middleware router |
packages/http-static |
Static file HTTP handler backed by an async VFS |
packages/websocket |
WebSocket client and server based on @webnet/http |
packages/webdav |
WebDAV Level 1 and optional Level 2 client and server based on @webnet/http |
packages/ftp |
FTP/FTPS client and server backed by an async VFS |
packages/ssh |
SSH-2 client and server connections, channels, sessions, and TCP forwarding |
packages/sftp |
SFTP client and server backed by an async VFS |
packages/smb2 |
SMB2/3 client implementing the async VFS interface |
packages/taildrive |
Taildrive peer discovery, WebDAV client helpers, and server bridge |
packages/xml |
XML parsing and serialization with browser-native and Node.js backends |
packages/react |
Shared React hooks, error display, and browser capability helpers |
packages/utils |
Browser, binary-data, upload, download, and formatting utilities |
packages/browser-test-utils |
Shared Playwright utilities for browser integration tests |
packages/example-app |
Example app demonstrating the browser stack |
packages/test-app |
Vite app for manual and end-to-end protocol testing |
Submodules
The tailscale/ directory is a git submodule pointing to a fork of the Tailscale repository. The webnet branch on that fork contains the Go-side patches to tsconnect.
git submodule update --init tailscale
Development
# Build the WASM assets
npm run build-go --workspace=packages/tsconnect
# Build the TypeScript package
npm run build --workspace=packages/tsconnect
# Start the test app
npm run dev --workspace=packages/test-app
# Expose a development app to a trusted remote host or reverse proxy
npm run dev:host --workspace=packages/test-app
# Lint and format
npm run lint
npm run format
Remote-host development
Development apps provide two deliberate modes:
npm run dev --workspace=packages/<app>is local-only and retains the dev server's host-header protections.npm run dev:host --workspace=packages/<app>binds to all network interfaces and accepts forwarded hostnames. Use it only on a trusted network, such as a Tailnet or an authenticated code-server proxy: a dev server can expose source maps, development endpoints, and application credentials or state.
The hosted mode leaves the HMR websocket URL relative to the page URL, so it works through a reverse proxy without baking a container or localhost address into the app. Configure that proxy to forward WebSocket upgrade requests (Upgrade and Connection headers) to the dev server, including the Vite HMR endpoint or webpack-dev-server's /ws endpoint.
Commits must follow the Conventional Commits spec.
ESLint and Prettier are also required to pass.
This is enforced at commit time by husky with commitlint and lint-staged.
Package boundaries
Each package owns its public API. Packages may import another package's public entry points, but may not re-export those dependencies; consumers should import symbols from the package that defines them. Wildcard exports are also forbidden so API changes remain explicit and reviewable.
_internals entry points are intentionally unstable and carry no semantic
versioning compatibility guarantee. They are available only to their owning
package's tests and tooling. Cross-package _internals imports are forbidden in
both production and test code; tests should use public APIs or package-local
fixtures instead.
AI disclosure
Most of the code in this repository was AI-generated. The entire patch set in the Tailscale fork under tailscale/ was also AI-generated.