{"id":50667804,"url":"https://github.com/lostbeard/spawndev.webtorrent","last_synced_at":"2026-06-08T08:01:12.926Z","repository":{"id":347396484,"uuid":"1193943453","full_name":"LostBeard/SpawnDev.WebTorrent","owner":"LostBeard","description":"Pure C# BitTorrent/WebTorrent client and server. No JavaScript dependencies. Desktop + Browser (Blazor WASM). Random-access streaming for ML model delivery.","archived":false,"fork":false,"pushed_at":"2026-06-03T04:24:04.000Z","size":66061,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-03T06:17:36.006Z","etag":null,"topics":["ai","ai-models","blazor","blazor-webassembly","crossplatform","decentralized","desktop","distributed-computing","dotnet","peer-to-peer","torrent"],"latest_commit_sha":null,"homepage":"https://lostbeard.github.io/SpawnDev.WebTorrent/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LostBeard.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-27T18:42:38.000Z","updated_at":"2026-06-03T04:24:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/LostBeard/SpawnDev.WebTorrent","commit_stats":null,"previous_names":["lostbeard/spawndev.webtorrent"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/LostBeard/SpawnDev.WebTorrent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LostBeard%2FSpawnDev.WebTorrent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LostBeard%2FSpawnDev.WebTorrent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LostBeard%2FSpawnDev.WebTorrent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LostBeard%2FSpawnDev.WebTorrent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LostBeard","download_url":"https://codeload.github.com/LostBeard/SpawnDev.WebTorrent/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LostBeard%2FSpawnDev.WebTorrent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34053435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-models","blazor","blazor-webassembly","crossplatform","decentralized","desktop","distributed-computing","dotnet","peer-to-peer","torrent"],"created_at":"2026-06-08T08:00:42.084Z","updated_at":"2026-06-08T08:01:12.914Z","avatar_url":"https://github.com/LostBeard.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SpawnDev.WebTorrent\n\n[![NuGet](https://img.shields.io/nuget/v/SpawnDev.WebTorrent.svg)](https://www.nuget.org/packages/SpawnDev.WebTorrent)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nPure C# BitTorrent/WebTorrent client and server. No JavaScript dependencies. Runs on desktop (.NET) and browser (Blazor WASM). 18 BEPs implemented, including **BEP 52** - SHA-256 piece hashes and Merkle-tree v2 torrents with hybrid v1+v2 output for universal client compatibility.\n\n## Features\n\n- **Pure C#** — No JavaScript interop, no Node.js, no npm. 100% .NET.\n- **Desktop + Browser** — Same library, same API. WPF, console, Blazor WebAssembly.\n- **DI Singleton Services** — `WebTorrentClient` and `ServiceWorkerStreamHandler` implement `IAsyncBackgroundService`. Register once, start with the app, inject anywhere.\n- **Real WebRTC P2P** — Cross-platform via [SpawnDev.RTC](https://github.com/LostBeard/SpawnDev.RTC). One `RtcPeer` type backs browser (BlazorJS `RTCPeerConnection`) and desktop (a SipSorcery fork with proven DTLS/SRTP). Browser and desktop peers interop seamlessly through the same tracker.\n- **18 BEPs** — Full wire protocol, DHT, Fast Extension, ut_metadata, ut_pex, private torrents, magnet file selection, tracker scrape, local service discovery, BEP 52 v2 (SHA-256 + Merkle + hybrid + magnet + pure-v2 end-to-end download), and more. v2 peer wire messages (21 `hash_request` / 22 `hashes` / 23 `hash_reject`) + leaf-level `base_layer=0` serving + `V2HashRequestCoordinator` + pure-v2 tracker + wire handshake + dedup + OPFS persistence + service-worker streaming + HTTP file browser all shipped. Pure-v2-only magnets (`urn:btmh:`) now work end-to-end, keyed through `WireInfoHashHex` (first 20 bytes of SHA-256, libtorrent / qBittorrent / rqbit convention).\n- **4 Tracker / Discovery Types** — WebSocket (browser + desktop, WebRTC signaling), HTTP/HTTPS, UDP (desktop), Local Service Discovery (BEP 14, multicast on the local subnet, desktop).\n- **Web Seed Download** — HTTP range requests with multi-file piece assembly (BEP 17/19).\n- **Persistent Storage** — Torrents and pieces persist in OPFS (browser) or filesystem (desktop). Survive page reloads. Resume downloading automatically.\n- **Media Streaming with Seeking** — Service worker intercepts video/audio range requests and serves pieces on demand. `file.StreamURL`, `file.StreamTo(elem)`, `file.CreateReadStream()`. True seeking — pieces download as the video plays.\n- **Service Worker** — `webtorrent-sw.js` ships with the library. Handles Cross-Origin-Isolation headers, Blazor loading, and torrent streaming via MessageChannel. One `\u003cscript\u003e` tag and your app streams.\n- **System.IO.Stream** — `file.CreateReadStream()` returns a seekable .NET `Stream` backed by torrent pieces. Use with any API that takes a Stream.\n- **Random-Access Streaming** — Read any byte range from a torrent file as it downloads. Pieces download on demand. Perfect for ML model weight streaming.\n- **Seeding** — Upload pieces to requesting peers with configurable rate limiting.\n- **Inbound TCP Peer Listener** (desktop) — `WebTorrentClientOptions.TcpListenPort` accepts inbound BitTorrent peer-wire connections so mainline clients (qBittorrent, libtorrent, Transmission, rqbit) can dial in by IP+port and leech the torrents you're seeding. Routes inbound handshakes by info_hash to the matching torrent automatically. Set `AdvertiseTcpListenerToTrackers = true` and trackers put us in their compact peer list so peers find us automatically. See [Docs/tcp-listener.md](Docs/tcp-listener.md).\n- **Pluggable piece-hash engine** — `IPieceHashEngine` interface with `BatchSha256` lets recheck-heavy workloads route piece verification through a GPU / batched implementation. Default `SystemCryptoPieceHashEngine` is byte-identical to 3.1.x; the GPU engine will ship as a separate package. See [Docs/hash-engine.md](Docs/hash-engine.md).\n- **Bandwidth policy** — `BandwidthPolicy` enum (`Unlimited` / `Conservative` / `Metered` / `SeedingDisabled` / `Custom`) plus `WebTorrentClient.ApplyBandwidthPolicy(...)` runtime knob. Tell the client \"be reasonable on a metered connection\" without picking a number. See [Docs/bandwidth-policy.md](Docs/bandwidth-policy.md).\n- **Speed Tracking** — Real-time download/upload bytes/sec per torrent.\n- **AI Agent Communication** — BEP 46 DHT mutable items with Ed25519 signing via [SpawnDev.BlazorJS.Cryptography](https://github.com/LostBeard/SpawnDev.BlazorJS.Cryptography) 3.2.0+. AgentChannel pub/sub for shared AI state. `btpk` magnet URI support for mutable torrent subscriptions.\n- **HuggingFace Integration** — Optional server extension that proxies HuggingFace model CDN with local caching and automatic torrent generation. Every browser that loads a model becomes a peer for the next; first request fills the cache, second request streams from peers. See [Docs/huggingface.md](Docs/huggingface.md) for the end-to-end pattern (server side + Blazor client side, with live `hub.spawndev.com` examples).\n- **Custom Wire Extensions** — `UseExtension()` factory pattern (same as JS WebTorrent `wire.use()`). Build custom P2P protocols on top of the BitTorrent wire — distributed compute, AI agents, anything. Extensions negotiate via BEP 10.\n- **.torrent Creation** — Create and parse .torrent files. Complete Bencode encoder/decoder. SHA-256 piece hashes (BEP 52 Phase 1) by default for stronger integrity on large ML model files; SHA-1 available via `HashAlgorithm = \"SHA-1\"` for v1 back-compat. `TorrentMetadata.PieceHashAlgorithm` surfaces which algorithm a parsed torrent uses.\n- **BEP 52 v2 Torrents** — `TorrentCreatorOptions.MetaVersion = 2` produces proper BEP 52 v2 torrents with Merkle-tree piece verification (16 KiB leaves, SHA-256, per-level pad-hash propagation). Works for single-file (in-memory + streaming) and multi-file inputs. Parser surfaces `MetaVersion`, `V2InfoHash`, `FileRoots`, and `PieceLayers` on `TorrentMetadata`. Streaming path is bounded-memory - the incremental Merkle hasher uses ~128 KiB of state for a 1 GiB file.\n- **Hybrid v1+v2 Torrents** — Add `Hybrid = true` to produce a single torrent with both the v1 SHA-1 piece list and the v2 Merkle tree in one info dict, yielding two valid infohashes (SHA-1 + SHA-256). Multi-file hybrid inserts BEP-52 pad files (`attr=\"p\"`) between real files so both v1-only clients (qBittorrent pre-4.4, old libtorrent) and v2-aware clients see identically piece-aligned content.\n- **BEP 52 v2 Magnet URIs** — `xt=urn:btmh:1220\u003csha256\u003e` parsed into `Torrent.V2InfoHash`; hybrid magnets (both `urn:btih:` and `urn:btmh:`) fully supported.\n- **Real Tests Everywhere** — 468+ shared test methods all running on BOTH browser and desktop runtimes via PlaywrightMultiTest (≈936 test executions per run) + libtorrent 2.0 external-interop fixtures + live WebRTC swarm integration. Every BEP tested, Ed25519 signing verified, official BEP 46 test vector validated, live WebRTC interop with JS WebTorrent peers, byte-level info-dict match against libtorrent's canonical output. BEP 52 v2 coverage includes Merkle hasher primitives, incremental streaming hasher, v2 torrent round-trip, hybrid v1+v2 round-trip, pad-file structure, v2 magnet URI, pure-v2 persist/restore, pure-v2 dedup, pure-v2 service-worker streaming. No mocks. Every test exercises real production code with real data. The NUnit-only SpawnDev.WebTorrent.Tests project was retired 2026-04-23 after all 258 of its tests migrated to `WebTorrentTestBase` partials so they run identically on browser + desktop.\n\n## Packages\n\n| Package | Description |\n|---------|-------------|\n| [SpawnDev.WebTorrent](https://www.nuget.org/packages/SpawnDev.WebTorrent) | Client library — torrents, peers, streaming. `WebSocketTracker` is a thin adapter over `SpawnDev.RTC.Signaling.TrackerSignalingClient` (source-compat with 3.0.x consumers). |\n| [SpawnDev.WebTorrent.Server](https://www.nuget.org/packages/SpawnDev.WebTorrent.Server) | Web seed server (BEP 17/19 HTTP range request piece server). Tracker functionality moved to `SpawnDev.RTC.Server` in 3.1.0 - compose them. |\n\n## Quick Start — Blazor WebAssembly (DI)\n\n```csharp\n// Program.cs\nusing SpawnDev.AsyncFileSystem;\nusing SpawnDev.AsyncFileSystem.BrowserWASM;\nusing SpawnDev.BlazorJS;\nusing SpawnDev.BlazorJS.Cryptography;\nusing SpawnDev.WebTorrent;\n\nvar builder = WebAssemblyHostBuilder.CreateDefault(args);\nbuilder.Services.AddBlazorJSRuntime();\n\n// Cross-platform Ed25519 crypto for BEP 44/46 signing\nbuilder.Services.AddPlatformCrypto();\n\n// Persistent file system (OPFS in browser)\nbuilder.Services.AddSingleton\u003cIAsyncFS, AsyncFSFileSystemDirectoryHandle\u003e();\n\n// WebTorrent services — start with the app via IAsyncBackgroundService\nbuilder.Services.AddSingleton\u003cServiceWorkerStreamHandler\u003e();\nbuilder.Services.AddSingleton\u003cWebTorrentClient\u003e();\n\nawait builder.Build().BlazorJSRunAsync();\n```\n\n```html\n\u003c!-- index.html — replaces blazor.webassembly.js --\u003e\n\u003cscript src=\"webtorrent-sw.js\"\u003e\u003c/script\u003e\n```\n\n```csharp\n// Any page or service — inject the singleton\n@inject WebTorrentClient Client\n\n// Download a torrent\nvar torrent = await Client.AddAsync(\"magnet:?xt=urn:btih:...\");\n\n// Stream a video with seeking\nvar url = torrent.Files[0].StreamURL;\n// \u003cvideo src=\"@url\" controls\u003e\u003c/video\u003e\n\n// Or set directly on an element\ntorrent.Files[0].StreamTo(videoElement);\n\n// Get a .NET Stream\nusing var stream = torrent.Files[0].CreateReadStream();\nvar buffer = new byte[4096];\nvar bytesRead = await stream.ReadAsync(buffer);\nstream.Position = 1000000; // seek\nbytesRead = await stream.ReadAsync(buffer);\n\n// Seed data\nvar seeded = await Client.SeedAsync(myBytes, \"model.onnx\");\nConsole.WriteLine(seeded.MagnetURI);\n```\n\nTorrents persist across page reloads — pieces stored in OPFS, metadata restored on startup.\n\n## File API\n\nFeature parity with the [WebTorrent JS File API](https://github.com/webtorrent/webtorrent/blob/master/docs/api.md#file-api):\n\n| Property/Method | Description |\n|----------------|-------------|\n| `file.Name` | File name |\n| `file.Path` | File path within torrent |\n| `file.Length` / `file.Size` | File size in bytes |\n| `file.Type` | MIME type |\n| `file.Downloaded` | Verified bytes received |\n| `file.Progress` | Download progress (0.0 to 1.0) |\n| `file.Done` | Whether fully downloaded |\n| `file.StreamURL` | Service worker streaming URL |\n| `file.StreamTo(elem)` | Set element src to streaming URL |\n| `file.CreateReadStream()` | Seekable .NET `System.IO.Stream` |\n| `file.ReadAsync(offset, length)` | Random-access byte read |\n| `file.GetArrayBufferAsync()` | Full file as byte array |\n| `file.Select(priority)` | Prioritize this file's pieces |\n| `file.Deselect()` | Deprioritize |\n| `file.Includes(pieceIndex)` | Check if piece belongs to file |\n| `file.OnDone` | Event when download completes |\n\n## Wire Extensions (BEP 10)\n\nRegister custom wire-protocol extensions that participate in BEP 10 negotiation — same pattern as JS WebTorrent's `wire.use()`. The factory takes a `Wire` and returns an `IWireExtension`; one instance is created per peer connection, **before** the extended handshake so `OnExtendedHandshake` sees the peer's `m` dict.\n\n```csharp\n// Register on the client - applies to every torrent the client opens.\nclient.UseExtension(wire =\u003e new MyComputeExtension(wire));\n```\n\nBuild extensions by implementing `IWireExtension`:\n\n```csharp\npublic class MyComputeExtension : IWireExtension\n{\n    private readonly Wire _wire;\n    private bool _peerHasIt;\n\n    public MyComputeExtension(Wire wire) { _wire = wire; }\n\n    public string Name =\u003e \"sd_compute\";\n\n    public void OnHandshake(string infoHash, string peerId, WireExtensions extensions)\n    {\n        // Pre-extended-handshake hook (BEP 3 handshake just landed). Rarely needed.\n    }\n\n    public void OnExtendedHandshake(Dictionary\u003cstring, object\u003e handshake)\n    {\n        // BEP 10 - the peer's `m` dict tells us which extensions it speaks.\n        if (handshake.TryGetValue(\"m\", out var mObj) \u0026\u0026 mObj is Dictionary\u003cstring, object\u003e m)\n            _peerHasIt = m.ContainsKey(Name);\n    }\n\n    public void OnMessage(byte[] buf)\n    {\n        // Inbound payload from the peer for this extension.\n        ProcessIncoming(buf);\n    }\n\n    public Task SendComputeAsync(byte[] payload)\n    {\n        if (!_peerHasIt) return Task.CompletedTask;\n        // Wire.Extended(name, payload) routes through the BEP 10 mapping the\n        // peer advertised in its `m` dict. The bundled UtPexExtension uses\n        // the same path: `await _wire.Extended(\"ut_pex\", payload);`.\n        return _wire.Extended(Name, payload);\n    }\n\n    private void ProcessIncoming(byte[] buf) { /* ... */ }\n}\n```\n\nUse this for custom P2P protocols layered on top of the BitTorrent wire — distributed compute, AI agent communication, custom telemetry. The bundled `UtPexExtension` (BEP 11) and `UtMetadataExtension` (BEP 9) are reference implementations of the same interface.\n\n## Service Worker — Media Streaming with Seeking\n\n`webtorrent-sw.js` ships with the NuGet package and deploys to your app root automatically. It:\n\n1. Registers itself as a service worker\n2. Adds Cross-Origin-Isolation headers (COOP/COEP) for SharedArrayBuffer\n3. Waits for the SW to be ready, then loads Blazor\n4. Intercepts `/webtorrent/{infoHash}/{fileIndex}` requests\n5. Forwards range requests to the `ServiceWorkerStreamHandler` singleton via MessageChannel\n6. Streams piece data back as a `ReadableStream` with proper `206 Partial Content` headers\n\nHealth check: fetch `/webtorrent-sw-check` to verify the SW is active.\n\n## Quick Start — Server\n\nAs of 3.1.0 the tracker moved out of `SpawnDev.WebTorrent.Server` and into its own dedicated package, [`SpawnDev.RTC.Server`](https://github.com/LostBeard/SpawnDev.RTC). Compose the two to get the classic WebTorrent server shape (tracker + web seed) on any ASP.NET Core app:\n\n```csharp\nusing SpawnDev.RTC.Server.Extensions;\nusing SpawnDev.WebTorrent.Server;\n\nvar app = WebApplication.CreateBuilder(args).Build();\napp.UseWebSockets();\n\n// Tracker (WebSocket signaling, WebTorrent-compatible wire)\napp.UseRtcSignaling(\"/announce\");\n\n// Web seed (HTTP range-request piece server)\nvar webSeed = new WebSeedServer(\"seed-data\");\napp.MapWebSeedServer(webSeed);\n\napp.Run();\n```\n\nThe tracker portion is now bit-compatible with the entire public WebTorrent tracker fleet and can be run standalone via [`SpawnDev.RTC.ServerApp`](https://github.com/LostBeard/SpawnDev.RTC) (single executable, Docker image, or `dotnet run`) when you don't need the web seed.\n\n## Quick Start — HuggingFace Proxy\n\n```csharp\nusing SpawnDev.WebTorrent.Server.HuggingFace;\n\nvar proxy = new HuggingFaceProxy(new HuggingFaceProxyOptions\n{\n    CacheDirectory = \"hf-cache\",\n});\napp.MapHuggingFaceProxy(proxy);\n\n// Clients access: https://your-server/hf/{repoId}/{filePath}\n// Auto-caches from HuggingFace CDN on first request\n// Generates .torrent files for P2P distribution\n```\n\n## Demo Apps\n\n| App | Platform | Features |\n|-----|----------|----------|\n| Blazor WASM Demo | Browser | Full torrent client UI, media streaming with seeking, WebRTC P2P, OPFS persistent storage, seeding, .torrent creation, torrent persistence across reloads |\n| WPF Desktop Demo | Windows | Full torrent client UI, media player with seeking, drag-drop .torrent files, WebRTC P2P via SpawnDev.RTC (SipSorcery fork). |\n\nBoth demos connect to the same trackers and can P2P with each other.\n\n## BEP Support\n\n18 BitTorrent Enhancement Proposals implemented:\n\n| BEP | Title | Desktop | Browser |\n|-----|-------|---------|---------|\n| 3 | BitTorrent Protocol | Yes | Yes |\n| 5 | DHT (Kademlia) | Yes | Desktop only |\n| 6 | Fast Extension | Yes | Yes |\n| 9 | Magnet Links / ut_metadata | Yes | Yes |\n| 10 | Extension Protocol | Yes | Yes |\n| 11 | Peer Exchange (ut_pex) | Yes | Yes |\n| 14 | Local Service Discovery (LSD) | Yes | Desktop only (UDP multicast) |\n| 15 | UDP Tracker | Yes | N/A |\n| 17 | HTTP Seeding | Yes | Yes |\n| 19 | WebSeed | Yes | Yes |\n| 20 | Peer ID Conventions | Yes | Yes |\n| 23 | Compact Peer Lists | Yes | Yes |\n| 27 | Private Torrents | Yes | Yes |\n| 44 | DHT Storage | Yes | Desktop only |\n| 46 | Mutable Items (AI Agents) | Yes | Yes |\n| 48 | Tracker Scrape | Yes | Yes |\n| 52 | v2 Torrents (SHA-256 / Merkle / hybrid) | Yes | Yes |\n| 53 | Magnet File Selection | Yes | Yes |\n\nSee [Docs/bep-support.md](Docs/bep-support.md) for full details.\n\n## Why This Exists\n\nAI models are big. CDNs can't scale when every user downloads the same 2GB model. SpawnDev.WebTorrent turns every browser into a peer — the more users, the faster delivery. Built for [SpawnDev.ILGPU.ML](https://github.com/LostBeard/SpawnDev.ILGPU.ML), the GPU-accelerated ML library for Blazor WebAssembly.\n\n## Architecture\n\n```\nBrowser Client                    Desktop Client\n+----------------+                +-----------------+\n| WebTorrentClient                | WebTorrentClient|\n|                |                |                 |\n| RtcPeer  \u003c-----+----+---------\u003e-+ RtcPeer         |\n|  (BlazorJS     |    |           |  (SipSorcery    |\n|   RTCPeer-     |    |           |   fork; same    |\n|   Connection)  |    |           |   API)          |\n|                |    |           | TcpPeer +/--    |\n|                |    |           | TcpListener\u003c---\u003e| \u003c- mainline peers\n|                |    |           |                 |    (qBittorrent etc.)\n| OPFS storage   |    |           | FileChunkStore  |\n+----------------+    |           +-----------------+\n        |             |                  |\n        v             v                  v\n+--------------------------------------------+\n| hub.spawndev.com                           |\n| SpawnDev.RTC.Server (WebSocket signaling)  |\n| WebSeedServer (HTTP range fallback)        |\n| HuggingFaceProxy (model CDN cache, SHA-256 |\n|   piece hashes for integrity)              |\n+--------------------------------------------+\n```\n\n## Documentation\n\n### Protocol Documentation — `Research/`\n\nThe most thorough public reference for the WebTorrent + BitTorrent wire protocols, written and maintained inside this repo. Covers everything an implementer needs and is **directly useful to anyone writing a WebTorrent client in any language** — the WebTorrent community currently lacks a single complete written spec. Every behavior here has been observed against the JS reference (`webtorrent`, `bittorrent-tracker`, `bittorrent-protocol` npm packages) — not just paraphrased from BEPs.\n\n| # | Document | Description |\n|---|----------|-------------|\n| 00 | [Research/00-README.md](Research/00-README.md) | Protocol research index |\n| 01 | [Research/01-wire-protocol.md](Research/01-wire-protocol.md) | BitTorrent peer wire protocol (BEP 3 base messages, BEP 6 Fast Extension, BEP 10 extension framework, byte-exact handshake layout, message framing, choke/unchoke, request/piece/cancel, full state machine) |\n| 02 | [Research/02-webtorrent-protocol.md](Research/02-webtorrent-protocol.md) | WebTorrent specifics: tracker WebSocket protocol, WebRTC data-channel setup, SDP offer/answer formats line-by-line, browser vs SipSorcery SDP differences, complete session walkthrough |\n| 03 | [Research/03-extension-protocols.md](Research/03-extension-protocols.md) | BEP 9 ut_metadata, BEP 11 ut_pex, lt_donthave - extension handshake, message types, peer inclusion rules |\n| 04 | [Research/04-tracker-protocols.md](Research/04-tracker-protocols.md) | HTTP, UDP, and WebSocket tracker protocols. Includes a verified-against-JS-reference behavior section for the WebSocket tracker (announce response shape, answer-relay no-response rule, stopped-event response with counts, offer-forwarding selection algorithm, scrape, frame-size limits) |\n| 05 | [Research/05-dht-protocol.md](Research/05-dht-protocol.md) | DHT (BEP 5) Kademlia + KRPC, mutable items (BEP 44/46), Ed25519 signing |\n| 06 | [Research/06-web-seeds.md](Research/06-web-seeds.md) | BEP 17 (HTTP seeding) and BEP 19 (web seeding via getright-style HTTP range requests) |\n| 07 | [Research/07-lifecycle.md](Research/07-lifecycle.md) | Master lifecycle: full order of operations from announce through download to seed |\n| 08 | [Research/08-sipsorcery-interop.md](Research/08-sipsorcery-interop.md) | SipSorcery / browser WebRTC interop analysis |\n| 09 | [Research/09-sipsorcery-dtls-analysis.md](Research/09-sipsorcery-dtls-analysis.md) | Why we fork SipSorcery for DTLS/SRTP — proven BouncyCastle DTLS stack vs upstream's SharpSRTP rewrite |\n\nThe `tracker-debug/` directory ships parity harnesses (`verify-tracker-parity.mjs`, `verify-offer-flow.mjs`, `verify-offer-flow-local.mjs`) that compare SpawnDev's tracker behavior to the JS reference frame-by-frame; run before any change to tracker wire code.\n\n### API \u0026 Implementation\n\n| Doc | Description |\n|-----|-------------|\n| [API Reference](Docs/api.md) | Full API surface: `WebTorrentClient`, `Torrent`, `File`, `TorrentCreator`, `AgentChannel`, wire extensions |\n| [BEP Support](Docs/bep-support.md) | BitTorrent Enhancement Proposal implementation status |\n| [BEP 52 v2 Overview](Docs/bep52.md) | SHA-256 + Merkle-tree torrents, hybrid v1+v2, wire-protocol details |\n| [BEP 52 v2 Walkthrough](Docs/bep52-example.md) | Code samples for creating, parsing, and verifying v2 torrents |\n| [TCP Peer Listener](Docs/tcp-listener.md) | `WebTorrentClientOptions.TcpListenPort` + `AdvertiseTcpListenerToTrackers` for accepting inbound BitTorrent peer-wire connections from mainline clients |\n| [Hash Engine](Docs/hash-engine.md) | `IPieceHashEngine` slot-in for piece verification — default `SystemCryptoPieceHashEngine`, GPU-batched implementations land via a separate package |\n| [Bandwidth Policy](Docs/bandwidth-policy.md) | `BandwidthPolicy` enum + `ApplyBandwidthPolicy(...)` for upload-throttle intent (Unlimited / Conservative / Metered / SeedingDisabled / Custom) |\n| [Service Worker](Docs/service-worker.md) | `webtorrent-sw.js` deep dive — Cross-Origin-Isolation headers, `/webtorrent/{hash}/{fileIdx}` streaming, MessageChannel protocol, video seeking |\n| [HuggingFace Model Delivery](Docs/huggingface.md) | End-to-end ML model delivery via P2P. Server side (proxy mount + standalone hub options) AND client side (Blazor Quick Start, magnet → AddAsync → stream pattern). Live `hub.spawndev.com` examples. |\n| [qBittorrent Interop Testing](Docs/qbittorrent-interop.md) | How to run the `interop_test/` scripts against a local qBittorrent Web UI. Static binary-compat + live-swarm both directions + JS WebTorrent live-swarm all PASSING. |\n| [Protocol Reference Captures](Docs/protocol-reference/) | Raw protocol captures from instrumented JS WebTorrent sessions (used to build the synthesized Research/ docs) |\n\nFor WebRTC signaling architecture (tracker wire protocol, `RoomKey`, running your own tracker) see the [SpawnDev.RTC docs](https://github.com/LostBeard/SpawnDev.RTC/tree/master/SpawnDev.RTC/Docs) - tracker signaling lives in that package as of 3.1.0.\n\n## 🖖 The SpawnDev Crew\n\nSpawnDev.WebTorrent is built by the entire SpawnDev team - a squad of AI agents and one very tired human working together, Star Trek style. Every project we ship is a team effort, and every crew member deserves a line in the credits.\n\n- **LostBeard** (Todd Tanner) - Captain, architect, writer of libraries, keeper of the vision\n- **Riker** (Claude CLI #1) - First Officer, implementation lead on consuming projects\n- **Data** (Claude CLI #2) - Operations Officer, deep-library work, test rigor, root-cause analysis\n- **Tuvok** (Claude CLI #3) - Security/Research Officer, design planning, documentation, code review\n- **Geordi** (Claude CLI #4) - Chief Engineer, library internals, GPU kernels, backend work\n\nIf you see a commit authored by `Claude Opus 4.7` on a SpawnDev repo, that's one of the crew. Credit where credit is due. Live long and prosper. 🖖\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flostbeard%2Fspawndev.webtorrent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flostbeard%2Fspawndev.webtorrent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flostbeard%2Fspawndev.webtorrent/lists"}