# Tasks: enterprise-browser-network-libp2p **Change ID**: enterprise-browser-network-libp2p **Package**: `@suaveplan/network-libp2p` **Target path**: `browser/network/network-libp2p` **Prerequisite packages on Verdaccio**: `@suaveplan/network`, `@suaveplan/serialize`, `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events` --- ## 1. Scaffold - [x] Create `browser/network/network-libp2p/` directory tree per layout in `proposal.md`. - [x] Write `package.json` at version `0.1.0` — no `react` / `react-dom` in runtime deps. - `dependencies`: `@suaveplan/network workspace:^`, `@suaveplan/serialize workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/events workspace:^`, all libp2p packages from Bun catalog, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `@playwright/test catalog:testing`, `@suaveplan/testing workspace:^` - [x] Write `tsconfig.json` and `vitest.config.ts` (pool: forks). --- ## 2. Error codes (`src/error-codes.ts`) - [x] Define `Libp2pErrorCode`: `LIBP2P_DIAL_FAILED`, `LIBP2P_STREAM_RESET`, `LIBP2P_UNSUPPORTED_TRANSPORT`, `LIBP2P_BOOTSTRAP_REJECTED`, `LIBP2P_RELAY_INVALID`. - [x] Export `registerLibp2pErrorCodes()` and call eagerly. --- ## 3. Config schema (`src/config/config-schema/`) - [x] Define `Libp2pConfigSchema` (Zod): - `listenAddresses?: string[]` - `bootstrapPeers?: string[]` — required when `strict: true` - `relayAddrs?: string[]` — validated by `validateRelayAddrs()` - `enableWebRTC?: boolean`, `enableWebSockets?: boolean`, `strict?: boolean` (default `true`) - [x] Export `validateLibp2pConfig(config)` throwing `LIBP2P_BOOTSTRAP_REJECTED` when strict + empty bootstrap list. - [x] Register schema in `@suaveplan/schema-registry`. - [x] Write `config-schema.md`. --- ## 4. Presets (`src/presets/presets/`) - [x] Implement `presets.browserP2P()`, `presets.browserBrowser()`, `presets.browserNode()` returning valid `Libp2pConfig` objects. - [x] Write `presets.test.ts` asserting each preset passes schema validation and has non-empty transport list. - [x] Write `presets.md`. --- ## 5. Peer message (`src/lib/peer-message/`) - [x] Define `PeerMessage` wire format with `protocol`, `payload`, `from` fields. - [x] Zod schema for `PeerMessage`. - [x] Write `peer-message.test.ts`, `peer-message.md`. --- ## 6. Stream handler (`src/lib/stream-handler/`) - [x] Implement `StreamHandler` registration: `registerProtocol(protocol, handler)`, `unregisterProtocol(protocol)`, dispatch incoming streams. - [x] Write `stream-handler.test.ts`, `stream-handler.md`. --- ## 7. Messaging (`src/lib/libp2p-messaging/`) - [x] Implement `sendMessage(peerId, protocol, payload)` + `requestResponse(peerId, protocol, payload)` over a libp2p stream. - [x] Wire OTel histograms `libp2p.stream_ttfb_ms`. - [x] Write `libp2p-messaging.test.ts` (≤500 lines, split by responsibility), `libp2p-messaging.md`. --- ## 8. Send-to-peer helpers (`src/lib/send-to-peer/`) - [x] Implement convenience helpers: `sendToPeer`, `broadcastToPeers`, `sendToAll`. - [x] Write `send-to-peer.test.ts`, `send-to-peer.md`. --- ## 9. Connection (`src/lib/libp2p-connection/`) - [x] Implement `createLibp2pNode(config: Libp2pConfig): Promise` — calls `createLibp2p()` with transport/muxer/encryption assembled from config. - [x] Apply bootstrap gate: refuse public default bootstrap peers when `strict: true`. - [x] Write `libp2p-connection.test.ts`, `libp2p-connection.md`. --- ## 10. Transport (`src/transport/libp2p-transport/`) - [x] Implement `Libp2pTransport` composing all lib/ modules. - [x] Wire OTel counters `libp2p.connections_opened_total`, `libp2p.streams_opened_total`, `libp2p.bytes_in_total`, `libp2p.bytes_out_total`. - [x] Write `libp2p-transport.test.ts` (unit: wires components together), `libp2p-transport.md`, `libp2p-transport.types.ts`. --- ## 11. Integration test (`tests/integration.test.ts`) - [x] Two in-process libp2p nodes using the echo protocol; assert message round-trip. - [x] Strict-mode gate: config with empty bootstrapPeers + strict: true throws `LIBP2P_BOOTSTRAP_REJECTED`. - [x] Relay-addr validation: invalid multiaddr format throws `LIBP2P_RELAY_INVALID`. --- ## 12. Playwright E2E (`e2e/libp2p.spec.ts`) - [x] Two Chromium browser contexts; each runs a Vite-bundled test page with a real `Libp2pTransport` node. - [x] Nodes discover each other via a shared bootstrap addr. - [x] Echo protocol: send message from A to B, assert received at B. --- ## 13. Docs - [x] Write `.md` per module (≥200 words, examples, API reference). - [x] Write `README.md` with transport-preset table, strict-mode guidance, companion-package link. --- ## 14. Verify and publish - [x] `bunx turbo lint typecheck test --filter=@suaveplan/network-libp2p` — green. - [x] `bunx turbo test:coverage --filter=@suaveplan/network-libp2p` — 100%. - [x] `bun run docs:check --filter=@suaveplan/network-libp2p` — zero errors. - [x] No `react` in runtime deps; no `vi.mock`, `any`, `ts-ignore`, `.skip`. - [x] Playwright E2E two-node echo round trip passes. - [x] `bun scripts/publish.ts --package @suaveplan/network-libp2p`. - [x] Archive to `openspec/archive/2026-04-24-enterprise-browser-network-libp2p/`.