Documentation Index Fetch the complete documentation index at: https://mintlify.com/hypertekorg/hyperstack/llms.txt
Use this file to discover all available pages before exploring further.
A stack is the client-side interface to your deployed Hyperstack stream. It provides type-safe access to real-time data, transactions, and utilities. This page explains the stack concept and how to use it.
What is a Stack?
A stack is a TypeScript/Python/Rust SDK that:
Connects to your deployed stream via WebSocket
Subscribes to entity views
Receives real-time updates as mutations
Merges deltas into local state
Provides type-safe APIs for your app
Stack vs Stream
Concept Location Purpose Stream Server-side Processes blockchain events into entities Stack Client-side Provides access to processed entities
Stack Definition
TypeScript
Define a stack using defineStack:
import { defineStack , createListView , createStateView } from 'hyperstack-react' ;
const TokenStack = defineStack ({
name: 'my-tokens' ,
views: {
tokens: {
list: createListView < Token >( 'Token/list' ),
state: createStateView < Token >( 'Token/state' ),
},
users: {
list: createListView < UserProfile >( 'UserProfile/list' ),
},
},
transactions: {
buy: {
build : ( params : { mint : string ; amount : number }) => ({
instruction: 'buy' ,
accounts: { mint: params . mint },
data: { amount: params . amount },
}),
refresh: [{ view: 'tokens/state' , key : ( p ) => p . mint }],
},
},
helpers: {
formatPrice : ( lamports : number ) => ` ${ ( lamports / 1e9 ). toFixed ( 6 ) } SOL` ,
},
});
export default TokenStack ;
Rust
Use the Rust SDK directly:
use hyperstack_sdk :: HyperStack ;
let hs = HyperStack :: new ( "wss://api.hyperstack.xyz/ws" )
. await ? ;
let mut stream = hs . watch :: < Token >()
. filter ( | token | token . total_volume > 1_000_000 )
. await ? ;
while let Some ( update ) = stream . next () . await {
println! ( "Token updated: {:?}" , update );
}
Python
from hyperstack import HyperStack
hs = HyperStack( "wss://api.hyperstack.xyz/ws" )
for update in hs.watch( "Token" ):
if update.total_volume > 1_000_000 :
print ( f "High volume token: { update.mint } " )
Stack Components
Views
Views provide access to entity data:
views : {
tokens : {
list : createListView < Token >( 'Token/list' ),
state : createStateView < Token >( 'Token/state' ),
},
}
List Views
Returns an array of entities:
const { data : tokens } = stack . views . tokens . list . use ();
// tokens: Token[] | undefined
With Filters:
const { data } = stack . views . tokens . list . use ({
limit: 50 ,
where: { total_volume: { gte: 1000 } },
});
State Views
Returns a single entity by key:
const { data : token } = stack . views . tokens . state . use ({
key: mintAddress
});
// token: Token | undefined
Transactions
Transaction builders with automatic refresh:
transactions : {
buy : {
build : ( params : { mint : string ; amount : number }) => ({
instruction: 'buy' ,
accounts: { mint: params . mint },
data: { amount: params . amount },
}),
refresh : [
{ view: 'tokens/state' , key : ( p ) => p . mint },
{ view: 'users/state' , key : ( p ) => wallet . publicKey . toString () },
],
},
}
Usage:
const { submit , status } = stack . tx . useMutation ();
const handleBuy = async () => {
const ix = stack . transactions . buy . build ({
mint: tokenMint ,
amount: 1000
});
const signature = await submit ( ix );
// Views automatically refresh after transaction
};
Helpers
Utility functions bundled with the stack:
helpers : {
formatPrice : ( lamports : number ) => ` ${ ( lamports / 1e9 ). toFixed ( 6 ) } SOL` ,
calculateMarketCap : ( token : Token ) => token . supply * token . price ,
}
Usage:
const price = stack . helpers . formatPrice ( token . sol_reserves );
// "1.234567 SOL"
View Modes
List View
Returns all entities as an array:
const listView = createListView < Token >( 'Token/list' );
Access Pattern:
const { data } = stack . views . tokens . list . use ();
// data: Token[]
Query Parameters:
interface ListParams {
key ?: string ; // Partition key filter
where ?: WhereClause ; // Field filters
limit ?: number ; // Max results
}
Example:
const { data } = stack . views . tokens . list . use ({
limit: 10 ,
where: {
total_volume: { gte: 1_000_000 },
created_at: { gt: Date . now () - 86400000 },
},
});
State View
Returns a single entity by primary key:
const stateView = createStateView < Token >( 'Token/state' );
Access Pattern:
const { data } = stack . views . tokens . state . use ({ key: mintAddress });
// data: Token | undefined
Required Parameter:
interface StateParams {
key : string ; // Primary key value
}
Apply transformations to view data:
const tokenList = createListView < Token >( 'Token/list' , {
transform : ( raw ) => ({
... raw ,
priceFormatted: ( raw . sol_reserves / raw . token_reserves ). toFixed ( 6 ),
volumeFormatted: ( raw . total_volume / 1e9 ). toFixed ( 2 ) + ' SOL' ,
}),
});
Complex Transformations:
const enrichedTokens = createListView < EnrichedToken >( 'Token/list' , {
transform : ( raw ) => ({
// Flatten nested structure
mint: raw . id . mint ,
name: raw . metadata . name ?? 'Unknown' ,
symbol: raw . metadata . symbol ?? '???' ,
price: raw . reserves . price ?? 0 ,
volume: raw . trading . total_volume ,
// Compute derived values
marketCap: raw . reserves . price ?
raw . reserves . price * raw . total_supply : 0 ,
// Format dates
createdAt: new Date ( raw . created_at * 1000 ),
}),
});
Real-Time Updates
How Updates Work
Initial Subscription:
const { data } = stack . views . tokens . list . use ();
Client subscribes to Token/list view
Server sends snapshot of current state
Hook returns initial data
Mutation Arrives:
{
"type" : "mutation" ,
"export" : "Token" ,
"key" : "mint_address" ,
"patch" : { "sol_reserves" : 1000 },
"append" : [ "trades" ]
}
SDK Merges Delta:
Finds entity with matching key
Applies patch (deep merge)
Appends new items to arrays
Triggers re-render
Component Re-renders:
// Component automatically re-renders with new data
console . log ( data . sol_reserves ); // 1000 (updated)
Delta Updates
Hyperstack sends only changed fields:
Full State:
{
"mint" : "TokenMint..." ,
"sol_reserves" : 500 ,
"token_reserves" : 1000000 ,
"total_volume" : 50000 ,
"trade_count" : 100
}
Mutation (only changed field):
{
"patch" : { "sol_reserves" : 1000 }
}
Merged Result:
{
"mint" : "TokenMint..." ,
"sol_reserves" : 1000 , // Updated
"token_reserves" : 1000000 , // Unchanged
"total_volume" : 50000 , // Unchanged
"trade_count" : 100 // Unchanged
}
Append-Only Updates
Array fields with Append strategy send only new items:
Initial State:
{
"trades" : [
{ "user" : "User1" , "amount" : 100 },
{ "user" : "User2" , "amount" : 200 },
]
}
Mutation (only new trade):
{
"patch" : {},
"append" : [ "trades" ],
"trades" : [
{ "user" : "User3" , "amount" : 300 } // Only the new trade
]
}
Merged Result:
{
"trades" : [
{ "user" : "User1" , "amount" : 100 },
{ "user" : "User2" , "amount" : 200 },
{ "user" : "User3" , "amount" : 300 }, // Appended
]
}
Connection Management
Connection States
type ConnectionState =
| 'disconnected'
| 'connecting'
| 'connected'
| 'error'
| 'reconnecting' ;
Monitoring Connection
const { connectionState , isConnected } = useHyperstack ( TokenStack );
if ( connectionState === 'connected' ) {
// Connected and receiving updates
}
if ( connectionState === 'reconnecting' ) {
// Temporarily disconnected, attempting to reconnect
}
Auto-Reconnect
The SDK automatically reconnects on disconnection:
Disconnect Detected : Connection lost
Reconnection Attempt : Exponential backoff
Resubscribe : Re-establish view subscriptions
Sync State : Fetch latest snapshots
Type Safety
Stacks provide end-to-end type safety:
Generated Types
// Generated from Rust entity definition
interface Token {
mint : string ; // from Rust String
sol_reserves : number ; // from Rust u64
total_volume : bigint ; // from Rust u128
trades : TradeEvent []; // from Rust Vec<TradeEvent>
}
Type Inference
const { data } = stack . views . tokens . list . use ();
// TypeScript knows: data is Token[] | undefined
if ( data ) {
data . forEach ( token => {
console . log ( token . mint ); // ✓ string
console . log ( token . sol_reserves ); // ✓ number
console . log ( token . invalid ); // ✗ TypeScript error
});
}
Transaction Type Safety
stack . transactions . buy . build ({
mint: "TokenMint..." ,
amount: 1000 ,
// invalid: true, // ✗ TypeScript error
});
Advanced Usage
Conditional Subscriptions
function TokenDetail ({ mint } : { mint : string | null }) {
const stack = useHyperstack ( TokenStack );
// Only subscribe when mint is available
const { data } = stack . views . tokens . state . use (
mint ? { key: mint } : undefined
);
if ( ! mint ) return < p > Select a token </ p > ;
if ( ! data ) return < p > Loading ...</ p > ;
return < TokenCard token ={ data } />;
}
Multiple Views
function Dashboard () {
const stack = useHyperstack ( TokenStack );
const { data : tokens } = stack . views . tokens . list . use ();
const { data : users } = stack . views . users . list . use ();
const { data : stats } = stack . views . stats . state . use ({ key: 'global' });
if ( ! tokens || ! users || ! stats ) return < Loading />;
return < DashboardView tokens ={ tokens } users ={ users } stats ={ stats } />;
}
Manual Refresh
const { data , refresh , isLoading } = stack . views . tokens . list . use ();
const handleRefresh = () => {
refresh (); // Force re-fetch from server
};
Optimistic Updates
const { submit } = stack . tx . useMutation ();
const handleBuy = async () => {
// Optimistically update local state
updateLocalState ( token => ({
... token ,
total_volume: token . total_volume + amount ,
}));
try {
await submit ( instruction );
// Server update will overwrite optimistic update
} catch ( error ) {
// Revert optimistic update
revertLocalState ();
}
};
Stack Patterns
Derived Views
Create computed views from base views:
function useTopTokens ( limit : number = 10 ) {
const { data : allTokens } = stack . views . tokens . list . use ();
const topTokens = useMemo (() => {
if ( ! allTokens ) return undefined ;
return allTokens
. sort (( a , b ) => b . total_volume - a . total_volume )
. slice ( 0 , limit );
}, [ allTokens , limit ]);
return topTokens ;
}
Filtered Views
function useMyTokens ( userAddress : string ) {
const { data : allTokens } = stack . views . tokens . list . use ();
const myTokens = useMemo (() => {
if ( ! allTokens ) return undefined ;
return allTokens . filter ( token => token . creator === userAddress );
}, [ allTokens , userAddress ]);
return myTokens ;
}
Aggregated Views
function useTokenStats () {
const { data : tokens } = stack . views . tokens . list . use ();
const stats = useMemo (() => {
if ( ! tokens ) return undefined ;
return {
total: tokens . length ,
totalVolume: tokens . reduce (( sum , t ) => sum + t . total_volume , 0 ),
avgVolume: tokens . reduce (( sum , t ) => sum + t . total_volume , 0 ) / tokens . length ,
highestVolume: Math . max ( ... tokens . map ( t => t . total_volume )),
};
}, [ tokens ]);
return stats ;
}
View Granularity
Use state views for individual entities to avoid re-renders:
// ✓ Good: Only re-renders when this specific token changes
function TokenCard ({ mint } : { mint : string }) {
const { data } = stack . views . tokens . state . use ({ key: mint });
return < Card >{data?. name } </ Card > ;
}
// ✗ Avoid: Re-renders when ANY token changes
function TokenCard ({ mint } : { mint : string }) {
const { data : tokens } = stack . views . tokens . list . use ();
const token = tokens ?. find ( t => t . mint === mint );
return < Card >{token?. name } </ Card > ;
}
Memoization
Memoize expensive computations:
const { data : tokens } = stack . views . tokens . list . use ();
const sortedTokens = useMemo (() => {
if ( ! tokens ) return [];
return [ ... tokens ]. sort (( a , b ) => b . total_volume - a . total_volume );
}, [ tokens ]);
Lazy Loading
Fetch data only when needed:
function TokenList () {
const [ selectedMint , setSelectedMint ] = useState < string | null >( null );
const { data : tokens } = stack . views . tokens . list . use ();
// Only fetch details for selected token
const { data : details } = stack . views . tokens . state . use (
selectedMint ? { key: selectedMint } : undefined
);
return (
< div >
< List tokens = { tokens } onSelect = { setSelectedMint } />
{ details && < Details token = { details } /> }
</ div >
);
}
Next Steps
React SDK Build React apps with Hyperstack
TypeScript SDK Framework-agnostic TypeScript SDK
Rust SDK Native Rust client SDK
Stack API Reference Complete Stack API docs