libp2p service integration
This package can be used in two ways:
startRelay()for the full relay runtime — see Using as a library.orbitdbReplicationService()for mounting the OrbitDB replication + Helia pinning logic inside an existing libp2p node (covered here).
It also exports:
connectivityDebugProtocolsService()for opt-in/connectivity-echo/1.0.0and/connectivity-bulk/1.0.0.createPinningHttpRequestHandler()for embedding/health,/multiaddrs,/pinning/*, and/ipfs/*.PinningHttpServeras a small HTTP(S) wrapper around that request handler.
In the default startRelay() runtime those debug protocols stay disabled unless you either:
- pass
debugProtocolsprogrammatically, or - set
RELAY_CONNECTIVITY_ECHO_ENABLED=1and/orRELAY_CONNECTIVITY_BULK_ENABLED=1.
Install
Published package:
npm install orbitdb-relay
To pin an unreleased branch, install from Git:
npm install github:NiKrause/orbitdb-relay#<branch>
Local checkout:
npm install ../path/to/orbitdb-relay
What your project still provides
orbitdbReplicationService() plugs into your libp2p node, but your project still owns:
- the libp2p transports / muxers / encryption / discovery stack,
- the shared
datastore, - the shared
blockstore, - starting and stopping the libp2p node.
The service itself owns:
- its Helia instance,
- its OrbitDB instance,
- OrbitDB pubsub sync listeners for
/orbitdb/*, - media-CID extraction and Helia pinning.
Minimal example
import { join } from 'node:path'
import { createLibp2p } from 'libp2p'
import { LevelDatastore } from 'datastore-level'
import { LevelBlockstore } from 'blockstore-level'
import { gossipsub } from '@chainsafe/libp2p-gossipsub'
import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { identify } from '@libp2p/identify'
import { ping } from '@libp2p/ping'
import { circuitRelayTransport, circuitRelayServer } from '@libp2p/circuit-relay-v2'
import { kadDHT, removePrivateAddressesMapper } from '@libp2p/kad-dht'
import { pubsubPeerDiscovery } from '@libp2p/pubsub-peer-discovery'
import { tcp } from '@libp2p/tcp'
import { webSockets } from '@libp2p/websockets'
import { orbitdbReplicationService } from 'orbitdb-relay'
const storageDir = './orbitdb-replication-node'
const datastore = new LevelDatastore(join(storageDir, 'ipfs', 'data'))
const blockstore = new LevelBlockstore(join(storageDir, 'ipfs', 'blocks'))
await datastore.open()
await blockstore.open()
const libp2p = await createLibp2p({
datastore,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/0', '/ip4/127.0.0.1/tcp/0/ws']
},
transports: [circuitRelayTransport(), tcp(), webSockets()],
connectionEncrypters: [noise()],
streamMuxers: [yamux()],
peerDiscovery: [
pubsubPeerDiscovery({
interval: 5000,
topics: ['myapp._peer-discovery._p2p._pubsub'],
listenOnly: false,
emitSelf: true
})
],
services: {
identify: identify(),
ping: ping(),
pubsub: gossipsub({ allowPublishToZeroTopicPeers: true }),
aminoDHT: kadDHT({
protocol: '/ipfs/kad/1.0.0',
peerInfoMapper: removePrivateAddressesMapper
}),
relay: circuitRelayServer(),
orbitdbReplication: orbitdbReplicationService({
datastore,
blockstore,
orbitdbDirectory: join(storageDir, 'orbitdb')
})
}
})
await libp2p.services.orbitdbReplication.syncAllOrbitDBRecords('/orbitdb/zdpu...')
const pinning = libp2p.services.orbitdbReplication.createPinningHttpHandlers()
console.log(pinning.getStats())
await libp2p.stop()
await datastore.close()
await blockstore.close()
API
Mounted service:
libp2p.services.orbitdbReplication
Methods:
syncAllOrbitDBRecords(dbAddress: string)createPinningHttpHandlers()
Additional reusable exports:
connectivityDebugProtocolsService(init)createPinningHttpRequestHandler(options)PinningHttpServer
Init options:
datastore— shared datastore used by the host node.blockstore— shared blockstore used by the host node.orbitdbDirectory?— optional directory for OrbitDB metadata.
Requirements
- The service declares a libp2p dependency on
@libp2p/pubsub, so your node must provide apubsubservice. - In practice you will usually also want
identify, plus whatever transports and discovery mechanisms your app uses. - Your node should share the same
datastore/blockstoreobjects with the replication service.
Lifecycle notes
libp2p.start()starts the replication service automatically.libp2p.stop()stops the replication service, its Helia instance, and its OrbitDB instance.- The service does not close your datastore or blockstore; close those after
libp2p.stop().
Troubleshooting
- If
orbitdbReplicationServiceis missing from the import, you are probably on an older published version that predates this export. - If you are testing a branch before release, install from Git or a local checkout instead of the registry.
- If your node does not provide
pubsub, libp2p will reject the service at startup because of the declared dependency.
Serving the pinning HTTP routes yourself
If you want the /health, /multiaddrs, /pinning/*, and /ipfs/* routes without the full
metrics server, mount the shared handler with createPinningHttpRequestHandler() (or wrap it in
PinningHttpServer). The full contract is documented in the HTTP API reference.