# TypeScript Example

Complete JavaScript/TypeScript implementation for streaming Solana transactions from NextBlock's TX Stream API, optimized for trading bots and fast transaction detection.

The example is hosted at [github.com/nextblock-ag/nextblock-stream-examples](https://github.com/nextblock-ag/nextblock-stream-examples/tree/main/typescript-example)

## Prerequisites

```bash
bun add @grpc/grpc-js @grpc/proto-loader
bun add @solana/addresses @solana/codec-strings @solana/kit

# Generate the TX Stream proto client from the proto specification
# In the example repo, dependencies and the generated .ts files are already available
```

## Example

```typescript
import * as grpc from "@grpc/grpc-js";

import {
    NextStreamNotification,
    NextStreamServiceClient,
} from "./protos/stream";
import { NextStreamSubscription } from "./protos/stream";
import {
    createKeyPairFromBytes,
    getAddressFromPublicKey,
    getBase58Decoder,
    getBase58Encoder,
    getCompiledTransactionMessageDecoder,
    getSignatureFromTransaction,
    getTransactionDecoder,
    getUtf8Encoder,
    signBytes,
    type Address,
} from "@solana/kit";

/*
the auth message needs to be built clients-side.
it is a pipe-separated string made of:
1. domain that's being connected to (e.g. fra.stream.nextblock.io)
2. the publickey that sent the fee to strmuYvHKeA1qvHqooUpwUk2BFwaAmMbK9WXY9mh2GJ
3. a random nonce
4. the current unix timestamp

it is then signed by the supplied publickey.
*/

function buildAuthMessage(
    domain: string,
    authenticatedPublicKey: Address
): string {
    const nonce = Math.random().toString();
    const ts = Math.floor(Date.now());
    return `${domain}|${authenticatedPublicKey.toString()}|${nonce}|${ts}`;
}

async function main() {
    const domain = "fra.stream.nextblock.io:22221";
    const authenticationPrivateKey = await createKeyPairFromBytes(
        getBase58Encoder().encode("YOUR_PRIVATE_KEY")
    );
    const authenticationPublicKey = await getAddressFromPublicKey(
        authenticationPrivateKey.publicKey
    );

    const authenticationMessage = buildAuthMessage(
        domain,
        authenticationPublicKey
    );
    const authenticationSignature = await signBytes(
        authenticationPrivateKey.privateKey,
        getUtf8Encoder().encode(authenticationMessage)
    );

    const client = new NextStreamServiceClient(
        domain,
        grpc.credentials.createInsecure(),
        {
            "grpc.keepalive_time_ms": 5000,
            "grpc.keepalive_timeout_ms": 1000,
            "grpc.keepalive_permit_without_calls": 0,
        }
    );

    const req: NextStreamSubscription = {
        authenticationPublickey: authenticationPublicKey.toString(),
        authenticationMessage,
        authenticationSignature: getBase58Decoder().decode(
            authenticationSignature
        ),
        accounts: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"],
    };

    const stream = client.subscribeNextStream(req);

    stream.on("data", (msg: NextStreamNotification) => {
        try {
            const packet = msg.packet;
            if (!packet) {
                return;
            }

            const txBytes = packet.transaction;
            const slot = packet.slot;

            const tx = getTransactionDecoder().decode(txBytes);
            const message = getCompiledTransactionMessageDecoder().decode(
                tx.messageBytes
            );

            console.log(
                `got new sig ${getSignatureFromTransaction(
                    tx
                ).toString()} on slot ${slot}`
            );
        } catch (e) {
            console.error("error processing message:", e);
        }
    });

    stream.on("error", (err) => {
        console.error("error receiving from sub:", err);
        process.exit(1);
    });

    stream.on("end", () => {
        console.error("stream ended");
        process.exit(0);
    });
}

main();
```

## Usage Examples

```bash
# Log signature + slot for all filtered transactions
bun index.ts
```

## Available Endpoints

Choose the endpoint closest to your location:

* **Frankfurt**: `fra.stream.nextblock.io:22221`
* **Amsterdam**: `amsterdam.stream.nextblock.io:22221`
* **London**: `london.stream.nextblock.io:22221`
* **Singapore**: `singapore.stream.nextblock.io:22221`
* **Tokyo**: `tokyo.stream.nextblock.io:22221`
* **New York**: `ny.stream.nextblock.io:22221`
* **Salt Lake City**: `slc.stream.nextblock.io:22221`
* **Dublin**: `dublin.stream.nextblock.io:22221`
* **Vilnius**: `vilnius.stream.nextblock.io:22221`

## Best Practices for Trading Bots

1. **Match the endpoint requirements**: Follow the transport settings shown in the example for the current TX Stream service
2. **Filter efficiently**: Only subscribe to programs you need to reduce bandwidth
3. **Handle reconnections**: Implement automatic reconnection logic
4. **Process quickly**: Avoid blocking the stream receiver
5. **Monitor performance**: Track processing latency and throughput
6. **Implement graceful shutdown**: Handle interrupt signals properly
7. **Use multiple endpoints**: Implement redundancy for critical applications


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nextblock.io/api/tx-stream/typescript.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
