helius-laserstream
v0.6.1
Published
High-performance Laserstream gRPC client with automatic reconnection
Downloads
71,963
Maintainers
Readme
Laserstream TypeScript Client
High-performance TypeScript client for streaming real-time Solana data via Laserstream with automatic reconnection and slot tracking.
Installation
npm install helius-laserstreamQuick Start
import { subscribe, CommitmentLevel, LaserstreamConfig } from 'helius-laserstream';
async function main() {
const config: LaserstreamConfig = {
apiKey: 'your-api-key',
endpoint: 'https://laserstream-mainnet-tyo.helius-rpc.com',
};
const request = {
slots: {
client: {}
},
commitment: CommitmentLevel.CONFIRMED,
};
const stream = await subscribe(
config,
request,
async (update) => {
console.log('Received:', update);
},
async (error) => {
console.error('Error:', error);
}
);
}
main().catch(console.error);Configuration Examples
Basic Configuration
const config: LaserstreamConfig = {
apiKey: 'your-api-key',
endpoint: 'https://laserstream-mainnet-tyo.helius-rpc.com',
};Advanced Configuration with Channel Options
import { LaserstreamConfig, ChannelOptions, CompressionAlgorithms } from 'helius-laserstream';
const channelOptions: ChannelOptions = {
// Connection settings
connectTimeoutSecs: 20,
maxDecodingMessageSize: 2_000_000_000, // 2GB
maxEncodingMessageSize: 64_000_000, // 64MB
// Keepalive settings
http2KeepAliveIntervalSecs: 15,
keepAliveTimeoutSecs: 10,
keepAliveWhileIdle: true,
// Flow control
initialStreamWindowSize: 8_388_608, // 8MB
initialConnectionWindowSize: 16_777_216, // 16MB
// Performance
http2AdaptiveWindow: true,
tcpNodelay: true,
bufferSize: 131_072, // 128KB
};
const config: LaserstreamConfig = {
apiKey: 'your-api-key',
endpoint: 'your-endpoint',
maxReconnectAttempts: 10,
channelOptions: channelOptions,
};Replay Control
// Disable replay - start from current slot on reconnect
const config: LaserstreamConfig = {
apiKey: 'your-api-key',
endpoint: 'your-endpoint',
replay: false, // Potential data gaps
};
// Enable replay (default) - resume from last processed slot
config.replay = true; // No data lossSubscription Examples
Account Subscriptions
const request = {
accounts: {
"usdc-accounts": {
account: ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"],
owner: [],
filters: []
},
"token-program-accounts": {
account: [],
owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
filters: []
}
},
commitment: CommitmentLevel.CONFIRMED,
};Transaction Subscriptions
const request = {
transactions: {
"token-txs": {
accountInclude: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
accountExclude: [],
accountRequired: [],
vote: false,
failed: false
},
"pump-txs": {
accountInclude: ["pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"],
accountExclude: [],
accountRequired: [],
vote: false,
failed: false
}
},
commitment: CommitmentLevel.CONFIRMED,
};tokenAccounts (ATA) Expansion
Set tokenAccounts on a transaction filter to also match transactions that
touch an Associated Token Account (ATA) owned by one of the accountInclude
wallets, not just transactions naming the wallet directly. Modes (server wire
values):
"none"— no expansion (default; same as omitting the field)."balanceChanged"— also match txs touching an ATA owned by anaccountIncludewallet whose token balance changed."all"— match any tx touching an ATA owned by anaccountIncludewallet.
const request = {
transactions: {
"wallet-and-atas": {
accountInclude: ["vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg"],
accountExclude: [],
accountRequired: [],
vote: false,
failed: false,
tokenAccounts: "balanceChanged",
},
},
commitment: CommitmentLevel.CONFIRMED,
};See examples/token-accounts-sub.ts.
Block Subscriptions
const request = {
blocks: {
"all-blocks": {
includeTransactions: true,
includeAccounts: true
}
},
blocksMeta: {
"block-metadata": {}
},
commitment: CommitmentLevel.CONFIRMED,
};Slot Subscriptions
const request = {
slots: {
"confirmed-slots": {
filterByCommitment: true
},
"all-slots": {
filterByCommitment: false
}
},
commitment: CommitmentLevel.CONFIRMED,
};Multiple Subscriptions
const request = {
accounts: {
"usdc-accounts": {
account: ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"],
owner: [],
filters: []
}
},
transactions: {
"token-txs": {
accountInclude: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
accountExclude: [],
accountRequired: [],
vote: false,
failed: false
}
},
slots: {
"slots": {}
},
commitment: CommitmentLevel.CONFIRMED,
};Stream Write - Dynamic Updates
// Initial subscription
const stream = await subscribe(config, initialRequest, onData, onError);
// Later, update subscription dynamically
stream.write({
accounts: {
"new-program": {
owner: ["new-program-id"],
account: [],
filters: []
}
}
});Compressed Account Filters (Cuckoo)
When you track a large set of accounts (tens of thousands to millions), sending an
explicit pubkey list in every SubscribeRequest is expensive (~32 bytes/account).
A cuckoo filter replaces that list with a compact probabilistic set
(~3 bytes/account). The server matches accounts against the filter with no false
negatives and <1% false positives — you re-check each incoming account locally
against your exact set with contains(), making the stream exact for your code.
import { subscribe, CommitmentLevel, CompressedAccountFilterSet } from 'helius-laserstream';
// Size the filter for your peak tracked-set size.
const tracked = new CompressedAccountFilterSet(2_000_000);
for (const pubkey of myTrackedPubkeys) {
tracked.insert(pubkey); // base58 string, Uint8Array/Buffer, or web3.js PublicKey
}
// Attach the filter to the request (no explicit account list needed).
const request = { accounts: {}, commitment: CommitmentLevel.CONFIRMED };
tracked.insertIntoSubscribeRequest(request, 'tracked_accounts');
const stream = await subscribe(config, request, (update) => {
const acct = update.account?.account;
// Re-check locally to drop the server's rare false positives.
if (acct && tracked.contains(acct.pubkey)) {
handleTrackedAccount(acct);
}
});Update the tracked set on the fly and re-send on the same stream:
tracked.insert(newPubkey); // or tracked.remove(oldPubkey)
if (tracked.takeDirty()) { // only re-send when the set actually changed
tracked.insertIntoSubscribeRequest(request, 'tracked_accounts');
await stream.write(request);
}Notes:
- Account subscriptions only. Filters up to 32 MiB (~10M accounts).
insert()throwsTableFullErrorif the filter saturates — rebuild with a larger capacity.contains()is exact (backed by an internalSet); the cuckoo table is used only on the wire.
Compression Examples
Zstd Compression
import { CompressionAlgorithms } from 'helius-laserstream';
const config: LaserstreamConfig = {
apiKey: 'your-api-key',
endpoint: 'your-endpoint',
channelOptions: {
'grpc.default_compression_algorithm': CompressionAlgorithms.zstd,
'grpc.max_receive_message_length': 1_000_000_000,
}
};Gzip Compression
const config: LaserstreamConfig = {
apiKey: 'your-api-key',
endpoint: 'your-endpoint',
channelOptions: {
'grpc.default_compression_algorithm': CompressionAlgorithms.gzip,
'grpc.max_receive_message_length': 1_000_000_000,
}
};Error Handling
const stream = await subscribe(
config,
request,
async (update) => {
// Handle different update types
if (update.account) {
console.log('Account update:', update.account.account?.pubkey);
}
if (update.transaction) {
console.log('Transaction:', update.transaction.transaction?.signature);
}
if (update.slot) {
console.log('Slot:', update.slot.slot);
}
},
async (error) => {
console.error('Stream error:', error);
// Handle reconnection, network issues, etc.
}
);Commitment Levels
import { CommitmentLevel } from 'helius-laserstream';
const request = {
// Latest data (may be rolled back)
commitment: CommitmentLevel.PROCESSED,
// Confirmed by cluster majority
// commitment: CommitmentLevel.CONFIRMED,
// Finalized, cannot be rolled back
// commitment: CommitmentLevel.FINALIZED,
// ... filters
};Stream Management
import { getActiveStreamCount, shutdownAllStreams } from 'helius-laserstream';
// Get active stream count
const activeStreams = getActiveStreamCount();
console.log(`Active streams: ${activeStreams}`);
// Cancel specific stream
stream.cancel();
// Shutdown all streams gracefully
await shutdownAllStreams();Complete Example
import { subscribe, CommitmentLevel, LaserstreamConfig, CompressionAlgorithms } from 'helius-laserstream';
async function main() {
const config: LaserstreamConfig = {
apiKey: process.env.LASERSTREAM_API_KEY!,
endpoint: process.env.LASERSTREAM_ENDPOINT!,
maxReconnectAttempts: 10,
channelOptions: {
'grpc.default_compression_algorithm': CompressionAlgorithms.zstd,
'grpc.max_receive_message_length': 1_000_000_000,
}
};
const request = {
slots: {
"client": {}
},
transactions: {
"token-txs": {
accountInclude: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
accountExclude: [],
accountRequired: [],
vote: false,
failed: false
}
},
commitment: CommitmentLevel.CONFIRMED,
};
try {
const stream = await subscribe(
config,
request,
async (update) => {
if (update.slot) {
console.log(`Slot ${update.slot.slot}: parent=${update.slot.parent}`);
}
if (update.transaction) {
console.log(`Transaction: ${update.transaction.transaction?.signature}`);
}
},
async (error) => {
console.error('Stream error:', error);
}
);
console.log(`Stream connected: ${stream.id}`);
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log('Shutting down...');
stream.cancel();
process.exit(0);
});
} catch (error) {
console.error('Failed to start stream:', error);
process.exit(1);
}
}
main().catch(console.error);Runtime Support
Node.js
node your-app.js
# or with TypeScript
npx ts-node your-app.tsBun
bun your-app.js
# or with TypeScript
bun your-app.tsBoth runtimes support Node-API (NAPI) bindings natively.
Requirements
- Node.js 16.0.0 or later
- Valid Laserstream API key
Examples Directory
See ./examples/ for complete working examples:
account-sub.ts- Account subscriptionstransaction-sub.ts- Transaction filteringblock-sub.ts- Block data streamingslot-sub.ts- Slot progressionchannel-options-example.ts- Performance tuningstream-write-example.ts- Dynamic updatescompression-example.ts- Gzip compressioncompression-zstd-example.ts- Zstd compression
