The BAGS Restream SDK provides a powerful, full-fledged, and resilient WebSocket client for connecting to the BAGS real-time data stream. It is designed to give developers a simple yet highly configurable way to subscribe to a wide range of on-chain Solana DeFi events, including token swaps, price updates, new token launches, and maker actions.
This guide provides a general overview of the SDK’s core concepts, features, and common usage patterns.
Prerequisites
Before starting, make sure you have:
Key Features
The ReStream client is built to handle the complexities of real-time data streaming so you can focus on your application’s logic.
- Automatic Reconnection: The client automatically handles dropped connections with a configurable exponential backoff strategy, ensuring your application remains connected and resilient.
- Simple Subscription Management: An intuitive API allows you to subscribe and unsubscribe from data channels, with built-in support for wildcard subscriptions.
- Built-in Protobuf Decoding: Raw binary messages are automatically decoded into structured, type-safe TypeScript objects, removing the need for manual parsing.
- Type-Safe Handlers: Leverage TypeScript generics to ensure your event handlers receive data with the correct types, improving code quality and reducing runtime errors.
- Resilient and Configurable: The client is highly configurable, allowing you to adjust connection timeouts, ping intervals, subscription limits, and reconnection behavior.
Getting Started: A Basic Subscription Script
Here is a complete script that demonstrates the fundamental workflow: connecting to the service, subscribing to BAGS launches, handling incoming data, and disconnecting gracefully.
import { RestreamClient, RestreamLaunchpadLaunchSubscriptionHandler, LaunchpadLaunchEvent } from "@bagsfm/bags-sdk";
// 1. Create a new Restream client instance
const client = new RestreamClient();
async function main() {
try {
// 2. Connect to the Restream service
console.log("🔌 Connecting to Bags Restream...");
await client.connect();
console.log("✅ Connected!");
// 3. Define a handler for incoming launch events
const launchHandler: RestreamLaunchpadLaunchSubscriptionHandler = (
launchData: LaunchpadLaunchEvent,
meta: { channel: string; topic: string; subject: string },
) => {
console.log(
`New token launch: ${launchData.mint}`,
);
};
const unsubscribe = client.subscribeTopic("launchpad_launch", "BAGS", launchHandler);
console.log("👂 Listening for all BAGS launch events. Press Ctrl+C to exit.");
// 5. Handle graceful shutdown
process.on("SIGINT", async () => {
console.log("\n🛑 Unsubscribing and disconnecting...");
unsubscribe();
await client.disconnect();
process.exit(0);
});
} catch (error) {
console.error("🚨 An error occurred:", error);
process.exit(1);
}
}
// Run the main function
main();
Subscription Methods
The SDK offers several ways to subscribe to channels, from generic to highly specific convenience methods.
Generic Methods
These methods provide maximum flexibility for subscribing to any channel.
-
subscribeTopic<T>(topic, subject, handler)
: The most common method. You provide the topic and subject separately.
// Subscribe to token launches for a specific launchpad
client.subscribeTopic(
'launchpad_launch',
'BAGS',
(ev) => { console.log('Launch:', ev); }
);
-
subscribe<T>(channel, handler):
Use this when you have the full channel string.
// Subscribe to all BAGS token launches
client.subscribe('launchpad_launch:BAGS', (ev) => {
console.log('Launch:', ev);
});
Convenience Methods
For common use cases, the SDK provides helper methods that build the channel string for you.
subscribeBagsLaunches(handler)
: Subscribes to new token launches on Bags.
streram-launches-convenient.tsx
import { RestreamClient, RestreamLaunchpadLaunchSubscriptionHandler, LaunchpadLaunchEvent } from "@bagsfm/bags-sdk";
// 1. Create a new Restream client instance
const client = new RestreamClient();
async function main() {
try {
// 2. Connect to the Restream service
console.log("🔌 Connecting to Bags Restream...");
await client.connect();
console.log("✅ Connected!");
// 3. Define a handler for incoming launch events
const launchHandler: RestreamLaunchpadLaunchSubscriptionHandler = (
launchData: LaunchpadLaunchEvent,
meta: { channel: string; topic: string; subject: string },
) => {
console.log(
`New token launch: ${launchData.mint}`,
);
};
const unsubscribe = client.subscribeBagsLaunches(launchHandler);
console.log("👂 Listening for all BAGS launch events. Press Ctrl+C to exit.");
// 5. Handle graceful shutdown
process.on("SIGINT", async () => {
console.log("\n🛑 Unsubscribing and disconnecting...");
unsubscribe();
await client.disconnect();
process.exit(0);
});
} catch (error) {
console.error("🚨 An error occurred:", error);
process.exit(1);
}
}
// Run the main function
main();
Handling Client Lifecycle Events
To build a robust application, you should monitor the client’s connection state. The RestreamClient is an EventEmitter and provides several key events.
// Log when the connection is first established
client.on("open", () => console.log("Connection opened!"));
// Log errors
client.on("error", (err) => console.error("🔥 Client Error:", err));
// Log when the connection closes and a reconnect is scheduled
client.on("close", ({ code, reason }) =>
console.log(`🚪 Connection Closed: ${code} - ${reason}`),
);
// Monitor reconnection attempts
client.on("reconnecting", ({ attempt, delayMs }) =>
console.log(`⏳ Reconnecting... (Attempt ${attempt}, delay ${delayMs}ms)`),
);
// Confirm when the connection is restored
client.on("reconnected", ({ attempts }) =>
console.log(`🎉 Reconnected after ${attempts} attempts!`),
);
Advanced: Debugging Events
Some events are emitted by the ReStream client for observability or custom logic:
// Log when there is a handler error
client.on("handler_error", (error) => console.error("handler error", error));
// Log when there is a socket error
client.on("socket_error", (error) => console.error("socket error", error));
// Could be server notices, errors, etc.
client.on("control", (msg) => console.log("notice:", msg))
// Reconnection errors
client.on("reconnect_error", (error) => console.log("reconnect error:", error))
// For every other error...
client.on("client_error", (ev) => console.log("some client error:", ev))
ReStream client doesn’t log anything by design, so make sure to subscribe to error events for observability, you can then tie that with your own logger.
Advanced: Custom Decoders
If Bags introduces a new topic without a built-in decoder in the SDK, or if you need to override existing decoding logic, you can register your own decoder function. The function receives a raw Buffer and should return the parsed data.
client.registerDecoder("new_experimental_topic", (payload: Buffer) => {
// Your custom decoding logic here
const decodedData = JSON.parse(payload.toString());
return decodedData;
});