npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@triton-one/triton-sdk

v0.0.1

Published

Solana web3.js compatible SDK client for Triton One services

Readme

yellowstone-account-sync TypeScript SDK

This SDK provides a web3.js-compatible Connection focused on local account reads from a realtime state buffer fed by Yellowstone account-sync subscriptions.

Current method coverage is intentionally narrow:

  • getAccountInfo is implemented and resolved from local buffered state.
  • getMultipleAccountsInfo is implemented as repeated local buffered account reads.
  • getParsedAccountInfo and getMultipleParsedAccounts are implemented with local parsing and client-side context fetches.
  • Account data conversion helpers are exported for callers that need raw encoding conversion.
  • Runtime subscription management is implemented (addAccounts, removeAccounts, setAccounts).

Purpose and Scope

The client is designed for applications that want to reduce polling RPC reads by maintaining local account state from a push stream.

Design goals:

  • Minimize integration changes for existing @solana/web3.js users.
  • Keep browser and Node transport behavior explicit and safe.
  • Keep transport internals separate from buffer/business logic.
  • Make runtime behavior deterministic and auditable.

Non-goals (current version):

  • Full web3.js method parity.
  • Historical state queries.
  • Multi-endpoint failover orchestration.

Public API

Constructor

The constructor keeps web3.js style:

new Connection(endpoint, commitmentOrConfig?)
  • endpoint: base endpoint used for defaults.
  • commitmentOrConfig: either a commitment string or a config object.

Methods

  • getAccountInfo(publicKey, commitmentOrConfig?) -> Promise<AccountInfo<Buffer> | null>
  • getParsedAccountInfo(publicKey, commitmentOrConfig?) -> Promise<RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>>
  • getMultipleAccountsInfo(publicKeys, commitmentOrConfig?) -> Promise<Array<AccountInfo<Buffer> | null>>
  • getMultipleAccountsInfoAndContext(publicKeys, commitmentOrConfig?) -> Promise<RpcResponseAndContext<Array<AccountInfo<Buffer> | null>>>
  • getMultipleParsedAccounts(publicKeys, rawConfig?) -> Promise<RpcResponseAndContext<Array<AccountInfo<Buffer | ParsedAccountData> | null>>>
  • addAccounts(accountIds) -> Promise<void>
  • removeAccounts(accountIds) -> Promise<void>
  • setAccounts(accountIds) -> Promise<void>
  • close() -> Promise<void>
  • getLastTransportError() -> Error | null

Compatibility Notes

  • Input and output shape of getAccountInfo matches web3.js expectations (AccountInfo<Buffer> | null).
  • Input and output shape of getMultipleAccountsInfo matches web3.js expectations (Array<AccountInfo<Buffer> | null>).
  • The optional commitmentOrConfig argument on getAccountInfo supports commitment, dataSlice, and minContextSlot; reads are from local buffer.
  • getMultipleAccountsInfo supports the same commitment, dataSlice, and minContextSlot options.
  • Raw account responses include top-level space at runtime, matching current web3.js RPC behavior, though the public web3.js AccountInfo type does not declare it. space is the full account data size in bytes. dataSlice slices only data; space remains the full unsliced size.
  • getParsedAccountInfo and getMultipleParsedAccounts return web3.js-style parsed account info and fall back to raw base64 data when parsing context is unavailable.
  • getMultipleAccountsInfo returns entries in input order, including duplicate keys.
  • minContextSlot is evaluated against the buffered account update slot in this SDK. Direct web3.js RPC treats minContextSlot as a node read-context requirement and can throw MIN_CONTEXT_SLOT_NOT_REACHED; this SDK waits on the local buffer and returns null if no matching update arrives before missTimeoutMs.

Account Encoding

Account data conversion is backed by a small Rust WASM library under account-encoding-wasm. The Rust side is deterministic and does not open HTTP, gRPC, or RPC connections.

Supported encodings:

  • "binary": legacy Solana account data form, encoded as base58.
  • "base58": base58 account data.
  • "base64": base64 account data.
  • "base64+zstd": zstd-compressed base64 account data. This build enables it in WASM.
  • "jsonParsed": Solana program-aware parsed account data where supported.

jsonParsed sometimes needs extra data. SPL token account parsing needs the mint account to compute token amounts. The WASM parser reports the missing mint, then the TypeScript connection calls this same client's existing getAccountInfo method for that mint. The fetched mint account is cached and in-flight fetches are shared so concurrent parses do not start duplicate reads.

Default parser context cache settings:

  • maxEntries: 256
  • ttlMs: 300000

Known limits:

  • WASM does not do network I/O.
  • Unsupported program parsers fall back to base64 account data, matching RPC-style behavior.
  • If fallbackOnParseFailure is set to false, parser and context errors are thrown as typed errors.
  • Token-2022 parsing depends on the Solana account decoder version compiled into the WASM crate.

Discovery notes for maintainers:

  • Account updates are decoded in src/codec/geyser_codec.ts.
  • Latest account state is buffered in src/core/account_sync_core.ts and src/core/account_buffer.ts.
  • Web3 account conversion is in src/connection/utils.ts.
  • Node and browser read APIs are wired in src/connection/node_connection.ts and src/connection/browser_connection.ts.
  • WASM build output is generated into src/wasm/account_encoding and copied into dist/wasm/account_encoding during npm run build.
  • Building from source requires the Rust wasm32-unknown-unknown target and the wasm-bindgen CLI.

Configuration

The SDK extends web3.js config with accountSync options:

{
  accountSync?: {
    transport?: "ws" | "grpc" // Node
    // browser build only accepts "ws"
    subscriptionEndpoint?: string
    commitment?: "processed" | "confirmed" | "finalized"
    initialAccounts?: Array<string | PublicKey>
    autoSubscribeOnMiss?: boolean
    missTimeoutMs?: number
  }
}

Example:

const connection = new Connection("https://example.com/<TOKEN>", {
  accountSync: {
    transport: "grpc",
    commitment: "finalized",
    initialAccounts: [publicKey],
  },
});

getAccountInfo also accepts the web3.js commitment argument:

await connection.getAccountInfo(publicKey, "finalized");
await connection.getAccountInfo(publicKey, { commitment: "processed" });
await connection.getAccountInfo(publicKey, {
  commitment: "confirmed",
  dataSlice: { offset: 8, length: 32 },
  minContextSlot: 123456,
});

getMultipleAccountsInfo accepts the same account read options:

const accounts = await connection.getMultipleAccountsInfo(
  [publicKeyA, publicKeyB],
  {
    commitment: "confirmed",
    dataSlice: { offset: 8, length: 32 },
    minContextSlot: 123456,
  },
);

getMultipleAccountsInfoAndContext returns the same values with one context:

const response = await connection.getMultipleAccountsInfoAndContext(
  [publicKeyA, publicKeyB],
  { commitment: "confirmed" },
);

console.log(response.context.slot, response.value);

Parsed account examples:

const parsed = await connection.getParsedAccountInfo(publicKey, {
  commitment: "confirmed",
});

console.log(parsed.value?.data);
const parsedMany = await connection.getMultipleParsedAccounts(
  [publicKeyA, publicKeyB],
  {
    commitment: "confirmed",
    minContextSlot: 123456,
  },
);

console.log(parsedMany.context.slot, parsedMany.value);

Raw conversion helper example:

import { convertAccountData } from "@triton-one/triton-sdk";

const asBase58 = await convertAccountData(base64Data, "base64", "base58");

getParsedAccountInfo and getMultipleParsedAccounts accept the same account read options:

await connection.getParsedAccountInfo(publicKey, {
  commitment: "confirmed",
});

For local-buffer multiple-account reads, the context slot is the minimum slot among non-null returned accounts. If all returned entries are null, the context slot is 0.

If this commitment differs from the connection's default account-sync commitment, the SDK opens a separate subscription stream for that commitment and keeps a separate buffer for it.

Defaults:

  • transport: "ws" (Node), "ws" only (browser).
  • subscriptionEndpoint:
    • WS transport: uses wsEndpoint from config, otherwise derives from endpoint (http -> ws, https -> wss), then normalizes path to /[<token>/]YellowstoneAccountSyncService/ws.
    • gRPC transport: defaults to endpoint; endpoint path is used as token prefix and subscribe method is called at /<token>/YellowstoneAccountSyncGrpcService/Subscribe (or /YellowstoneAccountSyncGrpcService/Subscribe when endpoint has no path). If endpoint scheme is omitted, SDK defaults to https:// for non-local hosts and http:// for localhost-style hosts.
  • initialAccounts: [].
  • commitment: "confirmed".
  • autoSubscribeOnMiss: true.
  • missTimeoutMs: 5000.

Live Release Tests

The live SDK integration test uses the real SDK against a configured server. It is skipped unless both TEST_ENDPOINT and TEST_TOKEN are set.

TEST_ENDPOINT=https://example.com \
TEST_TOKEN=token-value \
npm test -- test/sdk_live_integration.test.ts

The test runs the same workflow over gRPC and WebSocket transports. It loads accounts from ../../k6/accounts.txt, subscribes to sets of 100, 100, and 1000 accounts, and performs seeded random reads through the SDK methods. TEST_TOKEN is appended to TEST_ENDPOINT for both SDK JSON-RPC hydration and stream subscription endpoints.

Optional settings:

  • TEST_RANDOM_SEED: seed used for repeatable random account reads.
  • TEST_RANDOM_READS: random reads per account set.
  • TEST_MISS_TIMEOUT_MS: SDK read wait timeout for live account reads.
  • TEST_UNREACHABLE_MISS_TIMEOUT_MS: short timeout for the unreachable minContextSlot check.
  • TEST_CLOSE_TIMEOUT_MS: timeout for closing each SDK connection.
  • TEST_LIVE_TIMEOUT_MS: Vitest timeout for each transport workflow.

Runtime Architecture

The implementation is split into independent components:

  1. Connection facade
  • Node facade and browser facade preserve constructor/method ergonomics.
  • Facades inject the selected transport into the shared core.
  1. Core orchestration
  • AccountSyncCore manages startup, control operation serialization, and lifecycle.
  • SubscriptionRegistry stores desired tracked-account set.
  • AccountBuffer stores latest account state by account id.
  1. Transport adapters
  • WsAccountSubscriptionTransport for websocket streams.
  • GrpcAccountSubscriptionTransport for grpc-js bidi streams (Node only).
  1. Codec layer
  • Encodes subscribe requests and decodes account updates.
  • Uses @triton-one/yellowstone-grpc generated types as type-only references.

Data and Consistency Semantics

Buffered state uses one record per account per commitment with:

  • accountId
  • lamports
  • owner
  • executable
  • rentEpoch
  • data
  • slot
  • writeVersion
  • updatedAtMs

Update ordering rules:

  • Newer slot wins.
  • If slot is equal, higher or equal writeVersion wins.
  • Older updates are ignored.

Subscription Semantics

  • initialAccounts are pushed when transport starts.
  • Subscription commitment is pushed with every subscribe request (defaults to confirmed unless configured).
  • addAccounts updates the desired set additively, then transports send the full desired set.
  • setAccounts and removeAccounts can shrink the tracked set.
  • getAccountInfo(publicKey, commitmentOrConfig) uses commitmentOrConfig.commitment when provided.
  • getMultipleAccountsInfo(publicKeys, commitmentOrConfig) applies the same rules to each requested account.
  • A requested commitment different from the connection default uses a separate stream and buffer.
  • dataSlice applies to the returned data buffer only.
  • minContextSlot is the minimum buffered account update slot. If the local buffer does not receive an update at or above that slot before missTimeoutMs, the returned account entry is null.

Important behavior:

  • The server supports replace semantics for session account filters.
  • Transport adapters send the full desired account set on each change over the same live stream.
  • Account removals are applied in-place on the existing stream (no reconnect required).
  • Upstream receives the updated full tracked-account set from the server and updates subscriptions in realtime.

Cache Miss Behavior

getAccountInfo and each entry in getMultipleAccountsInfo follow the same behavior:

  1. If account exists in local buffer, return immediately.
  2. If missing and autoSubscribeOnMiss = false, return null.
  3. If missing and autoSubscribeOnMiss = true, add account to tracked set and wait up to missTimeoutMs for first update.
  4. If timeout expires before first update, return null.
  5. If minContextSlot is set and only older buffered updates are available, wait up to missTimeoutMs for a newer update; if none arrives, return null.

Error Model

Synchronous/constructor-path errors:

  • Invalid transport selection in browser (grpc) throws.
  • Invalid account input (bad public key) throws during normalization.

Async transport/runtime errors:

  • Stream disconnects and transport-level failures are captured.
  • Latest observed error is available via getLastTransportError().
  • Methods that run after close() reject with account-sync connection is closed.

Lifecycle

  • Call close() to stop subscriptions and release transport resources.
  • close() is idempotent.

Packaging and Environment Isolation

The package uses conditional exports:

  • Browser entry: exposes WS-capable connection only.
  • Node entry: exposes WS and gRPC transport options.

Safety rules:

  • Browser bundle does not expose gRPC transport.
  • gRPC adapter has a runtime guard that throws when loaded in browser context.
  • @triton-one/yellowstone-grpc is a dev-only dependency and used for type-only imports in SDK code.

Examples

Runnable examples are available at:

  • examples/clients/typescript/src/get_account_info_ws.ts
  • examples/clients/typescript/src/get_account_info_grpc.ts

Example package:

  • examples/clients/typescript/package.json