# 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](https://libp2p.io) 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).