# @suaveplan/network-libp2p-server - Server-tier libp2p relay daemon (bootstrap + circuit-relay-v2) paired with @suaveplan/network-transport-libp2p — Node-only HTTP/libp2p host with structural Zod option validation, AbortSignal lifecycle, health/ready/live endpoints, OTel observability, and injectable libp2p factory for real-fake integration tests. ## Summary Server-tier libp2p relay daemon paired with [`@suaveplan/network-transport-libp2p`](../network-transport-libp2p). Hosts a libp2p node configured as a bootstrap + circuit-relay-v2 server alongside an inline HTTP listener exposing `/health`, `/ready`, `/live` verbs. ## Documentation tree - [errors](./src/errors/errors.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_ - [health](./src/health/health.md) — _(no submodules)_ - [health](./src/health/health.md) — _(no submodules)_ - [otel](./src/otel/otel.md) — _(no submodules)_ - [otel](./src/otel/otel.md) — _(no submodules)_ - [server](./src/server/server.md) — _(no submodules)_ - [health-listener](./src/server/health-listener.md) — Wraps the asynchronous `http.Server.listen(port, host)` flow with the listener-attach / `EADDRINUSE` classification / `… - [peer-events](./src/server/peer-events.md) — Wires the `peer:connect` and `peer:disconnect` event listeners onto a `Libp2pServerNodeLike` and bridges them onto the… - [server](./src/server/server.md) — _(no submodules)_ - [types](./src/types/types.md) — _(no submodules)_ - [types](./src/types/types.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_- [health-listener](./src/server/health-listener.md) — Wraps the asynchronous `http.Server.listen(port, host)` flow with the listener-attach / `EADDRINUSE` classification / `… - [peer-events](./src/server/peer-events.md) — Wires the `peer:connect` and `peer:disconnect` event listeners onto a `Libp2pServerNodeLike` and bridges them onto the… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_- [health-listener](./src/server/health-listener.md) — Wraps the asynchronous `http.Server.listen(port, host)` flow with the listener-attach / `EADDRINUSE` classification / `… - [peer-events](./src/server/peer-events.md) — Wires the `peer:connect` and `peer:disconnect` event listeners onto a `Libp2pServerNodeLike` and bridges them onto the… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_- [health-listener](./src/server/health-listener.md) — Wraps the asynchronous `http.Server.listen(port, host)` flow with the listener-attach / `EADDRINUSE` classification / `… - [peer-events](./src/server/peer-events.md) — Wires the `peer:connect` and `peer:disconnect` event listeners onto a `Libp2pServerNodeLike` and bridges them onto the… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_ - [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_ - [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_ - [health-listener](./src/server/health-listener.md) — Wraps the asynchronous `http.Server.listen(port, host)` flow with the listener-attach / `EADDRINUSE` classification / `… - [peer-events](./src/server/peer-events.md) — Wires the `peer:connect` and `peer:disconnect` event listeners onto a `Libp2pServerNodeLike` and bridges them onto the… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_ - [types](./src/types/types.md) — _(no submodules)_ ## Run the daemon ```ts import { createLibp2p } from "libp2p"; import { tcp } from "@libp2p/tcp"; import { webSockets } from "@libp2p/websockets"; import { noise } from "@chainsafe/libp2p-noise"; import { yamux } from "@chainsafe/libp2p-yamux"; import { identify } from "@libp2p/identify"; import { circuitRelayServer } from "@libp2p/circuit-relay-v2"; import { bootstrap } from "@libp2p/bootstrap"; import { Libp2pServer } from "@suaveplan/network-libp2p-server"; const server = new Libp2pServer({ listen: ["/ip4/0.0.0.0/tcp/9090", "/ip4/0.0.0.0/tcp/9091/ws"], bootstrap: ["/dnsaddr/bootstrap.libp2p.io/p2p/QmNnoo..."], autoRelay: { enabled: true, maxConnections: 500 }, healthPort: 9099, libp2pFactory: async (cfg) => createLibp2p({ addresses: { listen: [...cfg.listen] }, transports: [tcp(), webSockets()], connectionEncrypters: [noise()], streamMuxers: [yamux()], peerDiscovery: cfg.bootstrap.length > 0 ? [bootstrap({ list: [...cfg.bootstrap] })] : [], services: { identify: identify(), relay: circuitRelayServer({ reservations: { maxReservations: cfg.autoRelay.maxConnections, }, }), }, connectionManager: { maxConnections: cfg.maxConnections }, }), }); const { peerId, multiaddrs } = await server.start(); console.log(`libp2p relay ${peerId} on:`); for (const a of multiaddrs) console.log(` ${a}`); // Graceful shutdown process.on("SIGTERM", () => server.stop()); ``` ## Test environment Tests inject a deterministic `FakeLibp2pServerNode` so the native transitive deps of the real `libp2p` package never enter the test surface — the daemon never resolves `libp2p` at module evaluation time and the integration suite boots a real `Libp2pServer` inside the test process. ```ts import { Libp2pServer } from "@suaveplan/network-libp2p-server"; import { FakeLibp2pHub, makeFakeServerFactory, } from "./tests/setup/fake-libp2p-server.js"; const hub = new FakeLibp2pHub(); const { factory } = makeFakeServerFactory(hub); const server = new Libp2pServer({ libp2pFactory: factory, listen: ["/ip4/0.0.0.0/tcp/0"], healthPort: 0, }); await server.start(); // ... drive the daemon, then: await server.stop(); ``` ## Acceptance gates - `bunx turbo lint typecheck test --filter=@suaveplan/network-libp2p-server` - `bunx turbo test:coverage --filter=@suaveplan/network-libp2p-server` → 100/100/100/100 - `bun run docs:check --filter=@suaveplan/network-libp2p-server` ## API See per-module `.md` docs: - [`src/server/server.md`](src/server/server.md) — `Libp2pServer` daemon - [`src/server/peer-events.md`](src/server/peer-events.md) — peer connect/disconnect bridging - [`src/server/health-listener.md`](src/server/health-listener.md) — inline-HTTP `listenHttp` helper - [`src/health/health.md`](src/health/health.md) — `/health` / `/ready` / `/live` verb pipeline - [`src/otel/otel.md`](src/otel/otel.md) — OTel instrumentation surface - [`src/errors/errors.md`](src/errors/errors.md) — error registry - [`src/types/types.md`](src/types/types.md) — public type contracts