Files
suaveplan/openspec/archive/2026-05-12-network-transport-libp2p/proposal.md
2026-05-27 23:29:53 +01:00

6.6 KiB

OpenSpec Change: network-transport-libp2p

  • Change ID: network-transport-libp2p
  • Package: @suaveplan/network-transport-libp2p
  • Category: universal (browser + server)
  • Target path: packages/network/network-transport-libp2p
  • Status: PROPOSED
  • Date: 2026-05-11
  • Parent: network-transport-family (2026-05-11) — Wave 4
  • Migration source: ../suaveplan/packages/browser/network-libp2p + ../suaveplan/enterprise/network-libp2p.md
  • Supersedes: the original name reservation in this folder (2026-05-11)

Summary

Migrate @suaveplan/network-libp2p into genesis as @suaveplan/network-transport-libp2p — a universal-tier Transport over the libp2p stack (TCP, WebSockets, WebRTC, Noise, Yamux, identify, ping, mDNS, bootstrap, circuit-relay-v2). Largest single migration in the network family — the upstream package is the most complex transport with ≈1.1k LOC of source, 18+ external deps, and a 749-line React demo that must be extracted. Last in Wave 4 because every other transport landing first proves the patterns this migration consolidates.


Why this is last in Wave 4

  • Surface size. 9 source files, 18+ libp2p subpackage deps, real test coverage gaps.
  • Demo extraction. Upstream libp2p-demo.tsx is 749 LOC of React, violating the 300-line cap and adding React runtime deps to a universal-tier package.
  • Dep-graph risk. libp2p brings transitive deps that may conflict with already-shipped packages. Landing it last surfaces conflicts after lighter Wave-4 work has stabilised the catalog.

Current-state audit

Upstream source layout (../suaveplan/packages/browser/network-libp2p/src/lib/):

File LOC Notes
network-libp2p.ts 213 Libp2pTransport class
libp2p-connection.ts 205 node create + connect
libp2p-messaging.ts 167 stream messaging
libp2p.types.ts 119
send-to-peer.ts 73
stream-handler.ts 60 protocol handler registration
peer-message.ts 45 wire format
libp2p-demo.tsx 749 ❌ React UI — over 300-line cap and brings React runtime dep into universal package
libp2p-demo.stories.tsx 211
network-libp2p.test.ts 505 over 500-line test cap
network-libp2p.spec.ts 56 duplicate test file using vitest globals

Tests: only top-level Libp2pTransport is covered. libp2p-connection, libp2p-messaging, send-to-peer, stream-handler, peer-message have no dedicated tests.


Parity Checklist

Capability Upstream Migrated Notes
Transport contract impl partial ⬆️ NEW conformant adapter.
NetworkPlugin wrapper 🚫 ⬆️ Mirrors WebRTCPlugin shape.
TCP transport ✅ ✅ Server tier only.
WebSockets transport ✅ ✅ Universal.
WebRTC transport ✅ ✅ Browser tier — composes shipped network-transport-webrtc ✅ where applicable.
Noise encryption ✅ ✅
Yamux muxer ✅ ✅
Identify / ping protocols ✅ ✅
mDNS discovery ✅ ✅ Server tier only.
Bootstrap node list ✅ (defaults present) ⬆️ Bootstrap list REQUIRED in options; no public-bootstrap fallback. Constructor throws INVALID_OPTIONS if missing.
Circuit-relay-v2 ✅ ✅
Stream-based request/response ✅ ✅
Wire-format peer message ✅ ✅ Re-use @suaveplan/serialize.
749-line libp2p-demo.tsx ✅ 🚫 Extracted to a separate companion package @suaveplan/react-network-libp2p-demo (Wave 7). This migration drops it from the transport package.
Storybook .stories.tsx ✅ 🚫 Extracted with the demo.
React/react-dom runtime deps ✅ ❌ 🚫 Removed — universal-tier package must not pull React.
Duplicate .spec.ts test file ❌ 🚫 DELETED. .spec.ts reserved for Playwright per CLAUDE.md.
505-line network-libp2p.test.ts ❌ (over cap) ⬆️ Split by responsibility into ≤500-line files.
Unit tests for libp2p-connection/-messaging/send-to-peer/stream-handler/peer-message 🚫 ⬆️ All authored fresh.
Structured errors 🚫 ⬆️ defineCodes("NET_LIBP2P", [...]): BOOTSTRAP_FAILED, DIAL_FAILED, STREAM_FAILED, PROTOCOL_NOT_SUPPORTED, IDENTIFY_REJECTED, INVALID_OPTIONS.
Zod boundary validation 🚫 ⬆️ Every public option struct.
OTel metrics partial (Libp2pMetrics type unused) ⬆️ Counters libp2p.connections_opened_total{outcome}, streams_opened_total, bytes_total{direction}; histograms libp2p.dial_ms, libp2p.stream_ttfb_ms.
AbortSignal 🚫 ⬆️ Threaded everywhere.
export * barrels check ⬆️ Convert to explicit named exports per §6a.
Test-runner imports direct vitest globals ⬆️ Rewrite to @suaveplan/testing/runner per §7.
100% test coverage 🚫 ⬆️ Bring to 100/100/100/100.
examples/ (if present) check ✅ Keep — lint-cleaned.

Available workspace deps on genesis

  • @suaveplan/network ✅
  • @suaveplan/network-plugin-transport-manager ✅
  • @suaveplan/network-transport-webrtc ✅ (composes for webrtc libp2p sub-transport)
  • @suaveplan/serialize ✅
  • @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/retry, @suaveplan/timing ✅
  • @suaveplan/testing ✅
  • External (add to root catalog under network-transport):
    • libp2p
    • @libp2p/tcp (server-only)
    • @libp2p/websockets
    • @libp2p/webrtc
    • @libp2p/bootstrap
    • @libp2p/circuit-relay-v2
    • @libp2p/echo
    • @libp2p/identify
    • @libp2p/interface
    • @libp2p/mdns (server-only)
    • @libp2p/ping
    • @chainsafe/libp2p-noise
    • @chainsafe/libp2p-yamux
    • @multiformats/multiaddr

NOT added: react, react-dom — demo lives in a separate package.


Acceptance gate

  1. bunx turbo lint typecheck test --filter=@suaveplan/network-transport-libp2p green.
  2. bunx turbo test:coverage --filter=@suaveplan/network-transport-libp2p 100/100/100/100.
  3. bun run docs:check green.
  4. No file > 300 LOC source (impl) or > 500 LOC tests.
  5. Zero React imports in this package's src/.
  6. Integration test: 2-peer dial across the webrtc sub-transport + 2-peer dial across websockets sub-transport; both complete envelope round-trips.
  7. STATUS.md row flipped.

Out of scope

  • The 749-line React demo — moves to @suaveplan/react-network-libp2p-demo in a future Wave-7 proposal.
  • libp2p bootstrap node hosting (deployment concern; user supplies bootstrap list).
  • IPFS / Kademlia DHT integration (separate proposal if needed).