@relay-federation/sdk
v0.2.0
Published
JavaScript SDK for the Federated SPV Relay Mesh — connect to any bridge from your app
Maintainers
Readme
@relay-federation/sdk
JavaScript SDK for the Federated SPV Relay Mesh. Connect to any bridge from your app.
Install
npm install @relay-federation/sdkQuick Start
import { RelayBridge } from '@relay-federation/sdk'
const bridge = new RelayBridge('http://your-bridge:9333')
// Get bridge status
const status = await bridge.getStatus()
console.log(`Height: ${status.headers.bestHeight}, Peers: ${status.peers.connected}`)
// Fetch a transaction
const tx = await bridge.getTx('abc123...')
console.log(`Source: ${tx.source}, Outputs: ${tx.outputs.length}`)
// Broadcast a raw transaction
const result = await bridge.broadcast('0100000001...')
console.log(`Relayed to ${result.peers} peers`)
// Query inscriptions
const images = await bridge.getInscriptions({ mime: 'image/png', limit: 10 })
console.log(`Found ${images.count} of ${images.total} total`)
// Get address history
const history = await bridge.getAddressHistory('1Abc...')
// Discover other bridges on the mesh
const mesh = await bridge.discover()
console.log(`${mesh.count} bridges on the network`)API
Constructor
const bridge = new RelayBridge(baseUrl, options?)| Option | Type | Default | Description |
|---|---|---|---|
| auth | string | — | Operator statusSecret for authenticated endpoints |
| timeout | number | 10000 | Request timeout in milliseconds |
Public Methods
| Method | Returns | Description |
|---|---|---|
| getStatus() | status object | Bridge status (peers, headers, mempool, BSV node) |
| getMempool() | { count, txs } | Parsed mempool transactions |
| getTx(txid) | tx object | Fetch and parse a transaction |
| broadcast(rawHex) | { txid, peers } | Relay a raw transaction to mesh peers |
| getInscriptions(filters?) | { total, count, inscriptions } | Query indexed inscriptions |
| getInscriptionContent(txid, vout) | { data, contentType } | Raw inscription content |
| getAddressHistory(address) | { address, history } | Transaction history for an address |
| discover() | { count, bridges } | All bridges known to this node |
| getApps() | { apps } | Health/SSL/usage for configured apps |
| getSessions(address) | { address, sessions, count } | Session metadata for an address |
| indexSession(session) | { ok } | Index a session (syncs to peers via SessionRelay) |
| backfillSessions(sessions) | { ok, indexed } | Bulk-index sessions |
| getRawTx(txid) | hex string | Raw transaction hex |
| getUnspent(address) | array of UTXOs | Unspent outputs for an address |
Operator Methods (require auth)
| Method | Returns | Description |
|---|---|---|
| register() | { jobId, stream } | Start on-chain registration |
| deregister(reason?) | { jobId, stream } | Start on-chain deregistration |
| fund(rawHex) | { stored, balance } | Store a funding transaction |
| connect(endpoint) | { endpoint, status } | Connect to a peer |
| send(toAddress, amount) | { jobId, stream } | Send BSV from bridge wallet |
| scanAddress(address, onProgress?) | { scanned, found, indexed } | Scan address for inscriptions |
| rebuildInscriptionIndex() | { rebuilt } | Rebuild inscription indexes |
| getJob(jobId) | events array | Get async job progress |
Inscription Filters
await bridge.getInscriptions({
mime: 'image/png', // filter by content type
address: '1Abc...', // filter by receiving address
limit: 100 // max results (capped at 200)
})Error Handling
import { RelayBridge, BridgeError } from '@relay-federation/sdk'
try {
const tx = await bridge.getTx('bad-txid')
} catch (err) {
if (err instanceof BridgeError) {
console.log(err.status) // HTTP status code (e.g. 404)
console.log(err.message) // Error message from bridge
}
}Multi-Bridge Discovery
// Connect to one bridge, discover the rest
const entry = new RelayBridge('http://your-bridge:9333')
const mesh = await entry.discover()
// Connect to all bridges
const bridges = mesh.bridges.map(b => new RelayBridge(b.statusUrl))
// Query across the mesh
for (const bridge of bridges) {
const status = await bridge.getStatus()
console.log(`${status.bridge.pubkeyHex?.slice(0, 8)}... height=${status.headers.bestHeight}`)
}Round-Robin Failover
For production apps, round-robin across multiple bridges so one failure doesn't take you down:
const bridges = [
new RelayBridge('http://bridge-alpha:9333', { timeout: 8000 }),
new RelayBridge('http://bridge-beta:9333', { timeout: 8000 }),
new RelayBridge('http://bridge-gamma:9333', { timeout: 8000 }),
]
let idx = 0
async function meshCall(fn) {
const startIdx = idx++ % bridges.length
for (let i = 0; i < bridges.length; i++) {
try {
return await fn(bridges[(startIdx + i) % bridges.length])
} catch (_) { /* try next */ }
}
throw new Error('All bridges failed')
}
// Usage
const tx = await meshCall(b => b.getTx('abc123...'))
const result = await meshCall(b => b.broadcast('0100...'))Building Apps
Apps are consumers of the federation — they run anywhere and talk to bridges via this SDK or plain REST. See the full guide: Building Apps on the Federation
Requirements
- Node.js >= 18 (uses native
fetch) - Works in browsers with
fetchsupport
License
MIT
