Files
2026-05-27 23:47:53 +01:00
..
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00

@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. 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 — (no submodules)
  • health — (no submodules)
  • otel — (no submodules)
    • otel — (no submodules)
  • server — (no submodules)
    • health-listener — Wraps the asynchronous http.Server.listen(port, host) flow with the listener-attach / EADDRINUSE classification / `…
    • peer-events — Wires the peer:connect and peer:disconnect event listeners onto a Libp2pServerNodeLike and bridges them onto the…
    • server — (no submodules)
  • types — (no submodules)
    • types — (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 — Wires the peer:connect and peer:disconnect event listeners onto a Libp2pServerNodeLike and bridges them onto the…
  • server — (no submodules)- types — (no submodules)- types — (no submodules)- errors — (no submodules)- health — (no submodules)- health — (no submodules)- otel — (no submodules)- otel — (no submodules)- server — (no submodules)- health-listener — Wraps the asynchronous http.Server.listen(port, host) flow with the listener-attach / EADDRINUSE classification / `…
  • peer-events — Wires the peer:connect and peer:disconnect event listeners onto a Libp2pServerNodeLike and bridges them onto the…
  • server — (no submodules)- types — (no submodules)- types — (no submodules)- errors — (no submodules)- health — (no submodules)- health — (no submodules)- otel — (no submodules)- otel — (no submodules)- server — (no submodules)- health-listener — Wraps the asynchronous http.Server.listen(port, host) flow with the listener-attach / EADDRINUSE classification / `…
  • peer-events — Wires the peer:connect and peer:disconnect event listeners onto a Libp2pServerNodeLike and bridges them onto the…
  • server — (no submodules)- types — (no submodules)- types — (no submodules)- errors — (no submodules)- health — (no submodules) - health — (no submodules)- otel — (no submodules) - otel — (no submodules)- server — (no submodules) - health-listener — Wraps the asynchronous http.Server.listen(port, host) flow with the listener-attach / EADDRINUSE classification / `…
  • peer-events — Wires the peer:connect and peer:disconnect event listeners onto a Libp2pServerNodeLike and bridges them onto the…
  • server — (no submodules)- types — (no submodules) - types — (no submodules)

Run the daemon

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.

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: