import Yellowstone, {
CommitmentLevel,
type SubscribeRequest,
type SubscribeUpdate,
} from "@triton-one/yellowstone-grpc";
const Client = typeof Yellowstone === "function" ? Yellowstone : Yellowstone.default;
export function makeRequest(
filters: Partial<SubscribeRequest> = {},
): SubscribeRequest {
return {
accounts: {}, slots: {}, transactions: {}, transactionsStatus: {},
blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
commitment: CommitmentLevel.CONFIRMED,
...filters,
};
}
export async function* subscribe(
filters: Partial<SubscribeRequest>,
): AsyncGenerator<SubscribeUpdate> {
const token = process.env.GRPC_API_TOKEN;
if (!token) throw new Error("Set GRPC_API_TOKEN before starting");
const endpoint = process.env.GRPC_ENDPOINT ?? "https://grpc.solanatracker.io";
// This helper exposes disconnects to the caller instead of auto-reconnecting.
const client = new Client(endpoint, token, undefined, { enabled: false });
const stream = await client.subscribe(makeRequest(filters));
try {
for await (const update of stream) {
if (update.ping) {
await new Promise<void>((resolve, reject) => {
stream.write(makeRequest({ ping: { id: 1 } }), (error?: Error | null) => {
if (error) reject(error);
else resolve();
});
});
continue;
}
if (!update.pong) yield update;
}
} finally {
stream.destroy();
}
}