# OpenSpec Change: enterprise-browser-network-libp2p - **Change ID**: enterprise-browser-network-libp2p - **Package**: `@suaveplan/network-libp2p` - **Category**: browser - **Target path**: `browser/network/network-libp2p` - **Status**: SUPERSEDED-BY-GENESIS-WAVE - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/network-libp2p.md` --- ## Summary Deliver `@suaveplan/network-libp2p` on the genesis branch from scratch at enterprise quality. The package provides the browser-side libp2p transport for `@suaveplan/network`, stitching together the canonical libp2p stack (WebSockets, WebRTC, Noise, Yamux, identify, ping, bootstrap, circuit-relay-v2) into a `Libp2pTransport` class with connection lifecycle, peer addressing, streaming messaging, and metrics. No React dependencies — demo UI moves to a companion package. --- ## Current-state audit (genesis) The package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/network` (`workspace:^`) | `Transport` interface, peer/connection types | | `@suaveplan/error` (`workspace:^`) | Typed libp2p errors | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/events` (`workspace:^`) | Event maps | | `@suaveplan/serialize` (`workspace:^`) | Wire message encoding | | `@suaveplan/schema-registry` (`workspace:^`) | Config schema registration | | `zod` (`catalog:forms`) | `Libp2pConfig` schema | | `@opentelemetry/api` (`catalog:observability`) | Connection/stream counters, latency histograms | | `tslib` (`catalog:build`) | Runtime helpers | External libp2p deps (from Bun catalog): `libp2p`, `@libp2p/websockets`, `@libp2p/webrtc`, `@libp2p/bootstrap`, `@libp2p/circuit-relay-v2`, `@libp2p/identify`, `@libp2p/ping`, `@libp2p/interface`, `@chainsafe/libp2p-noise`, `@chainsafe/libp2p-yamux`, `@multiformats/multiaddr`. No `react` / `react-dom` in runtime deps. Dev deps: `vitest`, `@vitest/coverage-istanbul`, `@playwright/test` (`catalog:testing`), `@suaveplan/testing workspace:^`. --- ## Preserved public API surface (from main branch) ```ts class Libp2pTransport { constructor(config: Libp2pConfig) start(): Promise stop(): Promise dial(addr: Multiaddr | string): Promise send(peerId: PeerId, protocol: string, message: Uint8Array): Promise request(peerId: PeerId, protocol: string, message: Uint8Array): Promise registerHandler(protocol: string, handler: StreamHandler): void unregisterHandler(protocol: string): void getConnectedPeers(): PeerId[] getMetrics(): Libp2pMetrics on(event: 'peer:connect', handler: (peer: Libp2pPeerInfo) => void): void on(event: 'peer:disconnect', handler: (peer: Libp2pPeerInfo) => void): void on(event: 'error', handler: (error: Error) => void): void } interface Libp2pConfig { listenAddresses?: string[] bootstrapPeers?: string[] // Must be explicit; no public defaults unless strict: false relayAddrs?: string[] enableWebRTC?: boolean enableWebSockets?: boolean strict?: boolean // Default true; rejects public bootstrap peers } interface Libp2pMetrics { connectionsOpened: number; streamsOpened: number; bytesIn: number; bytesOut: number } interface Libp2pPeerInfo { peerId: PeerId; multiaddrs: Multiaddr[]; protocols: string[] } type StreamHandler = (stream: Stream, connection: Connection) => Promise ``` --- ## New additions for genesis ### 1. Structured errors via `@suaveplan/error` Error codes: `LIBP2P_DIAL_FAILED`, `LIBP2P_STREAM_RESET`, `LIBP2P_UNSUPPORTED_TRANSPORT`, `LIBP2P_BOOTSTRAP_REJECTED`, `LIBP2P_RELAY_INVALID`. ### 2. Strict-mode bootstrap gate When `strict: true` (default), `Libp2pConfig.bootstrapPeers` must be explicitly supplied; throw `LIBP2P_BOOTSTRAP_REJECTED` if the list is empty. Users who want public defaults must set `strict: false`. ### 3. Transport presets ```ts const presets = { browserP2P(): Libp2pConfig // WebRTC + WebSocket + Yamux + Noise + identify + ping browserBrowser(): Libp2pConfig // WebRTC only browserNode(): Libp2pConfig // WebSocket + circuit-relay } ``` ### 4. `Libp2pConfig` Zod schema Full runtime validation of config; registered in `@suaveplan/schema-registry`. ### 5. OTel metrics Counters `libp2p.connections_opened_total`, `libp2p.streams_opened_total`, `libp2p.bytes_in_total`, `libp2p.bytes_out_total`; histograms `libp2p.dial_ms`, `libp2p.stream_ttfb_ms`. ### 6. Relay-addr validator `validateRelayAddrs(addrs)` checks multiaddr format and rejects obviously insecure patterns. --- ## File layout ```text browser/network/network-libp2p/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts lib/ libp2p-connection/ libp2p-connection.ts libp2p-connection.md libp2p-connection.test.ts index.ts libp2p-messaging/ libp2p-messaging.ts libp2p-messaging.md libp2p-messaging.test.ts index.ts peer-message/ peer-message.ts peer-message.md peer-message.test.ts index.ts send-to-peer/ send-to-peer.ts send-to-peer.md send-to-peer.test.ts index.ts stream-handler/ stream-handler.ts stream-handler.md stream-handler.test.ts index.ts transport/ libp2p-transport/ libp2p-transport.ts libp2p-transport.md libp2p-transport.types.ts libp2p-transport.test.ts index.ts presets/ presets/ presets.ts presets.md presets.test.ts index.ts config/ config-schema/ config-schema.ts config-schema.md index.ts tests/ integration.test.ts e2e/ libp2p.spec.ts (two real libp2p nodes, echo protocol) ``` --- ## Impact **Downstream**: P2P networking layers, drive distribution, real-time collaboration. **Breaking changes**: `react` / `react-dom` removed from runtime deps (demo relocated). **Prerequisites**: `@suaveplan/network`, `@suaveplan/serialize`, `@suaveplan/error`, `@suaveplan/events` on Verdaccio.