@suaveplan/network-discovery-gundb - Browser-tier GunDB DiscoveryStrategy: gossip-over-WebSocket peer discovery via Gun. Relay list REQUIRED — no public-relay fallback. Mandatory Ed25519-signed peer announces. Zod wire-payload validation. Constant-time peer-ID compare. AbortSignal + EventBusLike + ServiceRegistry + OTel + Zod boundaries.
Summary
Browser-tier DiscoveryStrategy for @suaveplan/network-bootstrap
chains. Wraps a GunDB instance — gossip-over-
WebSocket decentralised graph database — and exposes a deduped, capped
peer set to the bootstrap pipeline.
GunDB is flagged security-fragile upstream; this release tightens every relevant attack surface.
Documentation tree
- gundb-discovery — (no submodules)
- gundb-discovery — (no submodules)
- errors — (no submodules)
- errors — (no submodules)
- otel — (no submodules)
- otel — (no submodules)
- plugin — (no submodules)
- plugin — (no submodules)
- signing — (no submodules)
- signing — (no submodules)
- transport — (no submodules)
- envelope-signing — Provides the cryptographic helpers used by
GunDBTransportto sign every outgoingMessageEnvelopeand verify every i… - transport — (no submodules)
- envelope-signing — Provides the cryptographic helpers used by
- types — (no submodules)
- types — (no submodules)
- transport — (no submodules)- types — (no submodules)- types — (no submodules)- gundb-discovery — (no submodules)- errors — (no submodules)- errors — (no submodules)- otel — (no submodules)- otel — (no submodules)- plugin — (no submodules)- plugin — (no submodules)- signing — (no submodules)- signing — (no submodules)- transport — (no submodules)- envelope-signing — Provides the cryptographic helpers used by
GunDBTransportto sign every outgoingMessageEnvelopeand verify every i… - transport — (no submodules)- types — (no submodules)- types — (no submodules)- gundb-discovery — (no submodules)- errors — (no submodules)- errors — (no submodules)- otel — (no submodules)- otel — (no submodules)- plugin — (no submodules)- plugin — (no submodules)- signing — (no submodules)- signing — (no submodules)- transport — (no submodules)- envelope-signing — Provides the cryptographic helpers used by
GunDBTransportto sign every outgoingMessageEnvelopeand verify every i… - transport — (no submodules)- types — (no submodules)- types — (no submodules)- gundb-discovery — (no submodules)- errors — (no submodules) - errors — (no submodules)- otel — (no submodules) - otel — (no submodules)- plugin — (no submodules) - plugin — (no submodules)- signing — (no submodules) - signing — (no submodules)- transport — (no submodules) - envelope-signing — Provides the cryptographic helpers used by
GunDBTransportto sign every outgoingMessageEnvelopeand verify every i… - transport — (no submodules)- types — (no submodules) - types — (no submodules)
Why this package
- Plug-and-play
DiscoveryStrategyslot for network bootstrap chains. Works alongside@suaveplan/network-discovery-peerjs,@suaveplan/network-discovery-trystero,@suaveplan/network-discovery-webtorrent, and@suaveplan/network-discovery-crdt. - Relay list REQUIRED. Upstream's public-relay fallback
(
https://gun-manhattan.herokuapp.com/gun) is removed. Callers must supply their own relays. - Every outbound announce is Ed25519-signed. The local peer's 32-byte secret is the contract input.
- Every inbound announce is Zod-parsed AND Ed25519-verified before
admission. Failures silently drop the payload and increment
gundb.invalid_messages_total{reason}/gundb.signature_rejected_total{reason}— a malicious peer cannot crash a node by gossiping garbage. - Constant-time peer-ID compare via
constantTimeEqualfrom@suaveplan/crypto-utils. - Injectable
gunFactory— production wires the realGun(config); tests bind a deterministicGunNodeLikefake (novi.mockever used). - Typed
EventBusLike<GunDBEventMap>integration. - Optional
@suaveplan/service-discoveryServiceRegistrymirroring. - OTel surface:
disc_gundb.startspan; counterspeers_discovered_total{outcome},gundb.invalid_messages_total{reason},gundb.signature_rejected_total{reason},disc_gundb.relay_errors_total{relay}; histogramgundb_announce_duration_ms. AbortSignalhonoured on every async public method.- 100% test + branch + function + line coverage.
Basic example
import { GunDBDiscovery, publicKeyHex } from "@suaveplan/network-discovery-gundb";
const signingKey = crypto.getRandomValues(new Uint8Array(32));
const localPeerId = publicKeyHex(signingKey);
const discovery = new GunDBDiscovery({
peers: ["wss://my-private-relay.example.com/gun"],
gunFactory: async (cfg) => {
const { default: Gun } = await import("gun");
return Gun({ peers: cfg.peers as string[] }) as unknown as GunNodeLike;
},
localPeerId,
signingKey,
});
await discovery.start();
const peers = await discovery.discover(5_000);
console.log(`found ${peers.length} peers`);
await discovery.stop();
Advanced example
import { EventBus } from "@suaveplan/events";
import { ServiceRegistry } from "@suaveplan/service-discovery";
import { DiscoveryChain } from "@suaveplan/network-bootstrap";
import {
GunDBDiscovery,
publicKeyHex,
type GunDBEventMap,
} from "@suaveplan/network-discovery-gundb";
const bus = new EventBus<GunDBEventMap>();
const registry = new ServiceRegistry();
const signingKey = crypto.getRandomValues(new Uint8Array(32));
bus.on("gundb:peer-discovered", ({ peer }) => {
console.log("peer:", peer.id, peer.addresses);
});
bus.on("gundb:relay-error", ({ reason }) => {
console.warn("relay:", reason);
});
const discovery = new GunDBDiscovery({
peers: [
"wss://relay-a.example.com/gun",
"wss://relay-b.example.com/gun",
],
room: "my-app/v1",
maxPeers: 256,
announceIntervalMs: 15_000,
gunFactory: async (cfg) => {
const { default: Gun } = await import("gun");
return Gun({
peers: cfg.peers as string[],
localStorage: cfg.localStorage,
}) as unknown as GunNodeLike;
},
localPeerId: publicKeyHex(signingKey),
signingKey,
bus,
registry,
});
const chain = new DiscoveryChain([discovery]);
const peers = await chain.discover(5_000);
API
See sibling co-located markdown:
src/types/types.mdsrc/errors/errors.mdsrc/otel/otel.mdsrc/signing/signing.mdsrc/core/gundb-discovery/gundb-discovery.md
License
MIT