Documentation Index
Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
Use this file to discover all available pages before exploring further.
Установка
npm install @orbitflare/sdk @grpc/grpc-js yaml
@grpc/grpc-js и yaml - опциональные peer-зависимости. Устанавливайте их, только если используете gRPC-клиент (или YAML-конфиг).
Сборка клиента
Пример клиента со всеми опциями:
import { GeyserClientBuilder, type RetryPolicy } from '@orbitflare/sdk';
const client = new GeyserClientBuilder()
.url('http://ny.rpc.orbitflare.com:10000')
.fallbackUrl('http://fra.rpc.orbitflare.com:10000')
.retry({
initialDelayMs: 100,
maxDelayMs: 30_000,
multiplier: 2.0,
maxAttempts: 0,
})
.timeoutSecs(30)
.keepaliveSecs(60)
.pingIntervalSecs(10)
.maxMissedPongs(3)
.channelCapacity(4096)
.build();
Минимальная конфигурация:
const client = new GeyserClientBuilder()
.url('http://ny.rpc.orbitflare.com:10000')
.build();
Методы билдера
.url(url) - основной gRPC-эндпоинт. Резерв: переменная окружения ORBITFLARE_GRPC_URL.
.url('http://ny.rpc.orbitflare.com:10000')
.urls([...]) - основной и резервные за один вызов. Первый элемент - основной.
.urls(['http://ny.rpc.orbitflare.com:10000', 'http://fra.rpc.orbitflare.com:10000'])
.fallbackUrl(url) / .fallbackUrls([...]) - добавить резервные эндпоинты. При сбое подключения SDK перебирает их по очереди.
.fallbackUrl('http://fra.rpc.orbitflare.com:10000')
.retry(policy) - управление backoff при переподключении. Когда соединение падает, SDK ждёт initialDelayMs, затем удваивает задержку на каждой попытке (ограничение maxDelayMs). maxAttempts: 0 - бесконечные повторы. По умолчанию: 100 мс начальная, 30 с максимум, множитель 2×, бесконечно.
.retry({
initialDelayMs: 200,
maxDelayMs: 15_000,
multiplier: 2.0,
maxAttempts: 0,
})
.timeoutSecs(n) - таймаут gRPC на запрос. По умолчанию: 30.
.keepaliveSecs(n) - интервал TCP keepalive. ОС отправляет пробу с этим интервалом для обнаружения мёртвых соединений на уровне TCP. По умолчанию: 60.
.pingIntervalSecs(n) - как часто SDK отправляет на уровне proto сообщения Ping. Сервер должен ответить Pong. По умолчанию: 10.
.maxMissedPongs(n) - сколько подряд ping без ответа допускается, прежде чем SDK считает соединение мёртвым и переподключится. По умолчанию: 3. С дефолтами «мёртвое» соединение обнаруживается примерно за 30 секунд.
.channelCapacity(n) - ограниченный буфер между фоновой задачей и вашим кодом. Если обработка событий медленная, фоновая задача приостанавливается при заполнении вместо неограниченного роста памяти. По умолчанию: 4096.
Написание YAML-конфига
Создайте YAML с нужными фильтрами:
# grpc.yml
transactions:
pumpfun:
vote: false
failed: false
account_include:
- "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
jupiter:
vote: false
failed: false
account_include:
- "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
accounts:
usdc_mint:
account:
- "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
token_program:
owner:
- "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
slots:
all:
filter_by_commitment: true
commitment: confirmed
Справочник фильтров YAML
transactions - каждая запись - именованный фильтр. Транзакция попадает, если задействован любой адрес из account_include. account_exclude исключает совпадения. account_required - все перечисленные адреса должны присутствовать. vote и failed фильтруют тип транзакции.
accounts - следить за конкретными аккаунтами по адресу или за всеми аккаунтами программы через owner.
slots - подписка на обновления слотов. filter_by_commitment отправляет обновления только на вашем уровне commitment.
commitment - 'processed', 'confirmed' или 'finalized'. По умолчанию 'confirmed'.
В YAML поддерживается подстановка ${ENV_VAR}:
transactions:
target:
account_include:
- "${TARGET_PROGRAM}"
Подписка и чтение событий
Из YAML
const stream = client.subscribeYaml('grpc.yml');
Программно
Для динамических фильтров во время выполнения:
import { proto } from '@orbitflare/sdk';
const request: proto.geyser.SubscribeRequest = {
transactions: {
target: {
vote: false,
failed: false,
signature: undefined,
accountInclude: [someAddress],
accountExclude: [],
accountRequired: [],
},
},
accounts: {},
slots: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
commitment: 1,
ping: { id: 1 },
};
const stream = client.subscribe(request);
Чтение потока
И subscribeYaml, и subscribe возвращают GeyserStream. Это асинхронно итерируемый объект - используйте for await:
for await (const update of stream) {
if (update.transaction) {
// update.transaction.slot - the slot this transaction was in
// update.transaction.transaction - the transaction info (signature, accounts, instructions, meta)
} else if (update.account) {
// update.account.slot - the slot
// update.account.account - account info (pubkey, lamports, owner, data)
// update.account.isStartup - true during initial account snapshot
} else if (update.slot) {
// update.slot.slot - the slot number
// update.slot.status - processed, confirmed, finalized, etc.
} else if (update.blockMeta) {
// update.blockMeta.slot, update.blockMeta.blockhash, update.blockMeta.parentSlot
// update.blockMeta.executedTransactionCount
}
}
Либо вызывайте await stream.next() напрямую, чтобы получать события по одному. Возвращает undefined, когда поток закрыт. Если повторы исчерпаны, следующая итерация выбрасывает исключение.
Сообщения Pong потребляются внутри и в ваш поток не попадают.
Закрытие
Немедленно останавливает фоновую задачу.
Несколько потоков
Один клиент может держать много потоков одновременно. У каждого свой фоновый коннект:
const pumpfun = client.subscribeYaml('config/pumpfun.yml');
const raydium = client.subscribeYaml('config/raydium.yml');
const slots = client.subscribeYaml('config/slots.yml');
Они разделяют состояние здоровья эндпоинтов: если один поток карантинит падающий эндпоинт, остальные при следующем переподключении его пропустят. Сами соединения и жизненные циклы независимы.
Новые потоки можно поднимать в любой момент, в том числе динамически по данным из существующего потока.
Полный пример
Поток следит за транзакциями pump.fun, декодирует подпись и печатает краткое резюме.
import bs58 from 'bs58';
import { GeyserClientBuilder } from '@orbitflare/sdk';
async function main() {
const client = new GeyserClientBuilder()
.url('http://ny.rpc.orbitflare.com:10000')
.fallbackUrl('http://fra.rpc.orbitflare.com:10000')
.build();
const stream = client.subscribeYaml('grpc.yml');
let txCount = 0;
console.log('streaming...');
for await (const update of stream) {
if (update.transaction) {
txCount += 1;
const info = update.transaction.transaction;
if (info?.signature) {
const sig = bs58.encode(info.signature);
const fee = info.meta?.fee ?? 0n;
const ixCount = info.transaction?.message?.instructions.length ?? 0;
console.log(
`#${txCount} slot=${update.transaction.slot} sig=${sig.slice(0, 16)}... fee=${fee} instructions=${ixCount}`,
);
}
} else if (update.slot) {
console.log(`slot ${update.slot.slot} (${update.slot.status})`);
}
}
}
void main();
С этим grpc.yml:
transactions:
pumpfun:
vote: false
failed: false
account_include:
- "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
slots:
all:
filter_by_commitment: true
commitment: confirmed