TypeScript SDK for OrbitFlare - RPC, gRPC (Yellowstone Geyser), JetStream, and WebSocket clients for Solana.
npm install @orbitflare/sdkThe RPC client works out of the box. Add only the peer dependencies for the transports you actually use:
npm install ws # WebSocket subscriptions
npm install @grpc/grpc-js # gRPC streaming (Yellowstone, JetStream)
npm install yaml # YAML stream config filesimport { RpcClientBuilder } from '@orbitflare/sdk';
const client = new RpcClientBuilder()
.url('http://ny.rpc.orbitflare.com')
.commitment('confirmed')
.build();
const slot = await client.getSlot();
const balance = await client.getBalance('CKs1E69a2e9TmH4mKKLrXFF8kD3ZnwKjoEuXa6sz9WqX');
const { blockhash, lastValidBlockHeight } = await client.getLatestBlockhash();
const inflation = await client.request('getInflationRate', []);
const raw = await client.requestRaw(
'{"jsonrpc":"2.0","id":1,"method":"getHealth","params":[]}',
);| Method | Returns |
|---|---|
getSlot() |
Current slot (number) |
getBalance(address) |
Lamports (number) |
getAccountInfo(address) |
Account data or null |
getMultipleAccounts(addresses) |
Array of accounts (auto-chunks to 100) |
getLatestBlockhash() |
{ blockhash, lastValidBlockHeight } |
getTransaction(signature) |
Full transaction with metadata |
getSignaturesForAddress(address, limit) |
Recent signatures |
getProgramAccounts(programId) |
All accounts owned by a program |
getRecentPrioritizationFees(addresses) |
Recent priority fees |
sendTransaction(txBase64) |
Signature string |
simulateTransaction(txBase64) |
Simulation result |
getTokenAccountsByOwner(owner, mint?, programId?) |
Token accounts |
getTransactionsForAddress(address, options) |
Full transaction history with filters and pagination (OrbitFlare-specific) |
request(method, params) |
Any RPC method by name |
requestRaw(body) |
Raw JSON-RPC body string |
Subscribe using a YAML config file:
# grpc.yml
transactions:
pumpfun:
vote: false
failed: false
account_include:
- "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
commitment: confirmedimport { GeyserClientBuilder } from '@orbitflare/sdk/grpc';
const client = new GeyserClientBuilder()
.url('http://ny.rpc.orbitflare.com:10000')
.build();
const stream = client.subscribeYaml('grpc.yml');
for await (const update of stream) {
if (update.transaction) {
console.log(`slot=${update.transaction.slot}`);
}
}The YAML format supports ${ENV_VAR} expansion. You can also call client.subscribe(request) with a programmatically constructed SubscribeRequest.
Build the request programmatically with the typed builder instead of YAML:
import {
AccountFilter,
Commitment,
GeyserClientBuilder,
Lamports,
Memcmp,
SlotFilter,
SubscribeRequestBuilder,
TransactionFilter,
} from '@orbitflare/sdk/grpc';
const request = new SubscribeRequestBuilder()
.transactions(
'pumpfun',
new TransactionFilter()
.vote(false)
.failed(false)
.accountInclude(['6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'])
.accountRequired(['So11111111111111111111111111111111111111112']),
)
.accounts(
'wsol-token-accounts',
new AccountFilter()
.owner(['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'])
.datasize(165)
.memcmp(Memcmp.base58(0, 'So11111111111111111111111111111111111111112'))
.lamports(Lamports.gt(0)),
)
.slots('slots', new SlotFilter().filterByCommitment(true))
.commitment(Commitment.Confirmed)
.build();
const stream = client.subscribe(request);client.subscribe(request) also accepts a raw SubscribeRequest if you'd rather construct it by hand.
# jetstream.yml
transactions:
raydium:
account_include:
- "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"import { JetstreamClientBuilder } from '@orbitflare/sdk/jetstream';
const client = new JetstreamClientBuilder()
.url('http://ny.jetstream.orbitflare.com')
.build();
const stream = client.subscribeYaml('jetstream.yml');
for await (const update of stream) {
if (update.transaction) {
console.log(`slot=${update.transaction.slot}`);
}
}Or build the request with the typed builder:
import {
JetstreamClientBuilder,
SubscribeRequestBuilder,
TransactionFilter,
} from '@orbitflare/sdk/jetstream';
const request = new SubscribeRequestBuilder()
.transactions(
'pumpfun',
new TransactionFilter()
.accountInclude(['6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'])
.accountRequired(['So11111111111111111111111111111111111111112']),
)
.build();
const stream = client.subscribe(request);v2 (@orbitflare/sdk/jetstream/v2) runs on the same endpoint and auth as v1 and is fully additive. Filters are managed at runtime over a bidirectional stream (no reconnect to change them), every response carries a monotonic sequence for gap detection, slot lifecycle events are a separate stream, and transactions can opt into enrichment (fee payer, program ids, compute-unit price, loaded address-table addresses, and more).
import { JetstreamClientBuilder, TransactionFilter } from '@orbitflare/sdk/jetstream/v2';
const client = new JetstreamClientBuilder()
.url('http://slc.jetstream.orbitflare.com')
.fallbackUrl('http://ams.jetstream.orbitflare.com')
.build();
console.log(`version=${await client.getVersion()}`);
const filter = new TransactionFilter()
.accountInclude(['6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'])
.includeEnrichment(true)
.withId('pumpfun');
const stream = client.subscribeTransactions([filter]);
for await (const resp of stream) {
if (resp.transaction) {
const tx = resp.transaction.transaction;
if (tx) {
console.log(`seq=${resp.sequence} slot=${tx.slot} cuPrice=${tx.computeUnitPrice}`);
}
} else if (resp.filterValidation) {
console.log(`filter ${resp.filterValidation.filterId} accepted=${resp.filterValidation.accepted}`);
}
}Add or remove filters on a live stream without reconnecting:
const handle = stream.handle();
handle.addFilters([
new TransactionFilter().accountInclude(['675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8']).withId('raydium'),
]);
handle.removeFilters(['pumpfun']);Slot lifecycle events are a separate server stream:
const slots = client.subscribeSlots();
for await (const event of slots) {
console.log(`slot=${event.slot} status=${event.status}`);
}import { WsClientBuilder } from '@orbitflare/sdk/ws';
const client = await new WsClientBuilder()
.url('ws://ny.rpc.orbitflare.com')
.build();
const sub = await client.slotSubscribe();
while (true) {
const slot = await sub.next();
if (slot === undefined) break;
console.log(slot);
}Subscription types: accountSubscribe, logsSubscribe, slotSubscribe, signatureSubscribe. All auto-resubscribe on reconnect.
All clients support multiple endpoints with automatic failover and health tracking.
const client = new RpcClientBuilder()
.urls([
'http://ny.rpc.orbitflare.com',
'http://fra.rpc.orbitflare.com',
'http://ams.rpc.orbitflare.com',
])
.build();Failing endpoints are quarantined with exponential cooldown (10s, 20s, 40s, max 60s) and automatically retried once the cooldown expires. Healthy endpoints are always preferred.
RPC calls retry on transient errors (5xx, 429, connection resets, Solana error codes -32005, -32007, -32014, -32015, -32016) with exponential backoff before failing over to the next endpoint. 429 responses with a Retry-After header are respected.
gRPC, JetStream, and WebSocket connections use active ping/pong to detect dead connections. Configurable via the builder:
const client = new GeyserClientBuilder()
.url('http://ny.rpc.orbitflare.com:10000')
.pingIntervalSecs(15) // send a ping every 15s (default: 10)
.maxMissedPongs(5) // kill connection after 5 missed pongs (default: 3)
.build();All three streaming clients reconnect automatically on disconnection. WebSocket also re-subscribes all active subscriptions after reconnecting.
Configure retry behavior:
import { RpcClientBuilder } from '@orbitflare/sdk';
const client = new RpcClientBuilder()
.url('http://ny.rpc.orbitflare.com')
.retry({
initialDelayMs: 200,
maxDelayMs: 15_000,
multiplier: 2.0,
maxAttempts: 5,
})
.build();| Variable | Used by | Purpose |
|---|---|---|
ORBITFLARE_LICENSE_KEY |
RPC, WebSocket | API key appended to endpoint URLs |
ORBITFLARE_RPC_URL |
RPC | Default endpoint if .url() is not called |
ORBITFLARE_WS_URL |
WebSocket | Default endpoint if .url() is not called |
ORBITFLARE_GRPC_URL |
gRPC | Default endpoint if .url() is not called |
ORBITFLARE_JETSTREAM_URL |
JetStream | Default endpoint if .url() is not called |
Eight runnable examples live in examples/, covering every transport in basic and full variants.
git clone https://github.com/orbitflare/orbitflare-sdk-ts.git
cd orbitflare-sdk-ts
npm install
npm run proto
npm run build
export ORBITFLARE_LICENSE_KEY=ORBIT-...
npm run example:rpc-basic
npm run example:rpc-full
npm run example:ws-basic
npm run example:ws-full
npm run example:grpc-basic
npm run example:grpc-full
npm run example:grpc-filters
npm run example:jetstream-basic
npm run example:jetstream-full
npm run example:jetstream-filters
npm run example:jetstream-v2-basic
npm run example:jetstream-v2-full