feat(wasm): expose taildrive WebDAV server and listDrivePeers via JS bridge #10

Merged
codinget merged 1 commits from feat/drive-wasm-bridge into webnet 2026-06-16 21:40:49 +02:00
Owner

Summary

  • Add drive.go: implements drive.FileSystemForRemote with a JS-backed streaming handler. The Go goroutine stays alive for the response duration; JS calls write(chunk)/end() to stream the body back. Request body is streamed chunk-by-chunk via readBodyChunk() (no full-body buffering).
  • Add drive_stub.go: no-op stubs for ts_omit_drive builds.
  • Add peer.go: buildPeerAPIURL helper extracted from the inline logic in run().
  • Modify wasm_js.go: call initDriveForRemote before NewLocalBackend (SubSystem is set-once), expose setDriveHandler and listDrivePeers via wireDriveJS, refactor peerAPI URL logic to use buildPeerAPIURL.

listDrivePeers mirrors native driveRemotesFromPeers: returns empty if DriveAccessEnabled() is false, filters peers by PeerCapabilityTaildriveSharer via the live ACL cap map (lb.PeerCaps(addr).HasCapability()).

Auth is fully handled by handleServeDrive in peerapi_drive.go before our code runs — the JS handler only receives pre-authenticated, permission-scoped requests.

Test plan

  • GOARCH=wasm GOOS=js ./tool/go vet ./cmd/tsconnect/wasm/ passes
  • GOARCH=wasm GOOS=js ./tool/go build ./cmd/tsconnect/wasm/ compiles cleanly
  • setDriveHandler wired up in the JS object returned by newIPN
  • listDrivePeers returns empty array when DriveAccessEnabled() is false
  • End-to-end: peer with drive:share ACL can be browsed via WebDAV from another node

The end-to-end item requires ACL nodeAttrs/grants/Taildrive support on the control plane, which only landed in Headscale v0.29.0 (not yet released stably — only v0.29.0-beta.4 exists as of writing). Deferred until a stable v0.29.0 release. webnet/webnet#27 has unit tests covering the JS-side bridge and IPN methods without requiring a live network.

🤖 Generated with Claude Code

## Summary - Add drive.go: implements drive.FileSystemForRemote with a JS-backed streaming handler. The Go goroutine stays alive for the response duration; JS calls write(chunk)/end() to stream the body back. Request body is streamed chunk-by-chunk via readBodyChunk() (no full-body buffering). - Add drive_stub.go: no-op stubs for ts_omit_drive builds. - Add peer.go: buildPeerAPIURL helper extracted from the inline logic in run(). - Modify wasm_js.go: call initDriveForRemote before NewLocalBackend (SubSystem is set-once), expose setDriveHandler and listDrivePeers via wireDriveJS, refactor peerAPI URL logic to use buildPeerAPIURL. listDrivePeers mirrors native driveRemotesFromPeers: returns empty if DriveAccessEnabled() is false, filters peers by PeerCapabilityTaildriveSharer via the live ACL cap map (lb.PeerCaps(addr).HasCapability()). Auth is fully handled by handleServeDrive in peerapi_drive.go before our code runs — the JS handler only receives pre-authenticated, permission-scoped requests. ## Test plan - [x] GOARCH=wasm GOOS=js ./tool/go vet ./cmd/tsconnect/wasm/ passes - [x] GOARCH=wasm GOOS=js ./tool/go build ./cmd/tsconnect/wasm/ compiles cleanly - [x] setDriveHandler wired up in the JS object returned by newIPN - [x] listDrivePeers returns empty array when DriveAccessEnabled() is false - [ ] End-to-end: peer with drive:share ACL can be browsed via WebDAV from another node The end-to-end item requires ACL `nodeAttrs`/`grants`/Taildrive support on the control plane, which only landed in Headscale v0.29.0 (not yet released stably — only `v0.29.0-beta.4` exists as of writing). Deferred until a stable v0.29.0 release. webnet/webnet#27 has unit tests covering the JS-side bridge and IPN methods without requiring a live network. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
codinget changed target branch from main to webnet 2026-06-09 23:01:53 +02:00
codinget force-pushed feat/drive-wasm-bridge from 7c5ecfe50f to 40e1346ab5 2026-06-16 12:35:15 +02:00 Compare
codinget marked the pull request as ready for review 2026-06-16 21:22:34 +02:00
codinget added 1 commit 2026-06-16 21:37:37 +02:00
Add drive.go (build tag !ts_omit_drive): implements drive.FileSystemForRemote
with a JS-backed handler. Streams request bodies chunk-by-chunk via
readBodyChunk() and response bodies via write()/end() callbacks so no
full-body buffering occurs regardless of file size. The handler is nil-safe:
returns 404 until setDriveHandler() is called from JS.

Add drive_stub.go (build tag ts_omit_drive): no-op stubs for stripped builds.

Add peer.go: extract buildPeerAPIURL helper (previously inline in run()).

Modify wasm_js.go: call initDriveForRemote before NewLocalBackend (SubSystem
is set-once), expose setDriveHandler and listDrivePeers via wireDriveJS,
and refactor the inline peerAPI URL logic to use buildPeerAPIURL.

listDrivePeers mirrors native driveRemotesFromPeers: returns empty if
DriveAccessEnabled() is false, then filters peers by PeerCapabilityTaildriveSharer
using lb.PeerCaps(addr).HasCapability() (the live ACL-derived cap map).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
codinget force-pushed feat/drive-wasm-bridge from 40e1346ab5 to cada6936b9 2026-06-16 21:37:37 +02:00 Compare
codinget merged commit cada6936b9 into webnet 2026-06-16 21:40:49 +02:00
codinget deleted branch feat/drive-wasm-bridge 2026-06-16 21:40:50 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: webnet/tailscale#10