@triton-one/yellowstone-fumarole-client
v0.0.1
Published
Yellowstone Fumarole client — native Node.js bindings via Rust/NAPI
Readme
@triton-one/yellowstone-fumarole-client
TypeScript client for the Yellowstone Fumarole service — a high-throughput Solana data streaming platform built on top of Geyser.
Installation
npm install @triton-one/yellowstone-fumarole-clientRequires Node.js >= 22. The native binary is installed automatically via an optional dependency for your platform.
Quick start
import {
FumaroleClient,
CommitmentLevel,
SubscribeRequest,
} from '@triton-one/yellowstone-fumarole-client'
const client = await FumaroleClient.connect({
endpoint: 'https://fumarole.triton.one',
xToken: process.env.FUMAROLE_X_TOKEN,
})
const request: SubscribeRequest = {
commitment: CommitmentLevel.CONFIRMED,
accounts: {},
transactions: {
all: { accountInclude: [], accountExclude: [], accountRequired: [] },
},
slots: { all: { filterByCommitment: true } },
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
}
const subscription = await client.subscribe('my-subscriber', request)
for await (const event of subscription) {
if (event.type === 'slotEnded') {
console.log('slot completed:', event.slot)
continue
}
// event.type === 'data'
console.log('slot:', event.slot, 'update:', event.update)
}Connecting
const client = await FumaroleClient.connect({
endpoint: 'https://fumarole.triton.one', // required
xToken: 'your-token', // optional auth token
maxDecodingMessageSizeBytes: 512 * 1024 * 1024, // optional, default 512 MB
})Subscribing
Basic subscribe
const subscription = await client.subscribe('my-subscriber', request)The subscriberName is a persistent identifier — Fumarole tracks your offset under this name so you can resume from where you left off after a restart.
Subscribe with tuning options
const subscription = await client.subscribeWithConfig('my-subscriber', request, {
numDataPlaneTcpConnections: 1, // parallel TCP connections (default: 1)
concurrentDownloadLimitPerTcp: 2, // concurrent downloads per connection (default: 2)
commitIntervalMs: 10_000, // offset commit interval in ms (default: 10 000)
maxFailedSlotDownloadAttempt: 3, // failures before session fails (default: 3)
gcInterval: 100, // GC tick interval (default: 100)
slotMemoryRetention: 1_000, // dedup window size in slots (default: 1 000)
noCommit: false, // disable offset commits
autoCommit: true, // commit after every event
})Consuming events
for await (const event of subscription) {
if (event.type === 'slotEnded') {
// All updates for this slot have been delivered
console.log('slot done:', event.slot)
continue
}
// event.type === 'data'
const { slot, update } = event
if (update.account) console.log('account update', update.account)
if (update.transaction) console.log('transaction', update.transaction)
if (update.slot) console.log('slot update', update.slot)
if (update.block) console.log('block', update.block)
if (update.blockMeta) console.log('block meta', update.blockMeta)
if (update.entry) console.log('entry', update.entry)
}Updating filters on a live subscription
await subscription.updateFilters({
...request,
transactions: {
specific: {
accountInclude: ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'],
accountExclude: [],
accountRequired: [],
},
},
})Consumer group management
Fumarole tracks your read position server-side under a named consumer group. The subscriberName you pass to subscribe is the consumer group name.
// List all consumer groups on the account
const { consumerGroups } = await client.listConsumerGroups()
// Get info for a specific group (returns null if not found)
const info = await client.getConsumerGroupInfo('my-subscriber')
// Create a group starting from the latest offset
await client.createConsumerGroup('my-subscriber')
// Create a group starting from a specific slot
await client.createConsumerGroup('my-subscriber', 350_000_000n)
// Delete a specific group (resets the offset)
await client.deleteConsumerGroup('my-subscriber')
// Delete all groups on the account
await client.deleteAllConsumerGroups()Miscellaneous
// Service version
const { version } = await client.version()
// Available slot range on the service
const range = await client.getSlotRange()Subscription filters reference
All fields of SubscribeRequest are optional except commitment. Set a field to an empty object {} to include it with no filter, or omit it entirely to exclude that update type.
| Field | Type | Description |
|---|---|---|
| commitment | CommitmentLevel | PROCESSED, CONFIRMED, or FINALIZED |
| accounts | Record<string, SubscribeRequestFilterAccounts> | Account updates |
| transactions | Record<string, SubscribeRequestFilterTransactions> | Transaction updates |
| transactionsStatus | Record<string, SubscribeRequestFilterTransactions> | Transaction status only |
| slots | Record<string, SubscribeRequestFilterSlots> | Slot updates |
| blocks | Record<string, SubscribeRequestFilterBlocks> | Full block updates |
| blocksMeta | Record<string, SubscribeRequestFilterBlocksMeta> | Block metadata only |
| entry | Record<string, SubscribeRequestFilterEntry> | Entry updates |
| accountsDataSlice | SubscribeRequestAccountsDataSlice[] | Slice account data |
Examples
See the examples/ directory:
subscribe-firehose.ts— subscribe to all accounts and transactionssubscribe-token-transactions.ts— filter transactions by programlist-consumer-groups-with-group-info.ts— list and inspect consumer groups
To run an example:
cd examples
cp .env.example .env # fill in FUMAROLE_ENDPOINT and FUMAROLE_X_TOKEN
npm install
npm run subscribe-firehose